我使用C/C++LI包装C库. C库旨在从非托管C类中使用.这意味着库函数接受C对象指针,然后在回调中提供该指针.这使得回调代码能够将请求重定向到调用C对象中的适当事件函数.
实际的功能非常复杂,所以我将问题空间简化为几个基本项:
// 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/C++LI下,垃圾收集器在内存中移动对象,因此将一个简单的固定指针传递给该类不再起作用.我可以通过固定对象来解决问题,但不建议这样做,因为它会导致内存碎片.似乎另一种选择是使用auto_gcroot指针,但我对托管C相当新,我不知道如何使这项工作.
解决方法
这恰好与我正在进行的工作类似.
这是一篇关于使用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(); }
这是我的示例的修改版本,可以在上面的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; }