我想我已经基本了解如何为回调编写 c# 委托(delegate),但是这个让我感到困惑。 c++定义如下:
typedef int (__stdcall* Callback)(
long lCode,
long lParamSize,
void* pParam
);
我的 C# 方法是:
unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);
虽然这似乎是不正确的,因为我得到了一个 PInvokeStackInbalance 错误,这意味着我对委托(delegate)的定义是错误的。
函数的其余参数是字符串或整数,这意味着它们不会导致错误,如果我只是传递一个 IntPtr.Zero 而不是委托(delegate)(这意味着我指向一个不存在的回调函数)我得到一个 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;
}
如果我传递的是 IntPtr.Zero
而不是委托(delegate),我在调用 _Initialize
的那一行收到了 PInvokeStackInbalance
错误,并且将函数的定义更改为 IntPtr
而不是 CallbackDelegate
然后我得到一个 AccessViolationException
。
最佳答案
我将您的代码添加到我当前的项目中,我在 VS2012 中进行了大量 C#/C++ 互操作。虽然我讨厌使用“它在我的机器上工作”,但它对我来说工作得很好。下面列出了我运行的代码,只是为了说明我没有进行根本性的更改。
我的建议是,您构建一个新的 native dll,其中包含一个用于 _Initialize 的 stub 函数,如下所示,看看当您可以控制界面的两侧时它是否有效。如果这有效但真正的 dll 无效,则归结为 native 端的编译器设置或者它们是 native 端的错误并且它正在踩踏堆栈。
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# 方面,我将声明添加到我的接口(interface)类中:
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));
关于用于 C++ 回调的 C# 委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13629798/