我使用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;
- }