如何在 C++/CLI 中包装 C 库回调

2024-01-08

给定以下具有要求设置缓冲区的回调事件的 C 库,如何以类型安全的方式编写正确的 C++/CLI 包装器?

// The callback signature
typedef void (__cdecl *BUFFERALLOCATOR)(void *opaque, void **buffer);

// A struct that contains the context of the library
struct lib_context_base_s
{
    // The stored callback function pointer 
    BUFFERALLOCATOR buffer_allocator;
    // Opaque pointer that contain the local context. Needed in C because
    // C doesn't have closures (functions that knows the context where
    // they are defined)
    void* opaque;
};

typedef struct lib_context_base_s lib_context_base;

// Init the base context
lib_context_base* new_lib_context_base()
{
    return malloc(sizeof(lib_context_base));
}

// Free the base context
void free_lib_context_base(lib_context_base *lib_context_base)
{
    free(lib_context_base);
}

// Set the buffer allocation callback
void set_allocate_buffer_callback(lib_context_base *lib_context_base,
                                  BUFFERALLOCATOR allocate_buffer, void* opaque)
{
    lib_context_base->buffer_allocator = allocate_buffer;
    lib_context_base->opaque = opaque;
}

该库应该可由托管代码使用delegate void BufferAllocator(ref IntPtr buffer) .


我会坚持类型安全原则:我知道已经有Marshal.GetFunctionPointerForDelegate但这需要在 C++/CLI 中进行函数指针类型转换,并隐藏编组非托管->托管的工作方式(调试要困难得多,我不喜欢不理解场景中发生的情况)。刚刚注意到该方法类似于this https://stackoverflow.com/questions/4982404/c-cli-class-wrapper-for-c-library-callbacks但不需要托管本机类(开销更少)。请告诉我您是否知道如何进一步简化它(维护类型安全和编组控制)并减少开销。

以下是C++/CLIWrapper.h header:

#include <gcroot.h>

using namespace System;
using namespace System::Runtime::InteropServices;

namespace LibraryWrapper
{
    // Declare the cdecl function that will be used 
    void cdecl_allocate_buffer(void *opaque, void **buffer);

    public ref class Library
    {
    public:
        // The BufferAllocator delegate declaration, available to any clr language
    // [In, Out] attributes needed (?) to pass the pointer as reference
        delegate void BufferAllocator([In, Out] IntPtr% buffer);

    internal:
        // The stored delegate ref to be used later
        BufferAllocator ^_allocate_buffer;

    private:
        // Native handle of the ref Library class, castable to void *
        gcroot<Library^> *_native_handle;
        // C library context
        lib_context_base *_lib_context_base;

    public:
        Library();
        ~Library();
        // The clr callback setter equivalent to the C counterpart, don't need
        // the context because in CLR we have closures
        void SetBufferAllocateCallback(BufferAllocator ^allocateBuffer);
    };
}

遵循 C++/CLiWrapper.cpp定义:

#include "wrapper.h"

namespace LibraryWrapper
{
    Library::Library()
    {
        // Construct the native handle
        _native_handle = new gcroot<Library^>();
        // Initialize the library base context
        _lib_context_base = new_lib_context_base();
        // Null the _allocate_buffer delegate instance
        _allocate_buffer = nullptr;
    }

    Library::~Library()
    {
        free_lib_context_base(_lib_context_base);
        delete _native_handle;
    }

    void Library::SetBufferAllocateCallback(BufferAllocator ^allocateBuffer)
    {
        _allocate_buffer = allocateBuffer;
        // Call the C lib callback setter. Use _native_handle pointer as the opaque data 
        set_allocate_buffer_callback(_lib_context_base, cdecl_allocate_buffer,
            _native_handle);
    }

    void cdecl_allocate_buffer(void *opaque, void **buffer)
    {
        // Cast the opaque pointer to the hnative_handle ref (for readability)
        gcroot<Library^> & native_handle = *((gcroot<Library^>*)opaque);
        // Prepare a IntPtr wrapper to the buffer pointer
        IntPtr buffer_cli(*buffer);
        // Call the _allocate_buffer delegate in the library wrapper ref
        native_handle->_allocate_buffer(buffer_cli);
        // Set the buffer pointer to the value obtained calling the delegate
        *buffer = buffer_cli.ToPointer();
    }
}

可以这样使用(C#):

// Allocate a ~10mb buffer in unmanaged memory. Will be deallocated
// automatically when buffer go out of scope
IntPtr _buffer = Marshal.AllocHGlobal(10000000);

// Init the library wrapper
Library library = new Library();

// Set the callback wrapper with an anonymous method
library.SetBufferAllocateCallback(delegate(ref IntPtr buffer)
{
    // Because we have closure, I can use the _buffer variable in the outer scope
    buffer = _buffer;
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 C++/CLI 中包装 C 库回调 的相关文章

  • ASP.NET 会员电子邮件验证

    尝试基于 C 创建电子邮件验证本文 https web archive org web 20211020153319 https www 4guysfromrolla com articles 062508 1 aspx 我创建了一个 ja
  • Windows 10 UWP 中的视觉状态管理器未在页面加载时应用初始状态

    我有一个带有相关面板的页面 可以根据宽度重新组织 但是 除非宽度 gt 720px 否则它似乎不会在加载时应用任何状态 如果我在加载页面后调整页面大小 则两种状态都有效 解决方法是检查加载页面上的窗口大小并手动选择状态 但我相信这应该自动处
  • 为什么不能使用initializer_list来初始化unique_ptr的向量? [复制]

    这个问题在这里已经有答案了 我想知道为什么initializer list 不能与unique ptr 一起使用 std vector
  • 无法在表适配器配置属性中找到对象“Web.config”的连接“MyConnName”

    I want to change the query in table adapter but it s not opening throwing an error Configure table Adapter Failed in pro
  • 如何自定义 ASP.Net Core 模型绑定错误?

    我只想从我的 Web API Asp net Core 2 1 返回标准化的错误响应 但我似乎不知道如何处理模型绑定错误 该项目刚刚从 ASP NET Core Web 应用程序 gt API 模板创建 我有一个简单的操作定义为 Route
  • ASP.NET Core 中 AsNoTracking 的模拟或更好的解决方法

    您如何模拟 AsNoTracking 或者是否有更好的解决方法来解决此问题 Example public class MyContext MyContextBase Constructor public MyContext DbContex
  • MSVC10 /MP 在项目中跨文件夹构建非多核

    我希望有人指出我们所遇到的错误或解决方法 使用 MP 编译项目时 似乎仅同时编译同一文件夹中的文件 我使用进程资源管理器来滑动命令行并确认行为 项目过滤器似乎对同时编译的内容没有影响 项目结构disk Folder project vcxp
  • std::async 参数的生命周期是多少?

    看来函数的参数是通过std async分享未来的生活 include
  • 使用 CMake 对 SDL 的未定义引用

    我正在使用 SDL v1 2 15 7 和 CMake 3 2 1 开发一个项目 在 h 文件中我添加了 include
  • android 销毁时是否有任何视图回调?

    我有一个自定义视图组件 我在片段或活动中使用了它 我想知道当它从片段 活动中销毁时是否有回调 View 没有回调 除了finalize 但我不认为这就是你所要求的 查看有onDetachedFromWindow 当它从屏幕上移除时 但这与它
  • Math.Sin、Math.Cos 和 Math.Tan 精度以及正确显示它们的方法

    我正在用 C 编写一个计算器 textBoxResult是一个文本框 我在其中显示数字 recount是以度为单位获取角度并以弧度为单位返回的函数 我的角度是从texBoxInput public double recount int nu
  • Ajax 函数在重定向后不保存滚动位置

    正如标题所述 我编写了一个 ajax 函数 该函数应该滚动到用户在重定向之前所在的位置 我写了一个alert对于测试场景 它确实触发了 但滚动不断回到顶部 我在这里做错了什么 JavaScript ajax type GET url Adm
  • 如何在Phone类库项目中添加ResourceDictionary并访问它

    我正在开发一个项目 其中我有一个引用图书馆项目的子项目 在我的库项目 电话类库 中 如何创建 ResourceDictionary xaml 其中我需要添加一些样式并在 xaml 文件和 cs 文件中使用它 我需要访问 xaml 文件中的
  • 为什么 C++20 范围不只提供管道语法?

    我知道这个问题听起来很奇怪 所以这里有一些背景信息 最近 我很失望地了解到 C 20 范围内的映射缩减并不像人们所期望的那样工作 即 const double val data transform accumulate 不起作用 你必须这样
  • 验证域用户凭据

    我需要一种方法来验证 Windows 上本机 C 的用户 密码对 输入的是用户名和密码 用户可以是 DOMAIN user 格式 基本上我需要编写一个函数 如果用户 密码是有效的本地帐户 则返回 true 第1部分 如果用户 密码在给定的域
  • 更改成员资格、角色等的默认连接字符串

    默认情况下 我的网络应用程序似乎正在使用LocalSqlServer作为用于任何应用程序服务 例如成员资格 角色 身份验证 等 的连接字符串 有什么方法可以更改默认连接字符串应该是什么 默认值是 LocalSqlServer 似乎很随意 我
  • 不兼容的指针到字符转换

    我正在编写一个程序 将卡片值写入 52 个点字符的多维数组中 该程序是一个测试数组 稍后我将其作为函数写入主程序中 在程序中 我通过以下方式初始化 for 循环计数0通过51 我用一个switch语句调制13将卡牌值分配给数组点 但是 我收
  • 使用 QTestLib 时抑制 qDebug

    我正在向 Qt 中的项目添加单元测试 并希望使用 QTestLib 我已经设置了测试并且它们运行良好 问题是在项目中我们重写了 qDebug 以输出到我们自己的日志文件 这在运行应用程序时效果很好 问题是当我测试类时 它有时会开始记录 然后
  • 使texture2D在运行时/脚本Unity3D中可读[重复]

    这个问题在这里已经有答案了 我有一个插件 可以让我访问 Android 手机图库中的图片 这给了我一个Texture2D类型的纹理 然后我想使用 GetPixels 函数对其进行编辑 但默认情况下它未设置为可读 如何使纹理可读 以便我可以在
  • 如何在您的网站中连接两个人

    有一款名为 Verbosity 的游戏 这是一款有目的的游戏 位于此链接上www gwap com 在游戏中 他们随机连接两个玩家互相玩 游戏是玩家1应该向他的搭档 玩家2 描述一个单词 而玩家2应该猜测这个单词 我正在尝试建立一个网站来执

随机推荐

  • 查看 Music.app 中正在播放的歌曲

    在 iOS 上 我的应用程序是否可以找到音乐应用程序中当前正在播放的歌曲 例如 如果他们在使用我的应用程序时在后台播放歌曲 我可以获得有关该歌曲的信息吗 如果可以的话 有没有办法让我的应用程序在新歌曲开始播放时收到某种通知 谢谢 可以获得这
  • 将列转换为字符串,保留 NaN(作为 None 或空白)

    我想格式化列表中的一堆数字 最简单的方法是首先将其转换为一堆字符串 这是我如何执行此操作的示例 df col name astype str tolist 然而 问题是我得到的值如下 12 19 13 99 1 00 nan 9 00 有什
  • 使用 nginx 和 uWSGI 的多个服务器进程

    我注意到你可以在 nginx 后面的一个 uWSGI 实例中启动多个进程 uwsgi processes 4 socket tmp uwsgi sock 或者你可以在不同的套接字上启动多个uWSGI实例 并使用nginx在它们之间进行负载平
  • 制作 Erlang 版本的最佳实践是什么?

    我一直在查看 Faxien Sinan 和 Rebar Erlang OTP 的基本理念似乎是在单个 Erlang 映像实例上安装应用程序和发布 保持版本独立的最佳实践是什么 有没有一种方法可以打包版本 这样您就不必修改要部署到的计算机的站
  • 在 Sql Server 中将列中的逗号分隔值拆分为多行

    我的表有三列 其中一列 Col3 有多个值 因此 当我在桌子上发出选择命令时 Select col1 col2 col3 from MyTable 它给了我以下结果 Col1 Col2 Col3 Row 1 430 A319 N1160 N
  • git pull 和 git pull 有什么区别?

    我今天偶然发现了一些奇怪的事情 我请一位暑期工作的同事帮我为我的代码设置一个新的远程 git 存储库 但我对他所做的和我想做的有很多困惑 我要求他发送他的配置 以便能够查看他的遥控器的路径 但发现他没有遥控器 当我问他这个问题时 他这样解释
  • 将声明复制为标头已被弃用,并将从 v4.0 中删除 - lcobucci/jwt 包中的 Laravel Passport Problem

    我在用着laravel passport 7 5 1包在我的 laravel 项目中 最近遇到了这个异常 任何想法 我暂时降级了lcobucci jwt 3 4 0打包到lcobucci jwt 3 3 3 Replicating clai
  • python:pandas - 如何将 pandas 数据帧的前两行合并到数据帧标题?

    我正在尝试读取一个 Excel 文件 如下所示 我还有一个脚本 可以将此 xlsx 文件转换为带有工作表名称的 csv 文件 如果三张工作表可用 那么它将创建三个不同的 csv 文件 它的 csv 文件如下所示 Unnamed 0 Gend
  • SQL 排序规则影响性能

    我只想检查几件事 Q1 Latin1 General CI AS 不区分大小写 区分重音 即SQL 会将以下内容视为相等 hello 和 HELLO 使用 LINQ 我经常这样做 db Where v gt v Email some ema
  • Numpy 相当于 list.index

    在多次调用的低级函数中 我需要执行与 python 的 list index 相同的操作 但使用 numpy 数组 该函数需要在找到第一个值时返回 否则引发 ValueError 就像是 gt gt gt a np array 1 2 3
  • 如何横向打印 HTML?

    这个问题已被提出并得到回答 但高度赞成的接受答案都是 没有解释如何做 不起作用 The reason of course is that the accepted answer1 https stackoverflow com a 1392
  • 包含所有 ascii 字符的字符串

    我想在 JavaScript 中创建一个包含所有 ASCII 字符的字符串 我怎样才能做到这一点 const s 0123456789 lt gt ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrs
  • Python 在 O(n) 时间和 O(1) 内存中查找多数数 [重复]

    这个问题在这里已经有答案了 我正在研究我的算法解决技能 但我在解决 O 1 内存复杂度的问题时遇到了困难 问题陈述 给定一个整数数组 您的任务是将多数数打印到标准输出 stdout 如果一个数字在大小为 N 的数组中出现超过 N 2 次 则
  • HTTP/1.1 响应多个范围

    在编写 HTTP 1 1 服务器时 我在处理多个范围请求时陷入困境 RFC 2616 的第 14 35 1 节引用了一些示例 但没有阐明服务器行为 例如 GET some resource HTTP 1 1 Range bytes 200
  • C# 中的数据加密和密钥管理

    走哪条路 有什么利弊 哪条更安全 1 生成 AES 密钥 用它加密数据 然后用 RSA 加密 AES 密钥 将加密数据和加密 AES 密钥保存到文件中 并将 RSA 密钥对保存到 KeyContainer 2 或者使用 DPAPI Prot
  • 如何停止/使 NStimer 失效

    我在用 NSTimer scheduledTimerWithTimeInterval 0 1f target self selector selector update userInfo nil repeats YES 我不想再把这个计时器
  • Mysql 将 XXXXXXXXXXXX 这样的字符串格式化为 XX-XX-XXXXXXX-X

    我需要一个看起来像 XXXXXXXXXXXX 的字符串 看起来像这样 XX XX XXXXXXX X 我不知道 MySQL 中是否有函数或模式工具可以做到这一点 你 在 MySQL 中 实现此目的的一种方法是使用带有 SUBSTRING 和
  • Rails 嵌套连接 Activerecord 有条件

    我正在尝试编写带有条件的嵌套连接查询 我现在的查询是 Event joins store gt retailer where store retailer id 2 其输出以下 SQL SELECT events FROM events I
  • 如何对现有应用程序进行 dockerize...基础知识

    我使用的是 Windows 并安装了 boot2docker 我已经从 docker hub 下载了图像并运行基本命令 但 如何获取本地计算机上的现有应用程序 假设它有一个文件index php 为简单起见 我如何将其放入 Docker 映
  • 如何在 C++/CLI 中包装 C 库回调

    给定以下具有要求设置缓冲区的回调事件的 C 库 如何以类型安全的方式编写正确的 C CLI 包装器 The callback signature typedef void cdecl BUFFERALLOCATOR void opaque