[英]C# Interop Delphi DLL
我有一个第三方DLL写在Delphi“a.dll”(没有源代码)。
这个DLL有一个带有此签名的方法。
function GetAny(pFileName: String): String;
我无法从c#进行互操作调用,因为'String type'在delphi中具有私有访问权限。
所以在delphi中构建另一个DLL以封装该调用。
function GetAny(pFileName: String): String; external 'a.dll'
function GetWrapper(url : PChar) : PChar; stdcall;
begin
Result := PChar(GetAny(url)); // I need avoid this String allocation, is throwing a exception.
end;
[DllImport("wrapper.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern IntPtr GetWrapper(String url);
在“GetWrapper”里面我调用了外部的“GetAny”,结果还可以(在delphi中我可以调试),但是在我将这个结果返回到c#侧之前,它会抛出异常。
IntPtr test = GetWrapper("a");
String result = Marshal.PtrToStringAnsi(test);
您的包装器DLL也无法调用GetAny,因为string是托管的Delphi类型,无法跨模块边界传递。
问题是GetAny的返回值在一个模块中分配,并在另一个模块中解除分配。 它在实现GetAny的DLL中分配,并在调用GetAny的DLL中解除分配。 由于这两个DLL使用不同的内存管理器,因此最终会尝试释放在不同堆上分配的内存。
如果可以说服实现GetAny的DLL共享内存管理器,那么您可以轻松解决该问题。
我确实质疑你提出的事实。 按照目前的情况,除非DLL被设计为与ShareMem一起使用,否则永远不能安全地调用该函数。
如果您准备泄漏内存,可以试试这个:
德尔福
function GetAny(pFileName: string): PChar; external 'a.dll'
procedure GetWrapper(url: PChar; out value: WideString); stdcall;
var
P: PChar;
begin
P := GetAny(url);
if Assigned(P) then
Value := P
else
Value := '';
end;
C#
[DllImport("wrapper.dll"]
public static extern void GetWrapper(
string url,
[MarshalAs(UnmanagedType.BStr)]
out string value
);
我已经下载了你的代码......
解决方案可能是这样的:
使用带有2个PChar类型参数的“cdecl”声明在Delphi中创建一个包装程序
原始Delphi功能:
function GetAny(pFileName: String): String; external 'a.dll';
Delphi - 包含函数的DLL:
procedure GetWrapper (url: PChar; var urlNew: PChar) cdecl;
var str: string;
begin
urlStr = string(url);
urNewStr := GetAny(urlStr);
urlNew := PChar(urNewStr);
end;
exports
GetWrapper;
begin
end.
使项目x32位(不是样本中的x64)
[DllImport("wrapper.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void GetWrapper ([MarshalAs(UnmanagedType.LPStr)]string url, [MarshalAs(UnmanagedType.LPStr)] out string urlNew);
在C#中调用:
string fileName; // = @“wertwertwertwertwer”;
GetWrapper(“2.jpg”,out fileName);
Console.WriteLine(文件名);
在我的环境中它起作用了。 (Delphi 5和VS2012)。
希望它也适合你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.