繁体   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