標籤:images 調用dll c++ 簡體 lis cee c# read imp
1. 起源:
VCU10之視頻下載模組,採用純python實現,c++代碼調用pythonrun.h配置python運行環境啟動python模組,以使介面UI能夠使用其中功能。
棘手問題!用去一天時間反覆列印日誌,驗證所傳字串區別,以期望發現問題定位問題,直至下班前始有靈感。
驗證發現,非中文字元可以正常下載,中文字元下載解析失敗,當時即想到可能是字串不統一所致,就在python代碼中做字串轉換處理,均不奏效。
原介面封裝代碼如下:
[DllImport("VideoDownloader", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private extern static bool VDDownload(IntPtr instance,string savePath,string imageSavePath, string quality, string ext, string subtitleLang);
比如傳savePath為[d:\vcu新],dll調用python模組,則列印日誌為:
dir: d:\kvd新, code: ‘d:\\kvd\xd0\xc2‘
而直接運行python代碼,其輸出卻是:
dir: d:\kvd新, code: ‘d:\\kvd\xe6\x96\xb0‘
用c#建Demo驗知\xd0\xc2為[新]字的gb2312編碼,\xe6\x96\xb0為[新]字的utf-8編碼。
2、字串編碼
Win7 64位簡體中文版中c#的預設編碼:
做如此簡單驗證,發現其預設編碼為gb2312;而所用python代碼,為兼顧中文等多位元組字元,預設採用utf-8編碼。
問題大抵就在這裡了,dll介面字串,改為utf-8字串傳遞。但c#內建沒有utf-8封裝器,自訂實現它。
3、UTF8Marshaler
//介面資料為utf-8編碼所設定 public class UTF8Marshaler : ICustomMarshaler { public void CleanUpManagedData(object managedObj) { } public void CleanUpNativeData(IntPtr pNativeData) { Marshal.FreeHGlobal(pNativeData); } public int GetNativeDataSize() { return -1; } public IntPtr MarshalManagedToNative(object managedObj) { if (object.ReferenceEquals(managedObj, null)) return IntPtr.Zero; if (!(managedObj is string)) throw new InvalidOperationException(); byte[] utf8bytes = Encoding.UTF8.GetBytes(managedObj as string); IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1); Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length); Marshal.WriteByte(ptr, utf8bytes.Length, 0); return ptr; } public object MarshalNativeToManaged(IntPtr pNativeData) { if (pNativeData == IntPtr.Zero) return null; List<byte> bytes = new List<byte>(); for (int offset = 0; ; offset++) { byte b = Marshal.ReadByte(pNativeData, offset); if (b == 0) break; else bytes.Add(b); } return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count); } private static UTF8Marshaler instance = new UTF8Marshaler(); public static ICustomMarshaler GetInstance(string cookie) { return instance; } }
4、更新介面字串封送樣式
[DllImport("VideoDownloader", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private extern static bool VDDownload(IntPtr instance, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))] string savePath, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))] string imageSavePath, string quality, string ext, string subtitleLang);
驗證工作OK!運行效果如下:
至此,一個技術痛點解決,記錄於此。
c#調用dll介面傳遞utf-8字串方法