【问题标题】:Using Delphi DLL in C#在 C# 中使用 Delphi DLL
【发布时间】:2016-11-07 14:45:41
【问题描述】:

我有一个用 Delphi 编写的第三方“神秘 dll”(未知版本),delphi 中的工作示例(2009 年过去),迫切需要在我的 C# 代码中使用所述 dll,几乎没有相关知识如何做到这一点.

这是 Delpi 使用此 dll 的示例:

type
TD_Query = function(host: WideString; port : Word;pud,query : WideString):WideString; stdcall;
procedure TForm11.Button6Click(Sender: TObject);
var
   Handle         : LongWord;
   D_Query        : TD_Query;
   sss            : WideString;
begin

 Handle := LoadLibrary('kobrasdk.dll');
 sss:='';
 if Handle <> 0 then
 begin
  @D_Query := GetProcAddress(Handle, 'D_Query');
  sss:=D_Query('host',8201,'pud','query');
  FreeLibrary(Handle);
 end;
end;

这是我用 C# 解释它的尝试:

class Program
{
    [DllImport("C:\\Games\\kobrasdk.dll", CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Ansi)]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern string D_Query(string host, ushort port, string pud, string query);


    static void Main(string[] args)
    {
        D_Query("test", 8201, "test", "test");
    }
}

不幸的是,我遇到了一个错误:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

根据我白天阅读的内容,我可能对返回类型或参数类型进行了编造。帮忙?

【问题讨论】:

  • 看起来你的调用约定可能是错误的。我不是 Delphi 专家,但这可能会有所帮助stackoverflow.com/questions/16601423/…
  • Eww,DLL 函数不应该返回任何类型的字符串,这可能会导致问题。
  • 有一个希望 - 我想在 Delphi 中创建代理 dll,以与 CSharp 兼容的方式返回数据
  • 我问哪个@MBo链接的问题是这个问题的关键

标签: c# delphi dllimport


【解决方案1】:

对于某些类型,Delphi ABI 与 Microsoft ABI 不同。 Delphi WideString 是托管类型(在 Delphi 术语中),并且作为返回类型使用与 Microsoft 工具不兼容的 ABI。

Delphi ABI 将托管返回类型转换为隐藏的var 参数。所以编译器转换:

function(host: WideString; port: Word; pud, query: WideString): WideString; stdcall;

进入

procedure(var result: WideString; host: WideString; port: Word; pud, query: WideString); 
  stdcall;

因此,您可以通过导入转换后的函数从 C# 访问原始 Delphi 函数。

[DllImport(@"...", CallingConvention = CallingConvention.StdCall)]
public static extern void My_D_Query(
    [MarshalAs(UnmanagedType.BStr)]
    out string result,
    [MarshalAs(UnmanagedType.BStr)]
    string host,
    ushort port,
    [MarshalAs(UnmanagedType.BStr)]
    string pud,
    [MarshalAs(UnmanagedType.BStr)]
    string query
);

【讨论】:

    【解决方案2】:

    我主要是想通了。出于某种我不清楚的原因,C# 无法处理 WideString 返回值。如果您可以访问 delphi 源代码,则可能适合与过程交换函数,并将返回值作为“out”参数传递。就我而言,我无法访问源代码,因此我不得不编写一个代理 DLL 来这样做。 例如上面的“代理”dll代码:

      type
      TD_Query = function(host : WideString;port : Word;pud,query : WideString):WideString; stdcall;
    
    procedure My_D_Query(host: WideString; port: Word; pud, query: WideString; out return : WideString); stdcall;
    var
       Handle: LongWord;
       D_Query : TD_Query;
       sss : WideString;
    begin
     Handle := LoadLibrary('kobrasdk.dll');
     sss:='';
     if Handle <> 0 then
     begin
      @D_Query:=GetProcAddress(Handle, 'D_Query');
      sss:=D_Query(host,port,pud,query);
      FreeLibrary(Handle);
     end;
    return := sss;
    end;
    

    然后用 C# 代码访问它:

    [DllImport("C:\\MyDll.dll", CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Ansi)]
    public static extern void My_D_Query(
    [MarshalAs(UnmanagedType.BStr)]
            string host,
            int port,
    [MarshalAs(UnmanagedType.BStr)]
            string pud,
    [MarshalAs(UnmanagedType.BStr)]
            string query,
    [MarshalAs(UnmanagedType.BStr)]
            out string result
    );
    

    它并不漂亮,但对我来说,这就是答案。

    【讨论】:

    • 您看到@MBo 发布的链接了吗? AFAICS,WideString 返回值实际上已经是一个输出参数,应该在 C# 端声明为这样。我会先试试。
    • 不需要代理 DLL,看我的回答。也就是说,代理 DLL 是一种处理棘手导入的干净方法,这里不需要它。此外,Word 映射到 ushort
    • @DavidHeffernan 我尝试按照您的建议摆脱代理 DLL,但我不断收到“尝试读取或写入受保护的内存”。错误。顺便说一句,将 int 更改为 ushort。
    • 我的回答有误。转换将结果作为第一个参数而不是最后一个参数。我更新的答案现在可以工作了。抱歉,我记错了这个细节。
    • @DavidHeffernan 谢谢,现在接受你的回答!
    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多