Smu*_*mur 1 c# delphi pinvoke interop delphi-7
当我调用Dll方法时,它有时会引发异常,有时则不会.
我这样称呼它:
public class DllTest
{
[DllImport(@"MyDll.dll")]
public extern static string MyMethod(string someStringParam);
}
class Program
{
static void Main(string[] args)
{
DllTest.MyMethod("SomeString");
}
}
Run Code Online (Sandbox Code Playgroud)
我有时得到的例外是:
AccessViolationException
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
AccessViolationException
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
AccessViolationException
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
有没有人知道我为什么有时会得到这个例外?为什么有时会顺利运行?
Dav*_*nan 13
您显然在p/invoke代码和Delphi代码之间存在不匹配.您还没有显示Delphi代码,但C#代码足以知道Delphi代码应该是什么样子.
您的DllImport属性使用默认值来调用约定和字符集.这意味着调用约定是stdcall,并且字符集是ANSI.您尚未指定任何编组属性,因此必须使用默认编组.
因此,您的Delphi代码必须如下所示:
function MyMethod(someStringParam: PChar): PChar; stdcall;
begin
Result := ??;
end;
Run Code Online (Sandbox Code Playgroud)
而现在这就是问题所在.p/invoke marshaller string以非常特殊的方式处理返回值.它假定p/invoke marshaller负责释放返回值的内存.它必须使用与本机代码相同的分配器.编组器的假设是将使用共享的COM分配器.
因此规则是本机代码必须通过调用分配内存和COM分配器CoTaskMemAlloc.我敢打赌,你的代码不会这样做,这肯定会导致错误.
下面是一个示例,说明如何在代码中创建与C#签名一起使用的本机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;
Run Code Online (Sandbox Code Playgroud)
虽然你可以采用这种方法,但我推荐一种替代方案.将所有字符串编组为BSTRC#端和WideStringDelphi端.这些是匹配类型,也由COM分配器分配.双方都知道如何处理这些类型,并将使您的生活更轻松.
遗憾的是,您无法WideString通过互操作边界从Delphi函数返回a ,因为Delphi对函数返回值使用不同的ABI.有关此问题的更多详细信息,请参阅我的问题为什么WideString不能用作interop的函数返回值?
因此,要解决这个问题,我们可以从Delphi代码声明返回类型TBStr.您的代码将如下所示:
C#
[DllImport(@"MyDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string MyMethod(
[MarshalAs(UnmanagedType.BStr)]
string someStringParam
);
Run Code Online (Sandbox Code Playgroud)
德尔福
function MyMethod(someStringParam: WideString): TBStr; stdcall;
begin
Result := SysAllocString(POleStr(someStringParam));
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2210 次 |
| 最近记录: |