公司有个很古老的系统,代码量很大,并且稳定线上运行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的更多相关文章

  1. 分享一次C#调用Delphi编写Dll程序

    1.前言: 最近接手了一个项目需要和Delphi语言编写的一个系统进行一些接口的对接,数据在传输过程中采用Des加密方式,因为Delphi 平台的加密方式和C#平台的加密方式不互通,所以采用的方式是C ...

  2. 用delphi的THTTPRIO控件调用了c#写的webservice。

    用delphi的THTTPRIO控件调用了c#写的webservice. 下面是我调试时遇到的一些问题: 1,导入wsdl文件:file--new----other----wenservice---W ...

  3. Delphi XE3写DLL,用Delphi7调用,报错!

    http://bbs.csdn.net/topics/390870532 用delphi xe3写的DLL,delphi7调用,参数都是PAnsiChar,DLL里的函数接收delphi7传的入参,没 ...

  4. 新奇:(nodejs兄弟)用HTML + FLASH +JS 也可以写桌面EXE。

    首先看下面这张图片,下面的所有界面都是用html代码实现的. 编程IDE:vb6.0 使用控件:WEBBROWSER 原理:使用olelib 让程序继承:IDocHostUIHandler 和 ICu ...

  5. JAVA调用C语言写的SO文件

    JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...

  6. (转载)将DELPHI数据库连接写进INI配置文件中

    将DELPHI数据库连接写进INI配置文件中 procedure TDM.DataModuleCreate(Sender: TObject); var piececonfg:Tinifile; pat ...

  7. java调用C/C++写的dll(转)

    源:java调用C/C++写的dll Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性. Java调用C/C++写好的DLL ...

  8. 关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题

    关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题,有需要的朋友可以参考下. php调用java写的soap接口经验:   场景一: java是以数组的形式接收参数的 ...

  9. 更改开机默认不显示explorer.exe,直接启动自己写的EXE程序方法

    原文:更改开机默认不显示explorer.exe,直接启动自己写的EXE程序方法 更改开机默认不显示explorer.exe,直接启动自己写的EXE程序的函数: bool UpdateWinlogon ...

随机推荐

  1. Domino(群组工作软件)

    ylbtech-Miscellaneos: Domino(群组工作软件) “Domino”是一种群组工作软件.使用了Domino的服务器就叫Domino服务器Domino的功能强大,界面丰富,主要用于 ...

  2. go语言之进阶篇error接口应用

    1.error接口应用 示例: package main import "fmt" import "errors" func MyDiv(a, b int) ( ...

  3. libcurl HTTP POST请求向服务器发送json数据【转】

    转载:http://blog.csdn.net/dgyanyong/article/details/14166217 转载:http://blog.csdn.net/th_gsb/article/de ...

  4. Linux:磁盘挂载

    本来虚拟centos的服务器的磁盘分配的就不大,之前只分配了20G的样子,由于最近有装了不少软件,比如nifi压缩版就有1.2G的大小,一下子没有磁盘资源了.今晚就折腾在这事上了. [root@mas ...

  5. [Algorithm] Check if a binary tree is binary search tree or not

    What is Binary Search Tree (BST) A binary tree in which for each node, value of all the nodes in lef ...

  6. C++ 函数适配器

    1.考虑下面的需求,在一个int的vector中,找出一个比5的元素,容易想到的解决办法,定义一个方法对象,使用模板,如下:vector<int>::iterator iter = fin ...

  7. 使用 HTML5, javascript, webrtc, websockets, Jetty 和 OpenCV 实现基于 Web 的人脸识别

    这是一篇国外的文章,介绍如何通过 WebRTC.OpenCV 和 WebSocket 技术实现在 Web 浏览器上的人脸识别,架构在 Jetty 之上. 实现的效果包括: 还能识别眼睛 人脸识别的核心 ...

  8. WinRAR如何批量分别压缩不同的文件夹

    全选所有文件夹,然后右击添加到压缩文件,然后在文件选项中勾选把每个文件放到单独的压缩文件中   OK了  

  9. angular5中使用jsonp请求页面

    说多了,都是眼泪,折腾了很久,各种百度,查到的例子,全都报错,可能是因为我的angular的版本太高,向下都不兼容? 我的angular版本为最新的5.2.11: 下面是正确的jsonp请求的方法 1 ...

  10. SQL从一个表查询数据插入/更新到另一个表

    示例一: 从数据库表A中查询出数据插入到数据库表B 从数据库DataBaseA的表TDA中查询出数据插入到数据库DataBaseB的表TDB insert into [DataBaseA].[dbo] ...