c# - 将 C 回调函数封装在 C# 函数中

标签 c# c callback

我需要使 C# 程序可以访问用 C 编写的 DLL。我用 C# 编写了一个包装器 DLL,它包装了每个 C 接口(interface)函数。 我得到了一个可以正常运行的代码,但最终崩溃并显示以下消息:

Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'D:\WrapperTest\bin\x64\Debug\WrapperTest.exe'.

Additional information: A callback was made on a garbage collected delegate of type 'vJoyInterfaceWrap!vJoyInterfaceWrap.vJoy+WrapFfbCbFunc::Invoke'.

导致崩溃的部分与 C# 代码向 DLL 注册的回调函数有关。当 DLL 从注册的回调函数调用(或返回)时,就会发生崩溃。

C DLL 接口(interface):

// Definition of callback function prototype
// Parameter 1: Pointer to a data structure to be used inside the CB function
// Parameter 2: Pointer to user-defined data passed during registration
typedef void (CALLBACK *FfbGenCB)(PVOID, PVOID);

// Registration of CB function.
// Parameter cb is a pointer to the callback function.
// Parameter data is a pointer to user-defined data
VOID        __cdecl FfbRegisterGenCB(FfbGenCB cb, PVOID data);

C# 接口(interface):

我希望用户定义的数据是一个对象(而不是 IntPtr)。 为此,我使用预定义的回调函数封装了用户的回调函数,该函数将 IntPtr 转换为对象。 早些时候在注册过程中,我注册了预定义的回调函数并将用户定义的数据(C# 对象)转换为 IntPtr。

// The user-defined CB function is of type FfbCbFunc
//  FfbCbFunc is defined:
public delegate void FfbCbFunc(IntPtr data,  object userData);

// The registration of the predefined callback function _WrapFfbCbFunc is done by calling
// function FfbRegisterGenCB:
       public void FfbRegisterGenCB(FfbCbFunc cb, object data)
        {
            // Convert object to pointer
            GCHandle handle1 = GCHandle.Alloc(data);

            // Apply the user-defined CB function
            _g_FfbCbFunc = new FfbCbFunc(cb);
            WrapFfbCbFunc wf = new WrapFfbCbFunc(_WrapFfbCbFunc);

            _FfbRegisterGenCB(wf, (IntPtr)handle1);
        }

以下是其他定义和声明:

// Placeholder for user defined callback function
private static FfbCbFunc _g_FfbCbFunc;

// predefined callback function that encapsulates the user-defined callback function
public delegate void WrapFfbCbFunc(IntPtr data, IntPtr userData);
public void _WrapFfbCbFunc(IntPtr data, IntPtr userData)
        {
            // Convert userData from pointer to object
            GCHandle handle2 = (GCHandle)userData;
            object obj = handle2.Target as object;

            // Call user-defined CB function
            _g_FfbCbFunc(data, obj);
        }

最佳答案

包装回调函数及其引用必须是静态:

// Make wf global and static
private static WrapFfbCbFunc wf;

// Make the wrapping callback function static
public static void  _WrapFfbCbFunc(IntPtr data, IntPtr userData)
{

    object obj = null;

    if (userData != IntPtr.Zero)
    {
        // Convert userData from pointer to object
        GCHandle handle2 = (GCHandle)userData;
        obj = handle2.Target as object;
    }

    // Call user-defined CB function
    _g_FfbCbFunc(data, obj);
}

附注

我不认为这是一个糟糕的问题,值得得到 -1 票。 就我个人而言,我只是忽略那些不有趣的问题。

关于c# - 将 C 回调函数封装在 C# 函数中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28806140/

相关文章:

c# - 开发类似于ASP.NET session 的系统时要考虑的安全性注意事项

C sprintf 用字节参数中断(Keil 编译器)

javascript - 当一系列 readFile 调用在 node.js 中完成时如何运行函数?

javascript - 为什么 Mongoose 的 JavaScript 在同一行中既有返回又有回调?

c# - 从右到左的工具提示文本 c#

c# - Socket.Send 和 Stream.Write 有什么区别? (与 tcp ip 连接相关)

c - 从文件读取并放入二维缓冲区

c++ - 如何使用 C++ 成员函数作为 C 框架的回调函数

c# - 来自 javascript 或 c# 的动态 html?

有人可以解释这个按位的 C 代码吗?