gpt4 book ai didi

c# - 访问 Delphi DLL 抛出偶尔的异常

转载 作者:太空宇宙 更新时间:2023-11-03 17:15:36 25 4
gpt4 key购买 nike

当我调用 Dll 方法时,它有时会抛出异常,有时不会。

我是这样调用它的:

public class DllTest
{

[DllImport(@"MyDll.dll")]
public extern static string MyMethod(string someStringParam);
}


class Program
{

static void Main(string[] args)
{
DllTest.MyMethod("SomeString");
}
}

有时遇到的异常是这样的:


AccessViolationException



试图读取或写入 protected 内存。这通常表明其他内存已损坏。

有谁知道为什么我只有时得到这个异常?为什么有时运行很流畅?

最佳答案

您的 p/invoke 代码和 Delphi 代码显然不匹配。您没有显示 Delphi 代码,但 C# 代码足以知道 Delphi 代码应该是什么样子。

您的 DllImport 属性使用调用约定和字符集的默认值。这意味着调用约定是 stdcall 并且字符集是 ANSI。您尚未指定任何编码属性,因此必须使用默认编码。

因此您的 Delphi 代码必须如下所示:

function MyMethod(someStringParam: PChar): PChar; stdcall;
begin
Result := ??;
end;

现在问题来了。 p/invoke 编码器以一种非常特殊的方式处理 string 返回值。它假定释放返回值的内存是 p/invoke 编码器的责任。而且它必须使用与 native 代码相同的分配器。编码器做出的假设是将使用共享 COM 分配器。

因此规则是 native 代码必须通过调用 CoTaskMemAlloc 使用 COM 分配器分配内存。我敢打赌,您的代码不会那样做,那肯定会导致错误。

这是一个示例,说明如何在您的代码中创建一个使用 C# 签名的 native Delphi 函数。

function MyMethod(someStringParam: PChar): PChar; stdcall;
var
Size: Integer;
begin
Size := SizeOf(Char)*(StrLen(someStringParam)+1);//+1 for zero-terminator
Result := CoTaskMemAlloc(Size);
Move(someStringParam^, Result^, Size);
end;

虽然您可以采用这种方法,但我推荐另一种方法。在 C# 端将所有字符串编码为 BSTR,在 Delphi 端将所有字符串编码为 WideString。这些匹配类型也由 COM 分配器分配。双方都清楚地知道如何处理这些类型,并且会让您的生活更轻松。

不幸的是,您不能跨互操作边界从 Delphi 函数返回 WideString,因为 Delphi 对函数返回值使用不同的 ABI。有关此问题的更多详细信息,请参阅我的问题 Why can a WideString not be used as a function return value for interop?

因此,为了解决这个问题,我们可以将 Delphi 代码的返回类型声明为 TBStr。您的代码将如下所示:

C#

[DllImport(@"MyDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string MyMethod(
[MarshalAs(UnmanagedType.BStr)]
string someStringParam
);

德尔福

function MyMethod(someStringParam: WideString): TBStr; stdcall;
begin
Result := SysAllocString(POleStr(someStringParam));
end;

关于c# - 访问 Delphi DLL 抛出偶尔的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8533505/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com