P / Invoke - 从C#调用非托管DLL

时间:2013-08-14 12:42:11

标签: c# dll pinvoke marshalling

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

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

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

Infoline可以为空。

所以这就是我在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函数'Initialize'的调用使堆栈失衡。   这可能是因为托管的PInvoke签名不匹配   非托管目标签名。检查调用约定和   PInvoke签名的参数与目标非托管匹配   签名。

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

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

感谢您的帮助。

1 个答案:

答案 0 :(得分: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");

但是如果Initialize将存储委托以便稍后使用它,则返回后:

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

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

InfolineDelegate method 必须的保证有效期大于您使用的方法。所以不是局部变量。通常是调用类的字段/属性。