C#调用delphi dll接口问题

最近使用C#调用delphi dll中的PChar参数接口,结果出现了内存错误。在Stack上找到了答案,转来此处。


Delphi dll中的声明

procedure PasswordDLL(month  integer; password  pchar); 
export;
C#调用部分的代码
[DllImport(
    "DelphiPassword.dll",
    CallingConvention = CallingConvention.StdCall,
    CharSet = CharSet.Ansi,
EntryPoint = "PasswordDLL")]
public static extern void PasswordDLL(    
    int month,
    [MarshalAs(UnmanagedType.LPStr)] string password
    ); 
以上方法直接调用,会产生一个异常。


相关知识:


First off Since you have not stated which Delphi version your using I will answer assuming Delphi 6 for no other reason than I am familiar with it.

Your Delphi procedure does not specify a calling convention in its declaration, so it won't be using stdcall as per your import. It will use the default Delphi register convention which places the first few parameters in registers rather than on the stack. If you can change your Delhpi DLL add stdcall; after the declaration and rebuild and your calling conventions will match.

The table below summarizes calling conventions.

Directive Parameter order Clean-up Passes parameters in registers?
--------- --------------- -------- -------------------------------
register  Left-to-right   Routine  Yes
pascal    Left-to-right   Routine  No
cdecl     Right-to-left   Caller   No
stdcall   Right-to-left   Routine  No
safecall  Right-to-left   Routine  No
Looking at the .NET documentation there does not seem to be a calling convention that matches Delphi's register convention ( see table below) so I think your only option may be to change convention in the Delphi DLL.

Member name   Description
-----------   ------------------------ 
Cdecl         The caller cleans the stack. This enables calling functions with   varargs, which makes it appropriate to use for methods that accept a variable number of parameters, such as Printf.
FastCall      This calling convention is not supported.
StdCall       The callee cleans the stack. This is the default convention for calling unmanaged functions with platform invoke.
ThisCall      The first parameter is the this pointer and is stored in register ECX. Other parameters are pushed on the stack. This calling convention is used to call methods on classes exported from an unmanaged DLL.
Winapi        Supported by the .NET Compact Framework. This member is not actually a calling convention, but instead uses the default platform calling convention. For example, on Windows the default is StdCall and on Windows CE .NET it is Cdecl.

根据描述,我们可以知道如果我们没有在delphi dll中定义函数的导出类型,那么默认会启用register类型。而上面的C#调用代码中,我们采用的是stacall。两种接口并不兼容。所以会产生参数的传递错误。

解决方案:在delphi dll中,声明函数导出类型为stdcall。然后C#同样声明函数的接口类型为stdcall。此时dll中的函数可被正常调用。


在函数调用完成后,还需要注意的一个问题为PChar值传递问题。由于PChar类型实际为指向buffer的一个指针,所以需要在C#中预先分配充足的空间,否则会出现访问内存异常的提示。


你可能感兴趣的:(C#调用delphi dll接口问题)