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 -;
} 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 + );
Marshal.Copy(utf8bytes, , ptr, utf8bytes.Length);
Marshal.WriteByte(ptr, utf8bytes.Length, );
return ptr;
} public object MarshalNativeToManaged(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero)
return null; List<byte> bytes = new List<byte>();
for (int offset = ; ; offset++)
{
byte b = Marshal.ReadByte(pNativeData, offset);
if (b == )
break;
else
bytes.Add(b);
}
return Encoding.UTF8.GetString(bytes.ToArray(), , 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字串方法的更多相关文章

  1. C#程序实现动态调用DLL的研究(转)

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

  2. C#程序实现动态调用DLL的研究[转]

    摘   要: 在< csdn 开发高手> 2004 年第 03 期中的<化功大法——将 DLL 嵌入 EXE >一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在 ...

  3. C#程序实现动态调用DLL的研究

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

  4. DLL接口自动化测试总结

    1. DLL接口测试方法介绍 在最近测试的项目中,系统给业务端提供DLL文件,业务端通过DLL文件中的C++接口实现系统功能,这就需要对DLL中的C++接口进行详细功能测试. 本文主要介绍项目测试中使 ...

  5. 转【C#调用DLL的几种方法,包括C#调用C\C++\C#DLL】

    C#中dll调用方法   一.      DLL与应用程序 动态链接库(也称为DLL,即为“Dynamic Link Library”的缩写)是Microsoft Windows最重要的组成要素之一, ...

  6. 【转】C#调用DLL

    C#中如何调用动态链接库DLL(转)     每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基 ...

  7. android调用webservice接口获取信息

    我的有一篇博客上讲了如何基于CXF搭建webservice,service层的接口会被部署到tomcat上,这一篇我就讲一下如何在安卓中调用这些接口传递参数. 1.在lib中放入ksoap2的jar包 ...

  8. python 调用RESTFul接口

    本周需要将爬虫爬下来的数据入库,因为之前已经写好PHP的接口的,可以直接通过python调用PHP接口来实现,所以把方法总结一下. //python编码问题,因为好久用,所以很容易出现 # -*- c ...

  9. thinkjs学习-this.assign传递数据和ajax调用后台接口

    在页面加载时,就需要显示在页面上的数据,可以在后台使用this.assign赋值,在前台通过ejs等模板获取:用户点击按钮,或者触发某些事件和后台进行交互时,就需要用到ajax调用后台接口.本文通过一 ...

随机推荐

  1. mysql Lock wait timeout exceeded; try restarting transaction解决

    前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处理: ...

  2. linux环境运行java项目并有外部引用jar

    eclipse目录结构: linux目录结构: lib目录结构: 其中除了IMT_ENCODING_DSP.jar其余的都是外部引用的jar IMT_ENCODING_DSP.jar是java项目打包 ...

  3. iOS响应链原理

    ios找到被点击的view的过程是从根view开始递归地调用hitTest方法,直到有一个子view的hitTest方法返回自身:如果所有一级子view的hitTest方法都返回nil,那么根view ...

  4. codes often WA

    枚举: 1.完美立方 #include<iostream> #include <cstdio> using namespace std; int main() { int N; ...

  5. mysql 忘记密码解决方案

    Mysql 忘记root密码的完美解决方法 转载  2016-12-23   作者:MR.QiGao    我要评论 通常在使用Mysql数据库时,如果长时间没有登陆,或者由于工作交接完成度不高,会导 ...

  6. 如何安装和配置RabbitMQ(转载)

    如何安装和配置RabbitMQ 今天开始一个小小的练习,学习一下安装和配置RabbitMQ,为什么要学它,因为WCF可以完全兼容和使用RabbitMQ了.我们新的大数据系统需要使用消息队列,所以就开始 ...

  7. vue中嵌套页面(iframe)

    vue中嵌套iframe,将要嵌套的文件放在static下面.(要将打包文件整体放在statici里,我的文件名是canvas) src可以使用相对路径,也可使用服务器根路径http:localhos ...

  8. vscode 不显示指定后缀名pyc文件

    不显示python生成的pyc文件 不显示java eclipse编辑器生成的.metadata生成的文件夹 py文件执行后会生成.pyc文件,会影响侧边栏的使用,可以通过如下设置隐藏.pyc等中间文 ...

  9. 16.2 profile 显示或者隐藏页面 修改密码

    我们auth在clent端有更加强大的功能 显示或者隐藏component 或者 我们可以阻止或者允许某个用户访问url

  10. 吴裕雄 python oracle子查询的用法(3)

    import cx_Oracle conn = cx_Oracle.connect("scott/admin@localhost:1521/orcl")cursor = conn. ...