将Delphi的PChar DLL导入到C#中?

4

I have a procedure in delphi:

procedure PasswordDLL(month  integer; password  pchar); 
export;

该过程应输出我传入的“密码”pchar的密码。从我查询和阅读的资料来看,我得出结论:参考:这里这里
[DllImport(
    "DelphiPassword.dll",
    CallingConvention = CallingConvention.StdCall,
    CharSet = CharSet.Ansi,
EntryPoint = "PasswordDLL")]
public static extern void PasswordDLL(    
    int month,
    [MarshalAs(UnmanagedType.LPStr)] string password
    ); 

当我调用以下代码时:

string pass = "";
PasswordDLL(2, pass);

因此,将密码输出到“pass”字符串中。

但是我会收到BadImageFormatException was unhandled: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)的错误。

听起来我使用的函数格式是错误的? 我想知道我是否对PChar使用了不正确的UnmanagedType,但从阅读中得知,它可能是LPWStr和LPStr。 我错过了什么吗?

提前致谢...

1个回答

2

首先,由于您没有说明使用的是哪个 Delphi 版本,我将假设您使用的是 Delphi 6,原因是我熟悉它。

您的 Delphi 程序在声明中没有指定调用约定,因此它不会使用 stdcall,而是使用默认的 Delphi register 调用约定,该约定将前几个参数放在寄存器中而不是堆栈上。如果您可以更改 Delphi DLL,则在声明后添加 stdcall; 并重新构建,这样您的调用约定就会匹配。

下表总结了调用约定。

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

查看.NET文档,似乎没有与Delphi的register调用约定相匹配的约定(请参见下表),因此我认为你唯一的选择可能是在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(6)PChar(指向以 null 结尾的 ANSI 字符串的指针)编组看起来正确。

1
谢谢,你的总结帮助我理解了。 :) - King
1
还有一件事情可能会出错:PChar指向的缓冲区必须由调用者分配。否则,在退出时你将遇到AV(最好的情况)。你需要添加一个参数来指定传递给dll的缓冲区大小,确保它足够大以返回数据 - 包括空字符 - 否则返回错误。 - Stephane
太棒了,这完美地解决了我在 Delphi 5 和 C# 中遇到的问题。非常感谢 Pete。 - nrjohnstone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接