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

2024-02-22

我正在使用 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 函数?回调实现应该如何重定向到调用对象的事件函数?


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

这是一篇关于使用 C++ 类提供本机回调的博客文章:http://blogs.microsoft.co.il/blogs/alon/archive/2007/05/29/Native-Callback.aspx 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();
}

Edit:添加了代码以显示我使用的无托管接口类示例。

这是我的示例的修改版本,可以根据您的情况使用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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 库的 C++/CLI 类包装器 - 回调 的相关文章

  • Android 回调监听器 - 将 SDK 中的 pojo 的值发送到应用程序的 Activity

    我有一个深埋在 SDK 中的 java 类 它执行一个操作并返回一个布尔值 它不知道应用程序的主要活动 但我需要主要活动来接收该布尔值 我见过很多关于回调 广播和监听器的问题 但他们似乎都了解该活动 我的 pojo 确实有一个 Activi
  • Eventbus onMessageEvent 没有被调用

    我已经在我的项目中实现了 EventBus 但我没有获得所有事件 public class MainActivity extends AppCompatActivity Override protected void onCreate Bu
  • WCF 回调:它可以与 Java 互操作吗?

    目前 我以 正常 方式实现所有 Web 服务 也就是说 我在 Eclipse 中创建一个 WSDL 文件 然后使用 WSCF blue 一个 Visual Studio 扩展 自动生成必要的代码 它是回复 请求 不过 我希望改用回调 这样我
  • Node.js 中的回调是始终异步还是始终同步?或者它们可以“有时是一个,有时是另一个”?

    我正在尝试在 Node js 中制作一些东西 并且我 像其他所有开始学习 Node 的人一样 对它的异步性质有疑问 我搜索了一下 但找不到关于它的具体问题的答案 也许我只是没有搜索得很好 所以这里是 一般来说 node js 回调是保证如果
  • 可选回调的 JavaScript 样式

    我有一些函数偶尔 并非总是 会收到回调并运行它 检查回调是否已定义 函数是一种好的风格还是有更好的方法 Example function save callback do stuff if typeof callback undefined
  • Twitter 的推文按钮有回调吗?

    有没有办法在 Twitter 的推文按钮上注册回调 我希望能够跟踪我网站上的哪些特定用户在 Twitter 上发布了链接 我无法添加 onClick 事件 因为它是跨域 iFrame 还有其他想法吗 我见过一种方法 https stacko
  • 检测 Google 验证码的挑战窗口何时关闭

    我正在使用谷歌隐形验证码 有没有办法检测挑战窗口何时关闭 我所说的挑战窗口是指您必须选择一些图像进行验证的窗口 目前 我在按钮上放置了一个旋转器 一旦单击按钮 就会呈现验证码挑战 无法向用户提示另一个质询窗口 我以编程方式调用渲染函数 gr
  • CLI/C++:void* 到 System::Object

    这是一个类似的问题这个帖子 https stackoverflow com questions 1154929 void to object in c cli 我一直无法用它来解决我的问题 我在这里包含了一些代码 希望能帮助某人了解其他帖子
  • Spotify 登录错误 INVALID_CLIENT:无效的重定向 URI android

    我正在制作一个包含 Spotify 集成的应用程序 我点击了此链接https developer spotify com technologies spotify android sdk tutorial https developer s
  • 使用 C++/CLI 包装非托管 C++ 类库 - 问题 2 - 集合

    Note 这篇文章代表了我的询问的问题 2 两个问题中都会重复介绍部分 达到数字之前的所有文本 因为它是回答问题可能需要的背景信息 问题简介 我有一个非托管 C 库 其中包含多个 更高级别 库所共有和共享的类和函数 我现在需要向 C Net
  • C++/CLI 中的 ref 和 out

    我知道 C CLI 代码 void foo Bar x 转变为 Void foo ref Bar x 变成的 C CLI 代码是什么 Void foo out Bar x 您可以使用 OutAttribute using namespace
  • 模拟函数指针

    以下类包含一个应使用回调技术计算积分的方法 package integrals import java lang public class Integrals public static double f1 double x return
  • Python子进程:cmd退出时的回调

    我目前正在使用启动一个程序subprocess Popen cmd shell TRUE 我对 Python 相当陌生 但 感觉 应该有一些 api 可以让我做类似的事情 subprocess Popen cmd shell TRUE po
  • Cython 回调适用于函数,但不适用于绑定方法

    我正在实现一个基于 cython 的 C 库接口 我实现了一个回调系统 它可以与普通函数一起使用 但在传入绑定方法时会奇怪地失败 这是我的 cython 代码的一部分 cdef extern from VolumeHapticTool h
  • 如何在 C++/CLI 中将 C++ Short* 传递给托管 C# 程序集

    我在将参数从 C CLI 代码传递到 NET C 函数时遇到问题 在 C 中 我有类似以下内容 void SomeFunction short id CSharpClass StaticClassInstance gt SetValue i
  • Shiny:从DT数据表中选定的行获取信息

    我们正在尝试重新创建示例 https demo shinyapps io 029 row selection https demo shinyapps io 029 row selection 使用DT包来渲染数据帧而不是shiny包 DT
  • 不调用 PreviewCallback 和带缓冲区的 PreviewCallback

    我对 Android 4 0 x 的预览回调有疑问 我设置了一个相机 创 建一个表面来显示相机图像on previewCallback 事件 一切正常 但对于 Android 4 0 x 则不然onPreviewCallback被称为 也不
  • 在 C++/CLI 中实现 IEnumerable

    我在实施时遇到问题IEnumerable
  • 如何在图文中突出显示单击的点?

    我正在使用选定的形状在图表上绘制更大的菱形形状 当用户单击一个点时 我在另一个 div 中显示数据 但我想突出显示单击的点 换句话说 我想 切换 点后面的数据 并且单击的点需要显示它们是否包含在数据集中 我相信我在某处见过这个 但我找不到它
  • 在回调中使用正确的上下文

    标题基本概括了所有内容 如果您有从一个类到另一个类的回调 并且需要从回调中调用一些需要上下文的方法 那么正确的上下文是什么 一个常见的例子是AsyncTask回调Activity or Fragment那个用过它 我通常会尽量避免使用get

随机推荐

  • 在 R igraph 中正确着色顶点

    我正在使用 igraph 给顶点着色 我有两个 CSV 文件答案和图表拓扑 答案 这表明玩家 K 和 N 回答正确 Player Q1 I1 1 k 1 2 l 0 3 n 1 4 m 0 拓扑 表示谁与谁相连 Node 1 Node 2
  • 使用 extraOptimizations 改造 Spark SQL AST

    我想将 SQL 字符串作为用户输入 然后在执行之前对其进行转换 特别是 我想修改顶级投影 select 子句 注入要由查询检索的附加列 我希望通过使用 Catalyst 来实现这一点sparkSession experimental ext
  • 如何使用 iframe 内的函数从父页面删除 iframe?

    我有一个使用书签放在页面上的 iframe 当我导航到此 iframe 内的某个页面时 我希望此 iframe 自行关闭 如何使用 JavaScript 做到这一点 注意 iframe 和容器页面位于不同的域中 据我所知 您无法从 ifra
  • Python:异步生成器已在运行

    如下例所示 我在使用异步生成器时遇到了异常错误 async def demo async def get data for i in range 5 loop for or while await asyncio sleep 1 some
  • Azure Web 应用程序与 Azure 移动应用程序

    我今天创建了一个Azure Web应用程序 它在设置中有一个移动部分 其中包含推送通知 移动身份验证等 您甚至可以下载移动客户端应用程序的源代码 我知道这曾经是移动应用程序 移动服务 的一部分 我创建了一个 Azure 移动应用程序来与 W
  • 识别活动网络接口

    在 NET 应用程序中 如何识别使用哪个网络接口与给定 IP 地址进行通信 我在具有多个网络接口 IPv4 和 v6 的工作站上运行 并且我需要获取用于流向给定数据库服务器的 正确 接口的地址 最简单的方法是 UdpClient u new
  • Allure Framework:TestNG 适配器错误地将 @AfterMethod 放置在报告中

    我正在使用 allure V1 4 8 TestNG 看起来 TestNG 适配器错误地将 AfterMethod 放置在报告中 基本上它将 AfterMethod 从测试用例放入下一个测试用例中 这是简单的代码 Step a test1
  • 从 .Net 应用程序打开 Windows 7 帮助 (helpPane.exe)

    我正在尝试从 Net 表单应用程序打开 Windows 7 帮助到特定书签 例如在打印机安装时 我尝试以与打开控制面板小程序相同的方式打开它 在下面的示例中返回和恢复 ProcessStartInfo startInfo new Proce
  • 当页面滚动到顶部时,Next.js 链接不会呈现

    我有一个像这样的组件 const Milestone props gt const path disabled index rest props if disabled return
  • 生成一定范围内的唯一随机数

    我需要在一定范围内生成随机的唯一数字 我该怎么做 我可以通过以下方式生成随机数 generator arr x rand min max len count arr flag 0 for i 0 i lt len i if flag 1 g
  • 如何在javascript中打印所有百分比超过70%的学生姓名?

    我在用json rule engine https www npmjs com package json rules engine https www npmjs com package json rules engine我有一份学生名单
  • 在 R 中向量化循环

    必须有一种简单的方法来向量化 R 中的以下循环 但我看不到它 w lt numeric 10 z lt rnorm 20 v lt c sample 1 10 10 sample 1 10 10 Random ordering of c 1
  • jQuery AJAX 提交表单

    我有一张带有姓名的表格orderproductForm以及未定义数量的输入 我想做某种 jQuery get 或 ajax 或类似的东西 通过 Ajax 调用页面 并发送表单的所有输入orderproductForm 我想一种方法是做类似的
  • pyside-uic 在哪里?

    我正在尝试使用 Qt Designer 和 pyside uic mydesign ui gt design py 但是 这个程序不存在 我查看了 python 2 7 下的站点包 我看到 pyside lupdate exe pyside
  • 创建项目后如何将 ndk 设置从默认 C++ 工具链更改为 C++14?

    我使用默认的 C 工具链创建了一个 Android 项目 现在 当我尝试包含双簧管上包含 C 14 功能的示例项目的代码片段时 我不断收到错误 因此 我尝试包含代码来创建模板 但现在它使我的代码变得混乱 并转储了我不希望有的声明 我尝试提及
  • 使用 Meteor.settings 功能

    Meteor 最近添加了一个全新的Meteor 设置 http docs meteor com meteor settings meteor settings对象从 v0 5 4 开始 并且以一种极其烦人的方式 没有在他们的文档中正确解释如
  • 如何将一些 XML 元素包含在边界框中?

    我想在此处附上一对复选框和单选按钮 在矩形或 边界框 中 使其看起来像这样 当然 但不那么难看 如何以以下 XML 作为起点来做到这一点
  • GeoViews:具有 matplotlib 后端的 GeoDataFrames 的分类图例

    已安装的软件包 geoviews 1 9 1 matplotlib 3 4 2 我正在尝试做什么 For the Bokeh后端通过添加分类图例GeoViews是通过代理艺术家完成的 如中所述卡特里娜飓风路径示例 https geoview
  • UITableViewCell 的 NSTextAttachment 异步加载图像

    在异步线程或图像缓存库 如 SDwebimage 中动态加载图像 下面的代码是我尝试过的 从网络获取图像后它不会重新绘制 let mutableAttributedString NSMutableAttributedString if le
  • C 库的 C++/CLI 类包装器 - 回调

    我正在使用 C CLI 包装 C 库 C 库设计为从非托管 C 类中使用 这意味着库函数接受 C 对象指针 然后在回调中提供该指针 这使得回调代码能够将请求重定向到调用 C 对象中的适当事件函数 实际功能相当复杂 因此我将问题空间简化为几个