簡體   English   中英

C#Interop Delphi DLL

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

C#。

[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中創建一個包裝程序

    • 第一個是IN參數
    • 第二個是OUT參數

原始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.
  • 在Visual Studio中:

使項目x32位(不是樣本中的x64)

  • 將DLL導入為Cdecl

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM