2011-02-13 61 views
7

我使用C++/CLI封装了一个C函数库。 C库设计用于从非托管C++类中使用。这意味着库函数接受一个C++对象指针,然后在回调中提供该指针。这使回调代码可以将请求重定向到调用C++对象中的适当事件函数。c库的C++/CLI类封装器 - 回调函数

的实际功能是相当复杂的,所以我简化了问题空间只有几个基本项目:

// C library function signature 
void CLibFunc(CLIBCALLBACK *callback, void *caller); 

// C callback signature 
// Second parameter is meant to point to the calling C++ object 
typedef int (__stdcall CLIBCALLBACK) (int param1, void *caller); 

// C callback implementation 
int CallBackImpl(int param1, void* caller) 
{ 
    // Need to call the ManagedCaller's EventFunction from here 
    // ??? 
} 

// C++/CLI caller class 
public ref class ManagedCaller 
{ 
    public: 
     void CallerFunction(void) 
     { 
      // Call the C library function 
      // Need to pass some kind of this class pointer that refers to this object 
      CLibFunc(CallBackImpl, ????); 
     } 

     void EventFunction(param1) 
     { 
     } 
} 

现在的C库函数需要从一个托管C++类调用。在C++/CLI下,垃圾收集器在内存中移动对象,因此传递一个简单的固定指针到类不再工作。我可以通过固定对象来解决问题,但不建议这样做,因为这会导致内存碎片。看起来,另一种选择是使用auto_gcroot指针,但我对托管C++来说是相当新的,我不知道如何使其工作。

有谁知道如何使这项工作?什么样的指针应该传递给C函数?回调实现应该如何重定向到调用对象的事件函数?

回答

3

这恰好类似于我现在正在处理中的事情。

这里是用C++类提供本地回调的博客文章:http://blogs.microsoft.co.il/blogs/alon/archive/2007/05/29/Native-Callback.aspx

我不熟悉的C调用C++成员函数,但我做了一个接口(抽象基)类到另一个C++类回调(类似于文章)。以下是我提供一个桥梁的一个基本的例子:

// Interface (abstract base) class providing the callback 
class IProvider { 
public: 
    virtual ~IProvider() {} 
    virtual void Callback() = 0; 
}; 

// User class of the callback 
class CUser { 
    IProvider * m_pProvider; 
public: 
    CUser(IProvider * pProvider) { 
     m_pProvider = pProvider; 
    } 
    void DoSomething() { 
     m_pProvider->Callback(); 
    } 
}; 

// Implementation of the interface class 
class CHelloWorldProvider : public IProvider { 
    void Callback() { 
     printf("Hello World!"); 
    } 
}; 

// Usage of the callback provider in a pure native setting 
void PureNativeUsage() { 
    CHelloWorldProvider oProvider; 
    CUser oUser(&oProvider); 
    oUser.DoSomething(); 
} 

现在为了使这个可用于供应商的管理的实现,我们必须创造了一系列提供的桥梁课程。

// Where gcroot is defined 
#include <vcclr.h> 

// Managed provider interface class 
public interface class IManagedProvider { 
    void Callback(); 
}; 

// Native bridge class that can be passed to the user 
class CProviderBridge : public IProvider { 
    // Give the managed class full access 
    friend ref class ManagedProviderBase; 

    // Store a reference to the managed object for callback redirects 
    gcroot<IManagedProvider ^> m_rManaged; 

public: 
    void Callback(){ 
     m_rManaged->Callback(); 
    } 
}; 

// Managed provider base class, this provides a managed base class for extending 
public ref class ManagedProviderBase abstract : public IManagedProvider { 
    // Pointer to the native bridge object 
    CProviderBridge * m_pNative; 

protected: 
    ManagedProviderBase() { 
     // Create the native bridge object and set the managed reference 
     m_pNative = new CProviderBridge(); 
     m_pNative->m_rManaged = this; 
    } 

public: 
    ~ManagedProviderBase() { 
     delete m_pNative; 
    } 

    // Returns a pointer to the native provider object 
    IProvider * GetProvider() { 
     return m_pNative; 
    } 

    // Makes the deriving class implement the function 
    virtual void Callback() = 0; 
}; 

// Pure managed provider implementation (this could also be declared in another library and/or in C#/VB.net) 
public ref class ManagedHelloWorldProvider : public ManagedProviderBase { 
public: 
    virtual void Callback() override { 
     Console::Write("Hello World"); 
    } 
}; 

// Usage of the managed provider from the native user 
void MixedUsage() { 
    ManagedHelloWorldProvider^rManagedProvider = gcnew ManagedHelloWorldProvider; 
    CUser oUser(rManagedProvider->GetProvider()); 
    oUser.DoSomething(); 
} 

编辑:添加代码来显示W/O的管理接口类的例子,我使用。

这里是我的例子的一个修改版本,可以使用上面给出的CLibFunc。这是假设C函数如何执行回调是准确的。

此外,这可能会减少一点,这取决于您的回调类是如何参与以及您需要多少扩展的自由度。

// Where gcroot is defined 
#include <vcclr.h> 

// C callback signature 
// Second parameter is meant to point to the calling C++ object 
typedef int (__stdcall CLIBCALLBACK) (int param1, void *caller); 

// C library function 
void CLibFunc(CLIBCALLBACK *callback, void *caller) { 
    // Do some work 
    (*callback)(1234, caller); 
    // Do more work 
} 

// Managed caller interface class 
public interface class IManagedCaller { 
    void EventFunction(int param1); 
}; 

// C++ native bridge struct 
struct CCallerBridge { 
    // Give the managed class full access 
    friend ref class ManagedCaller; 

    // Store a reference to the managed object for callback redirects 
    gcroot<IManagedCaller ^> m_rManaged; 

public: 
    // Cast the caller to the native bridge and call managed event function 
    // Note: This must be __stdcall to prevent function call stack corruption 
    static int __stdcall CallBackImpl(int param1, void * caller) { 
     CCallerBridge * pCaller = (CCallerBridge *) caller; 
     pCaller->m_rManaged->EventFunction(param1); 
     return 0; 
    } 
}; 

// C++/CLI caller class 
public ref class ManagedCaller : public IManagedCaller { 
    // Pointer to the native bridge object 
    CCallerBridge * m_pNative; 

public: 
    ManagedCaller() { 
     // Create the native bridge object and set the managed reference 
     m_pNative = new CCallerBridge(); 
     m_pNative->m_rManaged = this; 
    } 
    ~ManagedCaller() { 
     delete m_pNative; 
    } 

    // Calls the C library function 
    void CallerFunction() { 
     CLibFunc(CCallerBridge::CallBackImpl, m_pNative); 
    } 

    // Managed callback function 
    virtual void EventFunction(int param1) { 
     Console::WriteLine(param1); 
    } 
}; 

// Usage 
int main(array<System::String ^> ^args) { 
    ManagedCaller^oCaller = gcnew ManagedCaller(); 
    oCaller->CallerFunction(); 
    return 0; 
} 
+0

这只是与我的问题相切。这显示了如何在托管C++类中包装非托管C++类并使用回调。我遇到过很多这方面的例子,包括http://tweakbits.com/UnmanagedToManagedCallback.cpp等示例。我正在寻找的是如何在C++/CLI类中包装C库并使用回调的示例。在这一天结束时,我面临的问题与这些样本中解决的问题有所不同。 – Theo 2011-02-13 18:26:27