zoukankan      html  css  js  c++  java
  • VS2017写的exe调用Delphi 7写的DLL

    公司有个很古老的系统,代码量很大,并且稳定线上运行10几年,这系统是公司的核心,公司收入基本靠它,系统几乎都是Delphi 7写的,要重写是不可能的。因为Delphi 7编译出来的DLL默认的导出符号就是二进制稳定的C符号。

    所以,理论上任何语言都可以调用该DLL导出的API。

    值得注意的是,在调用导出API的时候任何语言都是利用LoadLlibrary,GetProcAddress的原理来进行调用的。如果用C++来调用,最好这个干。

    调用该API的输入输出参数最好要是平坦内存结构,比如C语言类型的结构体,注意结构体字段与Delphi的导出的结构体的字段长度对应一致。

    如果是C#,最后用Marshal相关的函数对参数对象进行转换成平台内存结构来做输入输出,这样才能保证不出错。

    如果用C# ,以下是代码参考:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Runtime.InteropServices;
     6 
     7 namespace CSharpCallDelphiDLL
     8 {
     9     class Program
    10     {
    11 
    12         [StructLayout(LayoutKind.Sequential)]
    13         public struct PReadPatientInfoIn
    14         {
    15             [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4001)]
    16             public byte[] Xmlin;
    17         }
    18 
    19         [StructLayout(LayoutKind.Sequential)]
    20         public struct PReadPatientInfoOut
    21         {
    22             [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4001)]
    23             public byte[] Xmlout;
    24         }
    25 
    26         [StructLayout(LayoutKind.Sequential)]
    27         public struct PErrorInfo
    28         {
    29             [MarshalAs(UnmanagedType.ByValArray, SizeConst = 201)]
    30             public byte[] ErrorXml;
    31         }
    32 
    33         [DllImport(@"C:/Users/MathxH/Desktop/CSharpCallDelphiDLL/CSharpCallDelphiDLL/bin/x86/Debug/Hisint.dll", 
    34             EntryPoint = "ReadPatientInfo", CharSet = CharSet.Ansi,
    35             CallingConvention = CallingConvention.StdCall)]
    36         extern static void ReadPatientInfo(ref PReadPatientInfoIn pIn, ref PReadPatientInfoOut pOut, ref PErrorInfo pErr);
    37 
    38         static void Main(string[] args)
    39         {
    40             Console.WriteLine("Enry");
    41 
    42              PErrorInfo err;
    43             PReadPatientInfoIn sss;
    44             PReadPatientInfoOut ooo;
    45 
    46            
    47             String kk = "<ROOT><HOSPITALCODE>0003</HOSPITALCODE><PERSONNO></PERSONNO><ARRANGER>陈哈哈</ARRANGER><SECTIONNAME>骨科</SECTIONNAME><ZFLB>11</ZFLB><MZZDMC>癌症</MZZDMC><IDENTIFYNO>532625194704222925</IDENTIFYNO><MSGNO>71</MSGNO></ROOT>";
    48             
    49             String emm = "";
    50 
    51             Encoding gb2312;
    52 
    53             System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    54             gb2312 = Encoding.GetEncoding("GB2312");
    55             Byte[] bytes = gb2312.GetBytes(kk.PadRight(4001));
    56             sss.Xmlin = bytes;
    57            // sss.Xmlin = PadRightEx(kk,4002).ToCharArray();
    58 
    59             ooo.Xmlout = encoding.GetBytes(emm.PadRight(4001));
    60             err.ErrorXml = encoding.GetBytes(emm.PadRight(201));
    61 
    62 
    63            
    64             ReadPatientInfo(ref sss, ref ooo, ref err);
    65 
    66             // String outss = new String(ooo.Xmlout);
    67             String outss = gb2312.GetString(ooo.Xmlout);
    68 
    69 
    70             Console.ReadLine();
    71 
    72         }
    73     }
    74 }

    以上代码期间出了一些错误:

     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

  • 相关阅读:
    美国州名来源
    SQL Constraint/Index
    英语中的 姓氏/Surname
    GNU glibc
    英语人名探源/字母升序排列
    About 'atoi'
    封装一个类似jquery的ajax方法
    函数柯里化
    AngularJS实现TodoMVC
    webpack简单使用
  • 原文地址:https://www.cnblogs.com/foohack/p/8625356.html
Copyright © 2011-2022 走看看