将字符串从Delphi动态链接库传递到.NET

3
我已经搜索了很多关于这个问题的信息,但没有明确的答案说明如何将一个字符串从Delphi DLL传递给.NET。下面的代码是基于MSDN帮助文件:http://msdn.microsoft.com/en-us/library/4zey12w5.aspx
//Delphi code

function myDelphiFunc(var Buffer: PChar): Integer; export; stdcall;
  Buffer:='this is a test';
  Return:=0;
end;

//vb.NET code

<DllImport(path)> _
Public Function myDelphiFunc(ByVal buffer As String) As Integer

Public Sub myNETFunc()
  Dim buffer_size As integer = 25
  Dim buffer As String = New String(CChar(" "), buffer_size )
  Call myDelphiFunc(buffer)
  MsgBox(Strings.Left(buffer, InStr(buffer, Chr(0)) - 1))
End Sub

当我调用myDelphiFunc时,"buffer"变量中收到一个空字符串。我做错了什么吗? 提前致谢。

对我来说,你为要返回的字符串设置了一个var参数很奇怪。我对VB一无所知,但在我看来,您已经分配了缓冲区,因此不需要从Delphi DLL返回新的char指针。然而,我决定不质疑您的设计,并发布了与您当前的Delphi代码兼容的答案。 - AlexSC
2个回答

10

您的代码存在很多问题,主要包括:

  • Delphi函数通过引用接收指针,但VB代码传递的是按值传递的。
  • Delphi代码需要将字符串复制到提供的缓冲区中。
  • Delphi代码应该使用PAnsiChar与VB匹配。或者在p/invoke上使用PWideChar和CharSet.Unicode。
  • VB代码需要使用StringBuilder而不是String,以便将字符串编组回调用方。
  • 为了避免缓冲区溢出,函数需要接受长度参数。

然而,我不确定值得太深入理解。这个最简单的方法是使用分配在共享COM堆上的BSTR。这使得函数更容易使用,并隐藏所有内存分配复杂性。

Delphi

procedure TestFunc(out str: WideString); stdcall;
begin
  str := 'foo';
end;

VB

的翻译是:

VB

<DllImport(path)> _ 
Public Sub TestFunc(<MarshalAs(UnmanagedType.BStr)> ByRef str As String)

2
更好的方法是,如果您的.NET应用程序需要频繁与dll交互,则将您的dll实现为com服务器,并利用Delphi和.NET提供的广泛的Interop支持。 - Kenneth Cochran
这是很棒的信息。我有一组Delphi代码,想要在.NET上使用。有什么建议先读什么? - Leonardo Herrera
1
+1 感谢David Heffernan。我的应用程序现在完美运行。我希望这段简单的代码能够帮助其他程序员。 - user1361263
@LeonardoHerrera 你可以从这里开始学习Delphi(http://docwiki.embarcadero.com/RADStudio/XE4/en/Developing_COM-based_Applications_Index)和.NET(http://msdn.microsoft.com/en-us/library/6bw51z5z(v=vs.110).aspx)的开发。 - Kenneth Cochran

0

你的代码应该被替换为

function myDelphiFunc(var Buffer: PChar): Integer; export; stdcall;
const
  tmp = 'this is a test';
begin
  Buffer := StrAlloc(Lenght(tmp)+1);
  StrPCopy(Buffer, PChar(tmp));
  Return:=0;
end;

不行,这样做不行。需要在Delphi中删除var。需要使用PAnsiChar。需要在.net端使用StringBuilder。在Delphi端,您需要将其复制到提供的缓冲区中。在Delphi端使用export是不必要的。 - David Heffernan
@DavidHeffernan,既然CLR基于UTF-16,为什么使用AnsiChar?如果使用P * Char,CLR应如何传递给Delphi缓冲区长度? - Arioch 'The
@Arioch 默认的平台调用(p/invoke)的编码方式是ANSI。对于UTF16,请使用CharSet.Unicode。缓冲区长度将需要一个额外的参数,例如GetWindowText函数。请在pinvoke.net上查找相关信息。 - David Heffernan
谢谢AlexSC,最终我使用了David Hofferman的解决方案。 - user1361263

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接