C 库的 C++/CLI 类包装器 - 回调

发布于 2024-10-17 07:17:40 字数 1146 浏览 3 评论 0原文

我正在使用 C++/CLI 包装 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++/CLI 下,垃圾收集器在内存中移动对象,因此向类传递简单的固定指针不再起作用。我可以通过固定对象来解决问题,但不建议这样做,因为它会导致内存碎片。似乎另一个选择是使用 auto_gcroot 指针,但我对托管 C++ 相当陌生,我不知道如何完成这项工作。

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

I am wrapping a C library using C++/CLI. The C library was designed to be used from an unmanaged C++ class. This means that the library functions accept a C++ object pointer and then provide that pointer back in callbacks. This enables the callback code to redirect requests to an appropriate event function in the calling C++ object.

The actual functions are quite involved, so I have simplified the problem space to just a few basic items:

// 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)
        {
        }
}

Now the C library functions need to be called from a managed C++ class. Under C++/CLI, the garbage collector moves objects around in memory, so passing a simple fixed pointer to the class does not work anymore. I can solve the problem by pinning the object, but that is not recommended because it leads to memory fragmentation. It seems that another option would be to use auto_gcroot pointers, but I am fairly new to managed C++ an I am not sure how to make this work.

Does anyone know how to make this work? What kind of pointer should be passed to the C function? How should the callback implementation redirect to the calling object's event function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

筱武穆 2024-10-24 07:17:40

这恰好与我现在正在做的事情相似。

以下是关于使用 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;
}

This just happens to be similar to something I'm in the middle of working on right now.

Here is an blog post on providing native callbacks using C++ classes: http://blogs.microsoft.co.il/blogs/alon/archive/2007/05/29/Native-Callback.aspx

I'm not familiar with calling C++ member functions from C, but I have done an interface (abstract base) class to another C++ class for callbacks (similar to the article). Here is a basic example of what I am providing a bridge for:

// 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();
}

Now in order to make this available for managed implementations of the provider, we have to create a series of classes that provide the bridge.

// 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();
}

Edit: Added code to show w/o the managed interface class example I use.

Here is a modified version of my example that can be used given your CLibFunc above. This is assuming how the C function performs the callback is accurate.

Also this might be able to be slimmed down a bit depending on how involved your callback classes are and how much freedom for extension you need.

// 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文