首页 > 代码库 > c#调用dll接口传递utf-8字串方法

c#调用dll接口传递utf-8字串方法

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 =http://www.mamicode.com/= 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字串方法