1

我正在尝试从 C# 调用非托管 DLL。我对非托管代码和 P\Invoke 的经验很少,所以我希望多一双眼睛。

除了函数之外,我没有太多关于 DLL 的信息:

int Initialize(char *FileName, int Driver, int(*InfoLine)(char*), char *Message);

信息行可以为空。

所以这就是我在 C# 中所做的。
导入调用:

[DllImport(@"c:\Core\initialization.dll", EntryPoint="Initialize", CharSet = CharSet.Auto)]
private static extern int Initialize([MarshalAs(UnmanagedType.LPStr)] string FileName, int Driver, System.IntPtr InfoLine, [MarshalAs(UnmanagedType.LPStr)] string Message);

方法调用是:

IntPtr infoLine = IntPtr.Zero;
string message = "";
int success = Initialize(@"c:\config.dat", -1, infoLine, message);

Visual Studio 在调试模式下返回给我的错误消息是:

调用 PInvoke 函数“初始化”使堆栈失衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

我错误地传递了哪个参数?

我相当肯定对 DLL 的调用是正确的,因为有另一个函数没有传递参数并且类似的导入和方法代码有效。

谢谢您的帮助。

4

1 回答 1

3

尝试放入DllImport(... , CallingConvention=CallingConvention.Cdecl)

将参数传递给“本机”函数有 4 种方法。您必须知道哪一个是正确的(将它们放在内存中的哪个位置,谁必须在函数之后将它们从内存中删除......)。默认的是StdCall. 您的函数可能使用 Cdecl。见这里:http: //msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx

如果/当您决定使用Infoline回调时,

[UnmanagedFunctionPointer(CallingConvenction.Cdecl)]
private delegate int InfolineDelegate(
        [MarshalAs(UnmanagedType.LPStr)] string str);

private static extern int Initialize(
        [MarshalAs(UnmanagedType.LPStr)] string fileName, 
        int driver, 
        [MarshalAs(UnmanagedType.FunctionPtr)] InfolineDelegate infoLine, 
        [MarshalAs(UnmanagedType.LPStr)] string message);

如果Initialize将使用委托但不会存储它:

Initialize("FileName", 1, MyMethod, "Message");

但是 ifInitialize将存储委托以供以后使用,返回后:

// Put it outside the function... As a property/field of the class, for example
InfolineDelegate method = MyMethod;

Initialize("FileName", 1, method, "Message");

InfolineDelegate method 必须具有比您使用的方法更长的保证生命周期。所以不是局部变量。通常是调用类的字段/属性。

于 2013-08-14T12:43:52.490 回答