我想我基本上已经理解了如何为回调编写c#delegates,但这个让我很困惑。 c ++定义如下:
typedef int (__stdcall* Callback)(
long lCode,
long lParamSize,
void* pParam
);
我的c#方法将是:
unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);
虽然这看起来不正确,因为我收到了PInvokeStackInbalance错误,这意味着我对委托的定义是错误的。
函数的其余参数是字符串或整数,这意味着它们不会导致错误,如果我只是传递一个IntPtr.Zero而不是委托(这意味着我指向一个不存在的回调函数)我得到一个AccessViolation错误,这也是有意义的。
我做错了什么?
编辑:
完整的c ++函数是:
int
__stdcall
_Initialize (
const char* FileName,
Callback cbFunction,
int Code,
const char* Name,
unsigned int Option,
unsigned int Option2
);
我的c#版本是:
[DllImport("MyDll.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int _Initialize (string FileName, CallbackDelegate cbFunction, int Code, string Name, uint Options, uint Options2);
该函数是(用于测试)刚刚在控制台应用程序的主例程中调用:
static void Main(string[] args)
{
CallbackDelegate del = new CallbackDelegate(onCallback);
Console.Write(_Initialize("SomeFile.dat", del, 1000, "", 0, 4));
Console.Read();
}
onCallback
就是这样:
static int onCallback(int lCode, int lParamSize, IntPtr pParam)
{
return 0;
}
如果我传递PInvokeStackInbalance
代替委托,我在_Initialize
调用的行上出现IntPtr.Zero
错误,并将函数的定义更改为{{1} }而不是IntPtr
然后我得到CallbackDelegate
。
答案 0 :(得分:5)
我将您的代码添加到我当前的项目中,我在VS2012中进行了大量的C#/ C ++互操作。虽然我讨厌使用“它在我的机器上工作”,但它对我来说很好。我运行它的代码在下面列出,只是为了说明我没有进行和基本的更改。
我的建议是你为_Initialize构建一个带有存根函数的新本机dll,如下所示,当你可以控制界面的两面时,看看它是否有效。如果它工作但真正的dll没有,它归结为本机端的编译器设置或它们是本机端的错误,它在堆栈上踩踏。
extern "C" {
typedef int (__stdcall* Callback)(long lCode,long lParamSize,void* pParam );
TRADITIONALDLL_API int __stdcall _Initialize (const char* FileName,Callback cbFunction, int Code,
const char* Name,unsigned int Option,unsigned int Option2)
{
cbFunction(0, 0, nullptr);
return 0;
}
}
在C#方面,我将声明添加到我的接口类:
public delegate int CallbackDelegate(int lCode, int lParamSize, IntPtr pParam);
[DllImport("XXX.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int _Initialize(string FileName, CallbackDelegate cbFunction, int Code, string Name, uint Options, uint Options2);
然后在我的主要:
private int onCallback(int lCode, int lParamSize, IntPtr pParam)
{
return 0;
}
XXXInterface.CallbackDelegate del = new XXXInterface.CallbackDelegate(onCallback);
Console.Write(XXXInterface._Initialize("SomeFile.dat", del, 1000, "", 0, 4));
答案 1 :(得分:3)
.NET long
是64位。 C ++ long
可能只有32位。请查看编译该定义的C ++编译器,了解long
的大小。
答案 2 :(得分:3)
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);
如果.NET假定使用cdecl而不是stdcall,那么你的堆栈肯定会受到冲击。