C#代理C ++回调 [英] C# delegate for C++ callback

查看:239
本文介绍了C#代理C ++回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我已经基本了解如何编写c#代表回调,但这一点让我很困惑。
c ++定义如下:

  typedef int(__stdcall *回调)(
long lCode,
long lParamSize,
void * pParam
);

我的c#方法将是:

  unsafe delegate int CallbackDelegate(int lCode,int lParamSize,IntPtr pParam); 

虽然这似乎不正确,因为我得到一个PInvokeStackInbalance错误,这意味着我的代理定义是错误的。



函数的其余参数是字符串或int,这意味着它们不会导致错误,如果我只传递IntPtr.Zero而不是代理(这意味着我指向一个不存在的回调函数)我得到一个AccessViolation错误,这是有道理的。



我做错了什么?



编辑:



完整的c ++功能是:

  int 
__stdcall
_Initialize(
const char * FileName,
回调cbFunction,
int代码,
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选项2);

该功能是(用于测试)刚刚在控制台应用程序的主程序中调用: p>

  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 而不是委托,并更改函数的定义为 IntPtr 而不是 CallbackDelegate 然后我得到一个 AccessViolationException

解决方案

我将代码添加到我当前正在做的很多C#/ C ++互操作的项目中在VS2012。虽然我讨厌使用它在我的机器上工作,它对我来说很好。我运行的代码如下所示,仅仅是为了说明我没有做出和根本的改变。



我的建议是,您使用_Initialize的stub函数构建新的本机dll,如下所示,并且可以控制接口的两边时是否工作。如果这样工作,但真正的dll没有,它归结为本机端的编译器设置,或者是本地的一个错误,并且它在堆栈上踩踏。

  externC{

typedef int(__stdcall *回调)(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选项2);

然后在我的主页:

  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));


I think I have basically understood how to write c# delegates for callbacks, but this one is confusing me. The c++ definition is as follows:

typedef int (__stdcall* Callback)(
long lCode,
long lParamSize,
void* pParam 
);

and my c# approach would be:

 unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);

Although this seems to be incorrect, because I get a PInvokeStackInbalance error, which means my definition of the delegate is wrong.

The rest of the parameters of the function are strings or ints, which means they cannot cause the error, and if I just pass a IntPtr.Zero instead of the delegate (which would mean I'm pointing to a non-existent callback function) I get an AccessViolation error, which makes sense aswell.

What am I doing wrong?

EDIT:

The full c++ function is:

int
__stdcall
_Initialize (
const char*         FileName,
Callback            cbFunction,
int                 Code,
const char*         Name,
unsigned int        Option,
unsigned int        Option2
);

My c# version is:

[DllImport("MyDll.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int _Initialize (string FileName, CallbackDelegate cbFunction, int Code, string Name, uint Options, uint Options2);

The function is (for testing) just called inside of the main routine of a console application:

static void Main(string[] args)
{
    CallbackDelegate del = new CallbackDelegate(onCallback);

    Console.Write(_Initialize("SomeFile.dat", del, 1000, "", 0, 4));
    Console.Read();
}

where onCallback is this:

static int onCallback(int lCode, int lParamSize, IntPtr pParam)
{
    return 0;
}

I get the PInvokeStackInbalance error on the line where I call _Initialize, if I pass a IntPtr.Zero instead of the delegate, and change the definition of the function to IntPtr instead of CallbackDelegate then I get a AccessViolationException.

解决方案

I added your code to my current project where I'm doing a lot of C#/C++ interop in VS2012. And while I hate to use the "it worked on my machine", it worked fine for me. The code as I ran it is listed out below just to illustrate that I didn't make and fundamental changes.

My suggestion is that you build a new native dll with a stub function for _Initialize such as below and see if it works when you can control both sides of the interface. If that works but the real dll doesn't, it comes down to either compiler settings on the native side or their is a bug on the native side and it is stomping on the stack.

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;
    }
}

On the C# side, I added the declarations to my interface class:

 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);

And then in my main:

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 ++回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆