C++ 回调函数到 C#

Posted

技术标签:

【中文标题】C++ 回调函数到 C#【英文标题】:C++ Callback Function to C# 【发布时间】:2020-04-24 16:58:11 【问题描述】:

我想将一个函数从 C++ 重写为 C#。我对 C++ 没有任何经验,但那是我已经写过的。带有一些功能的 DLL 导入已经可以工作了。但是这个回调的事情让我很苦恼。请帮助我:)

c++代码:

/* Structure for PBORCA_CompileEntryImport callback function. */
typedef struct pborca_comperr  

    INT     iLevel;                         
    LPTSTR   lpszMessageNumber;             
    LPTSTR   lpszMessageText;               
    UINT    iColumnNumber;                  
    UINT    iLineNumber;                   

 PBORCA_COMPERR, FAR *PPBORCA_COMPERR;


/* Prototype for PBORCA_CompileEntryImport callback function.  */            
typedef PBCALLBACK(void, *PBORCA_ERRPROC) ( PPBORCA_COMPERR, LPVOID );

我的 C# 代码:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct PBORCA_COMPERR

    public int iLevel;                            
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string lpszMessageNumber;               
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string lpszMessageText;                  
    public int iColumnNumber;                       
    public int iLineNumber;                        


private delegate void PBORCA_CALLBACK(IntPtr pDirEntry, IntPtr lpUserData);

【问题讨论】:

【参考方案1】:

据我了解,有几种可能的方法可以做到这一点。这将取决于您需要什么。

选项 1) 使用 IntPtrMarshal.GetFunctionPointerForDelegate

// A template of the function you want other code to call
// Your calling convention may be different
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] // note calling convention
delegate void PBORCA_CALLBACK(IntPtr pDirEntry, IntPtr lpUserData);  

class Orca

    [DllImport("LibraryName.dll")]
    private static extern int PBORCA_CompileEntryImport(
        IntPtr hORCASession,
        ...
        long lEntrySyntaxBuffSize,
        IntPtr pCompErrorProc, // note the IntPtr
        IntPtr pUserData);

    // An implementation of the function delegate (this will be called)
    private static void StaticImpOfTheCallback(IntPtr pDirEntry, IntPtr lpUserData)
    
        // write code here (Notice: I'm a static function)
    

    // An implementation of the function delegate (this will be called)
    private void NonStaticImpOfTheCallback(IntPtr pDirEntry, IntPtr lpUserData)
    
        // write code here (Notice: I'm not static)
    

    // Create a delegate object which will link the callback function
    private PBORCA_CALLBACK staticCallbackDel = StaticImpOfTheCallback; 

    public void SomeCallingFunction()
    
        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            Marshal.GetFunctionPointerForDelegate(staticCallbackDel), // Delegate to function ptr
            0);

        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            Marshal.GetFunctionPointerForDelegate(
                new PBORCA_CALLBACK(NonStaticImpOfTheCallback) // create a delegate instance
            ), // Delegate to function ptr
            0);
    

选项 2 直接在定义中使用delegate

// A template of the function you want other code to call
// Your calling convention may be different
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] // note calling convention
delegate void PBORCA_CALLBACK(IntPtr pDirEntry, IntPtr lpUserData);  

class Orca

    [DllImport("LibraryName.dll")]
    private static extern int PBORCA_CompileEntryImport(
        IntPtr hORCASession,
        ...
        long lEntrySyntaxBuffSize,
        [MarshalAs(UnmanagedType.FunctionPtr)] // May or may not be needed
        PBORCA_CALLBACK pCompErrorProc, // note the use of the delegate
        IntPtr pUserData);

    // An implementation of the function delegate (this will be called)
    private static void StaticImpOfTheCallback(IntPtr pDirEntry, IntPtr lpUserData)
    
        // write code here (Notice: I'm a static function)
    

    // An implementation of the function delegate (this will be called)
    private static void NonStaticImpOfTheCallback(IntPtr pDirEntry, IntPtr lpUserData)
    
        // write code here (Notice: I'm a static function)
    

    // Create a delegate object which will link the callback function
    private PBORCA_CALLBACK staticCallbackDel = StaticImpOfTheCallback; 

    public void SomeCallingFunction()
    
        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            staticCallbackDel, // no need to convert the delegate
            0);

        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            StaticImpOfTheCallback, // could call directly too.
            0);

        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            NonStaticImpOfTheCallback, // could call directly too.
            0);

        // same as above (I think)
        PBORCA_CompileEntryImport(
            0, 
            ... ,
            128, 
            new PBORCA_CALLBACK(NonStaticImpOfTheCallback), // more explicit
            0);
    

这些是我能想到的大部分变化。其中之一应该适合你。如果以上任何内容不清楚,我建议您阅读一些有关委托如何在普通 C# 中工作的文档,并在尝试将它们与 C++ 代码结合使用之前在那里进行试验。网上有很多可供代表使用的教程,如果还没有的话,他们中的一个应该希望能得到一分钱。

祝你好运

【讨论】:

感谢您的详细解答!!!这给了我一些好的想法。我必须阅读一些委托文件才能完全理解它,但一开始它是有效的。

以上是关于C++ 回调函数到 C#的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 回调到 C#

C#调用C++动态库接口函数和回调函数

C#调用C++动态库接口函数和回调函数

如何从 C# 调用具有 void* 回调和对象参数的 C++ Dll 中的函数

(74)C#里怎么样调用WIN API的函数时实现回调函数

“运行时检查失败 #0 - ESP 的值未在函数调用中正确保存”从 C++ 代码成功 C# 回调后