事情源于有个客户需使用我们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. 报表和aspx结合后在aspx页面实现工具栏的方法

     现在有好多客户在.net中用到了快逸报表,主要方法是把报表部署在一个j2ee应用中,.net部署在IIS中,把报表嵌入到aspx页面中的iframe里面.如果原本aspx页面中一些按钮或者工具, ...

  2. 类和类的关系——java

    类(对象)之间的关系   1.继承关系(子类自动拥有了父类所有的成员变量和普通方法,如果父类的成员变量和普通方法是private 的,那么子类只有拥有权,没有使用权.父类的构造方法在子类的构造方法执行 ...

  3. 灰度图的直方图均衡化(Histogram Equalization)原理与 Python 实现

    原理 直方图均衡化是一种通过使用图像直方图,调整对比度的图像处理方法:通过对图像的强度(intensity)进行某种非线性变换,使得变换后的图像直方图为近似均匀分布,从而,达到提高图像对比度和增强图片 ...

  4. MySQL8.0初体验

    MySQL8.0的官方社区开源版出来有段时间了,而percona的8.0版本还没有正式对外发布(已发布测试版),一直以来也没安装体验下这个号称质的飞跃的版本,今天正好有些时间就下了安装体验体验. 一. ...

  5. 从零开始学习Docker

    由于项目中可能用到docker容器,在此记录一下我的学习过程 1,docker的安装,wget -qO- https://get.docker.com/ | sh,查看docker是否安装成功: 此处 ...

  6. 安装Window Server 2008的些配置

    上次安装window server2008,由于server2008需要设置很多东西,不然用起来很不爽,就说IE吧,每次随便打开一个网页都要弹出n多窗口出来叫你添加到信任域里面!太烦人了![下面有解决 ...

  7. spine获取骨骼位置

    time: 2015/07/23 版本: /****************************************************************************** ...

  8. Redis学习---Redis操作之List

    List操作,redis中的List在在内存中按照一个name对应一个List来存储 lpush(name,values) --> 实际上是左添加 # 在name对应的list中添加元素,每个新 ...

  9. September 03rd 2017 Week 36th Sunday

    What does it profit a man if he gains the whole world and loses his own soul? 失去灵魂,赢得世界又如何? It matte ...

  10. JDBC规范(转)

    公司开发一直用的是ibatis,进来心血来潮想研究一下源码,可是发现自己的JDBC似乎已经忘得差不多了,为了自己能顺利的研读ibatis的源码,于是乎找到了 XIAO_DF的JDBC规范的博客,转到自 ...