打赏

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:\\kvd\xd0\xc2'

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

dir: d:\kvd新, code: 'd:\\kvd\xe6\x96\xb0'

用c#建Demo用Encoding反解析验知\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!运行效果如下:

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

posted on 2017-03-27 20:15  楚人无衣  阅读(4664)  评论(2编辑  收藏  举报