VS2017写的exe调用Delphi 7写的DLL
公司有个很古老的系统,代码量很大,并且稳定线上运行10几年,这系统是公司的核心,公司收入基本靠它,系统几乎都是Delphi 7写的,要重写是不可能的。因为Delphi 7编译出来的DLL默认的导出符号就是二进制稳定的C符号。
所以,理论上任何语言都可以调用该DLL导出的API。
值得注意的是,在调用导出API的时候任何语言都是利用LoadLlibrary,GetProcAddress的原理来进行调用的。如果用C++来调用,最好这个干。
调用该API的输入输出参数最好要是平坦内存结构,比如C语言类型的结构体,注意结构体字段与Delphi的导出的结构体的字段长度对应一致。
如果是C#,最后用Marshal相关的函数对参数对象进行转换成平台内存结构来做输入输出,这样才能保证不出错。
如果用C# ,以下是代码参考:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices; namespace CSharpCallDelphiDLL
{
class Program
{ [StructLayout(LayoutKind.Sequential)]
public struct PReadPatientInfoIn
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] Xmlin;
} [StructLayout(LayoutKind.Sequential)]
public struct PReadPatientInfoOut
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] Xmlout;
} [StructLayout(LayoutKind.Sequential)]
public struct PErrorInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] ErrorXml;
} [DllImport(@"C:/Users/MathxH/Desktop/CSharpCallDelphiDLL/CSharpCallDelphiDLL/bin/x86/Debug/Hisint.dll",
EntryPoint = "ReadPatientInfo", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
extern static void ReadPatientInfo(ref PReadPatientInfoIn pIn, ref PReadPatientInfoOut pOut, ref PErrorInfo pErr); static void Main(string[] args)
{
Console.WriteLine("Enry"); PErrorInfo err;
PReadPatientInfoIn sss;
PReadPatientInfoOut ooo; String kk = "<ROOT><HOSPITALCODE>0003</HOSPITALCODE><PERSONNO></PERSONNO><ARRANGER>陈哈哈</ARRANGER><SECTIONNAME>骨科</SECTIONNAME><ZFLB>11</ZFLB><MZZDMC>癌症</MZZDMC><IDENTIFYNO>532625194704222925</IDENTIFYNO><MSGNO>71</MSGNO></ROOT>"; String emm = ""; Encoding gb2312; System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
gb2312 = Encoding.GetEncoding("GB2312");
Byte[] bytes = gb2312.GetBytes(kk.PadRight());
sss.Xmlin = bytes;
// sss.Xmlin = PadRightEx(kk,4002).ToCharArray(); ooo.Xmlout = encoding.GetBytes(emm.PadRight());
err.ErrorXml = encoding.GetBytes(emm.PadRight()); ReadPatientInfo(ref sss, ref ooo, ref err); // String outss = new String(ooo.Xmlout);
String outss = gb2312.GetString(ooo.Xmlout); Console.ReadLine(); }
}
}
以上代码期间出了一些错误:
1. 抛出BadImageFormatException的异常,也就是exe的代码要与所调用的DLL的机器位数一致,x86只能调用x86的,x64只能是x64.
2. 未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配。 这个需要C#这边的array长度与声明的长度一致,需要Padding补齐
3. System.Runtime.InteropServices.COMException”类型的未经处理的异常在 CSharpCallDelphiDLL.exe 中发生
传递给系统调用的数据区域太小。 (异常来自 HRESULT:0x8007007A)。这个是PadRight的时候出现中文编码导致填充的长度出现问题。把中文改成英文就不会出错了。
4. 针对问题3,因为参数肯定会有中文,所以,需要把编码转换成GB2312 locale
references:
https://www.cnblogs.com/wintalen/archive/2010/12/20/1911599.html
https://blog.csdn.net/cnhk1225/article/details/53265042
http://blog.51cto.com/andwp/1352739
https://www.cnblogs.com/Robert-huge/p/5130284.html
http://www.myexception.cn/h/1381235.html
VS2017写的exe调用Delphi 7写的DLL的更多相关文章
- 分享一次C#调用Delphi编写Dll程序
1.前言: 最近接手了一个项目需要和Delphi语言编写的一个系统进行一些接口的对接,数据在传输过程中采用Des加密方式,因为Delphi 平台的加密方式和C#平台的加密方式不互通,所以采用的方式是C ...
- 用delphi的THTTPRIO控件调用了c#写的webservice。
用delphi的THTTPRIO控件调用了c#写的webservice. 下面是我调试时遇到的一些问题: 1,导入wsdl文件:file--new----other----wenservice---W ...
- Delphi XE3写DLL,用Delphi7调用,报错!
http://bbs.csdn.net/topics/390870532 用delphi xe3写的DLL,delphi7调用,参数都是PAnsiChar,DLL里的函数接收delphi7传的入参,没 ...
- 新奇:(nodejs兄弟)用HTML + FLASH +JS 也可以写桌面EXE。
首先看下面这张图片,下面的所有界面都是用html代码实现的. 编程IDE:vb6.0 使用控件:WEBBROWSER 原理:使用olelib 让程序继承:IDocHostUIHandler 和 ICu ...
- JAVA调用C语言写的SO文件
JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...
- (转载)将DELPHI数据库连接写进INI配置文件中
将DELPHI数据库连接写进INI配置文件中 procedure TDM.DataModuleCreate(Sender: TObject); var piececonfg:Tinifile; pat ...
- java调用C/C++写的dll(转)
源:java调用C/C++写的dll Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性. Java调用C/C++写好的DLL ...
- 关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题
关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题,有需要的朋友可以参考下. php调用java写的soap接口经验: 场景一: java是以数组的形式接收参数的 ...
- 更改开机默认不显示explorer.exe,直接启动自己写的EXE程序方法
原文:更改开机默认不显示explorer.exe,直接启动自己写的EXE程序方法 更改开机默认不显示explorer.exe,直接启动自己写的EXE程序的函数: bool UpdateWinlogon ...
随机推荐
- go语言之进阶篇error接口的使用
1.error接口的使用 示例: package main import "fmt" import "errors" func main() { //var e ...
- 解决easyui combobox不能默认选中
开始出现很奇怪的问题,ff没有问题IE8还是会出现不能选中默认项的问题,更改了select.input的方式,数据加载方式也更改为json的方式,未果,最后将datagrid toolbar的初始化放 ...
- CSS-图像映射
图像映射是将一些区域变成热点,我们在网上获取搜索图片,图片上会有关于任务的简短信息介绍,还有一个接触更多的就是QQ空间的相册,浏览QQ空间照片鼠标滑动到人物头像的时候让你选择标记人物,都是将图片和内容 ...
- Backbone.js 中使用 Model
前面几篇 Backbone.js 的例子中有使用到 template, 及数据的填充,其实这已经很接近 Model 了.现在来学习怎么创建自己的 Model 类,并简单的使用.Backbone.js ...
- 赋值操作符、复制构造函数、析构函数、static成员练习
/** * 定义一个Employee类,包含雇员名字和一个唯一的雇员标识,为该类定义默认构造函数和参数为表示 * 雇员名字的string构造函数.如果该类需要复制构造函数或赋值操作符,实现这些函数 * ...
- offsetof与container_of宏[总结]
1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...
- echarts文档对照
echarts的各种配置项可以对照这个文档: https://echarts.baidu.com/echarts2/doc/option.html#title~tooltip.axisPointer. ...
- mke2fs 制作ext2文件系统image
方法1: 利用/dev/ram1: linux下有很多ram,我们用ram1,首先把ram1格式化成ext2文件系统[root@gucuiwen babylinux]# sudo mkfs.ext ...
- ASP入门(二)-创建Access数据库
通常来说,ASP程序是搭配Access数据库来使用的,因此在安装完ASP环境后,为了方便建立和管理数据库,我们还需要安装Access数据库. Access是Microsoft Office家族中的一员 ...
- Android Context完全解析,你所不知道的Context的各种细节
Context相信所有的Android开发人员基本上每天都在接触,因为它太常见了.但是这并不代表Context没有什么东西好讲的,实际上Context有太多小的细节并不被大家所关注,那么今天我们就来学 ...