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


    1. 起

    VCU10之视频下载模块,采用纯python编码实现,c++代码调用pythonrun.h配置python运行环境启动python模块,编译为dll给c#调用,以使界面UI能够使用其中功能。

    不要问为什么不用IronPython,它不是正统Python,且下载模块亦要为Mac产品所用。

    棘手问题!用去一天时间反复打印日志,验证所传字串区别,以期望发现问题定位问题,直至下班前始有灵感。

    验证发现,非中文字符可以正常下载,中文字符下载解析失败,当时即想到可能是字串不统一所致,就在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模块,打印其编码信息:

    print 'dir: ' + dir + ', code: ' + repr(dir))

    则打印日志为:

    dir: d:kvd新, code: 'd:\kvdxd0xc2'

    而直接运行python代码,其输出却是:

    dir: d:kvd新, code: 'd:\kvdxe6x96xb0'

    用c#建Demo用Encoding反解析验知xd0xc2为[]字的gb2312编码,xe6x96xb0为[]字的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!运行效果如下:

    至此,一个技术难点解决,记录于此。

  • 相关阅读:
    WebGL编程指南案例解析之绘制一个点
    在pixi中使用你的自定义着色器
    一个关于运维人员做事的很好的case,拿出来和大家共勉
    2015小目标
    在工作中修行
    ROW模式的SQL无法正常同步的问题总结
    从周末教儿子学溜冰联想到带人
    group_concat函数导致的主从同步异常
    招聘运维工程师
    一个锁的奇怪问题分析总结
  • 原文地址:https://www.cnblogs.com/crwy/p/6628589.html
Copyright © 2020-2023  润新知