【问题标题】:PInvoke & DelphiPInvoke 和 Delphi
【发布时间】:2013-05-19 17:33:27
【问题描述】:

如何在 c# 中使用这个 dll 函数?我尝试了以下但我得到错误。 "外部组件抛出异常。"

我第一次用 C# 和 Delphi 做这个 PInvoke 的东西。

function HTTPGET(location:string):string; stdcall;
var
HTTP:TIdHttp;
begin
  HTTP := TidHttp.Create(nil);
  try
    result := HTTP.Get(location);
  finally
  FreeAndNil(HTTP);
  end;
end;


exports
  HTTPGET;

begin
end.


namespace Test
{
    class Program
    {
        [DllImport("project1.dll")]
        public static extern string HTTPGET(string location);

        static void Main(string[] args)
        {
           Console.WriteLine(HTTPGET("http://www.reuters.com/"));
        }
    }
}

【问题讨论】:

  • 您确定 HTTP.Get() 与测试地址一起正常工作吗?
  • @thalm 那只是一个测试样本网站地址:)

标签: c# delphi pinvoke


【解决方案1】:

您不能从 C# 调用该函数。那是因为您不能使用 Delphi string 进行互操作。您可以将PAnsiChar 用于从托管传递到非托管的字符串,但在另一个方向上它更复杂。您需要在调用者处分配内存,或使用共享堆。我更喜欢使用 COM BSTR 最容易完成的后一种方法。这是德尔福的WideString

discussed before 一样,您不能使用 WideString 作为互操作的返回值,因为 Delphi 使用与 MS 工具不同的 ABI 作为返回值。

Delphi 代码需要如下所示:

procedure HTTPGET(URL: PAnsiChar; out result: WideString); stdcall;

在 C# 端,你可以这样写:

[DllImport("project1.dll")] 
public static extern void HTTPGET(
    string URL,
    [MarshalAs(UnmanagedType.BStr)]
    out string result
);     

如果您希望 URL 使用 Unicode,请使用 PWideCharCharSet.Unicode

procedure HTTPGET(URL: PWideChar; out result: WideString); stdcall;
....
[DllImport("project1.dll", CharSet=CharSet.Unicode)] 
public static extern void HTTPGET(
    string URL,
    [MarshalAs(UnmanagedType.BStr)]
    out string result
);     

【讨论】:

  • 它与函数有何不同?
  • 我添加了指向答案的链接。这很复杂。
  • 更容易,做同样的事情。太棒了。
  • @DavidHeffernan,您能否解释一下何时何地释放分配给宽字符串的内存?谢谢。
  • @AJ。它在 Delphi 代码中分配,在 C# 代码中释放。您根本不需要担心它,因为框架会为您完成。既然是BSTR,那么内存来自共享的COM堆,这就是为什么你可以在不同的模块中分配和释放。
【解决方案2】:

不要使用string类型:字符串需要内存管理,C#和Delphi模块显然使用不同的内存管理器(别管C#通过char*而Delphi期望String)。尝试在您的 DLL 中将 location 类型更改为 PChar,并更改您的结果类型,使其为 PChar(应显式分配缓冲区)或其他类型,但不是 string

【讨论】:

  • 您已经忽略了堆释放的问题。使用 PChar 返回值,然后呢?在 C# 方面呢?如果本机代码返回分配有CoTaskMemAllocPChar,则可以让C# string 返回值。但是你真的必须在这样的问题中详细涵盖所有基础。它是互操作的。它仅在互操作分隔的两侧对齐时才有效。
  • @DavidHeffernan 是否有关于 Delphi 和 C# 之间更复杂互操作的指南?或者 Hydra 是更复杂事物的解决方案。
  • @t0xic 实际上并没有一个非常好的 p/invoke 指南,而且很少有关于使用 Delphi 的 p/invoke 的指南。就我个人而言,我通过编写自己的 p/invokes 来进行互操作。一旦你知道自己在做什么,这并不难。
  • @t0xic 我不怀疑。我喜欢自己做这种事情,但我可以看到其他人选择不同的方式是正确的。
【解决方案3】:

我记得,你不能用 C# 编组 delphi 字符串...你必须使用 PChar 的解决方法并自己管理内存,或者使用类似于此处最后一个答案中提供的解决方法:

Using Delphi's stuct arrays and strings in C#

【讨论】:

  • @t0xic 我改回来了,因为您的编辑完全改变了问题
【解决方案4】:

试用 Robert Giesecke 的 C# 非托管导出

https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports

由于与 php 的兼容性,我们在 Delphi App 中使用来自 c# 的加密引擎并且运行良好(因此,不存在提到的字符串问题)。

我们之前的解决方案(更糟糕):将 c# dll 注册为 com 组件并使用它。上述解决方案输出库必须放在exe目录中,无需注册即可:)

【讨论】:

  • @Lightning UnmanagedExports 很棒,但它可以解决完全不同的问题。
猜你喜欢
  • 1970-01-01
  • 2011-09-15
  • 2011-08-23
  • 2013-08-15
  • 2011-02-27
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多