[英]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.