事情源于有个客户需使用我们C++的中间件动态库来跟设备连接通讯,但是传入以及传出的字符串指针格式都不正确(出现乱码或是被截断),估计是字符编码的问题导致。以下是解决问题的过程:

  我们C++中间件动态库的接口函数声明:

extern "C" bool __stdcall ExecuteTaskInFile(const char *szTaskID, const char *szInputFile, const char *szOutputFile, bool bSynch);

  传入的字符串指针要求是Ansi编码。

  我们给客户提供的Delphi例子是用Delphi7写的:

声明:

function ExecuteTaskInFile(szTaskID : Pchar; szInputFile:Pchar; szOutputFile:PChar; bSynch :boolean):boolean;stdcall;external 'XXXX.dll';

调用:

function ExecuteFileTask():boolean;

var

  strTaskID:string;

begin

    //略去若干注释

    strTaskID := '';

    Result := ExecuteTaskInFile(pchar(strTaskID), pchar('C:\Data\TestData\Input\Task.xml'), pchar('C:\Data\TestData\Output\TaskResult.xml'), true);

end;

  但是该程序拿到客户处编译运行后出现一些莫名错误,据客户反馈,他们也是使用Delphi,因此怀疑方向一度转到传入的数据文件内容是否有错误上,但从客户处取回数据文件后测试也无问题。不得已,只能上门拜访了下客户,幸好不是很远。到了现场才得知用户使用的Delphi是Delphi XE7,已经是Borland将Delphi抛弃很多年以后的事情了,距离我使用过的Delphi7也已经是12年后了。

  在客户现场查看动态库接口的日志,发现了如下的记录:

2018-10-15 13:28:14,318 [0x000012c0] INFO RUNNING 0 XXXX.XXXX Enter XXXX::ExecuteTaskInFile(TaskId:2)

  而我们传入的TaskId其实是'20160222111817081',只取到了第一个字符,那么很有可能是传入的指针指向的字符串是使用Unicode编码的,其第二个字节是0x00被当作字符串结束符而截断了。

  很多年没有关注Delphi,又回顾了下Delphi的历史,Delphi7还是Ansi编码的IDE,因此上面的代码调用C++动态库传入Ansi字符串没有问题, 而Delphi从2009开始完整正式支持Unicode,之后的XE7是2014年发布的。 Delphi在2009以后对应char*的类型为PWideChar,因此默认使用了Unicode编码,如果要用Ansi编码,必须是PAnsiChar。

  这样看来,问题就简单明了了,将Delphi代码改成如下后测试通过:

声明:

function ExecuteTaskInFile(szTaskID : PAnsichar; szInputFile:PAnsichar; szOutputFile:PAnsiChar; bSynch :boolean):boolean;stdcall;external 'XXXX.dll';

调用:

function ExecuteFileTask():boolean;

var

  strTaskID:string;

begin

    strTaskID := '';

    Result := ExecuteTaskInFile(pAnsichar(AnsiString(strTaskID)), pAnsichar('C:\Data\TestData\Input\Task.xml'), pAnsichar('C:\Data\TestData\Output\TaskResult.xml'), true);

end;

  值得注意的是,当使用字符串变量传递时,必须加以AnsiString转换,而常量字符串参数则可不用,后面再仔细研究了。

  总结:其实事情本不复杂,可以通过简单的沟通就了解到客户的使用场景以及动态库的调用日志然后做针对性的分析,但是我们常常会忽略一些细节从而做出一些片面的判断导致问题复杂化,遇到问题时按部就班,不放过一个细节,针对性的分析解决才是正确的做法。

  忌 一叶蔽目,管中窥豹。

  宜 审问慎思,明辨笃行。

Delphi XE7调用C++动态库出现乱码问题回顾的更多相关文章

  1. c#调用c++动态库的一些理解

    调用c++动态库一般我们这样写   [DllImport("UCamer.dll", CallingConvention = CallingConvention.Winapi)] ...

  2. C#调用C++动态库(dll)

    在实际软件开发过程中,由于公司使用了多种语言开发,在C#中可能需要实现某个功能,而该功能可能用其他语言已经实现了,那么我们可以调用其他语言写好的模块吗?还有就是,由于C#开发好的项目,我们可以利用re ...

  3. C#总结(四)调用C++动态库

    由于公司很多底层的SDK,都是C++开发,上层的应用软件却是C# Winform程序.在实际工作的过程中,就经常碰到了C# 程序调用C++ 动态库的问题.最近一直在和C++ 打交道,C# 怎么调用C+ ...

  4. Java调用dll动态库

    最近项目里使用java调用dll动态库,因此研究了一下这方面的东西. 使用的工具包如下 <dependency> <groupId>net.java.dev.jna</g ...

  5. 【C#】 使用Gsof.Native 动态调用 C动态库

    [C#] 使用Gsof.Native 动态调用 C动态库 一.背景 使用C# 开发客户端时候,我们经常会调用一些标准的动态库或是C的类库.虽然C# 提供的PInvoke的方式,但因为使用的场景的多变, ...

  6. python调用.net动态库

    # python调用.net动态库 ### pythonnet简介------------------------------ pythonnet是cpython的扩展- pythonnet提供了cp ...

  7. 使用ctypes在Python中调用C++动态库

    使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #in ...

  8. C# 调用C++动态库注意事项

    C# 调用C++动态库注意事项 最近项目上需要在C#中调用C++,期间遇到不少坑,总结如下: 1.in const char*   对应C#中string 或  IntPtr 2.out const ...

  9. JNI_Android项目中调用.so动态库

    JNI_Android项目中调用.so动态库 2014年6月3日 JNI学习 參考:http://blog.sina.com.cn/s/blog_4298002e01013zk8.html 上一篇笔者 ...

随机推荐

  1. 切换Fragment时实现数据保持

    摘要 Fragment设计初衷是为了简化不同屏幕分辨率的开发难度,他将代表一个功能的UI及其相关数据看做一个模块,以便达到复用.可以将Fragment看作是一个可以嵌入布局中的activity,有自己 ...

  2. Android TextEdit属性

    EditText继承关系:View-->TextView-->EditText 去掉边框 将EditText属性设置修改 android:background="@null&qu ...

  3. iPhone越狱cydia源大全

    越狱后如何添加cydia源及cydia源大全,希望对大家能有所帮助! 工具/原料 cydia 步骤/方法 越狱后添加cydia源 进入Cydia管理中找到软件源,先添加源. 进入“软件源”之后点击右上 ...

  4. 带你从零学ReactNative开发跨平台App开发(四)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  5. Nginx 配置多站点vhost

    假设你想在Linux Nginx中用不同的域名访问不同的目录,这时就要配置多个vhost,具体配置如下,假设网站根目录设定在/var/www/ 1.在/var/www/下新建两个目录 /var/www ...

  6. leetCode题解之Reshape the Matrix

    1.题目描述 2.分析 使用了一个队列. 3.代码 vector<vector<int>> matrixReshape(vector<vector<int>& ...

  7. UPDATE语句总结

    一.基本语句 1.SQL UPDATE 语法 UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition ...

  8. 关于Oracle中sys、system和Scott用户下的数据库连接问题

    system默认:manager sys默认:change_on_install 使用SQL Plus登录数据库时,system使用密码manager可直接登录. 由于为自己的密码时更改过的,所以我的 ...

  9. jsp 页面间传递参数

    JSP页面间传递参数是经常需要使用到的功能,有时还需要多个JSP页面间传递参数.下面介绍一下实现的方法. (1)直接在URL请求后添加 如:< a href="thexuan.jsp? ...

  10. Ogre学习教程:Ogre1.8.1+VS2010环境配置(转)

    http://blog.csdn.net/yangtrees/article/details/8724120 http://blog.csdn.net/cll611/article/details/8 ...