我正在尝试从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的调用是正确的,因为还有另一个函数没有传递参数,类似的导入和方法代码也起作用。
感谢您的帮助。
答案 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
必须的保证有效期大于您使用的方法。所以不是局部变量。通常是调用类的字段/属性。