如何从 PInvoke 本机回调返回 StringBuilder 或其他字符串缓冲区

2023-12-02

我想要一种干净的方法来增加本机代码填充所需的 StringBuilder() 的大小,下面的回调方法看起来很干净,但不知何故我们得到了缓冲区的副本而不是实际的缓冲区 - 我感兴趣解释和解决方案(最好坚持回调类型分配,因为如果它可以工作的话,它会很好而且干净)。

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace csharpapp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var buffer = new StringBuilder(12);
            // straightforward, we can write to the buffer but unfortunately
            // cannot adjust its size to whatever is required
            Native.works(buffer, buffer.Capacity); 
            Console.WriteLine(buffer);

            // try to allocate the size of the buffer in a callback - but now
            // it seems only a copy of the buffer is passed to native code
            Native.foo(size =>
                           {
                               buffer.Capacity = size;
                               buffer.Replace("works", "callback");
                               return buffer;
                           });
            string s = buffer.ToString();
            Console.WriteLine(s);
        }
    }

    internal class Native
    {
        public delegate StringBuilder AllocateBufferDelegate(int bufsize);
        [DllImport("w32.dll", CharSet = CharSet.Ansi)]
        public static extern long foo(AllocateBufferDelegate callback);
        [DllImport("w32.dll", CharSet = CharSet.Ansi)]
        public static extern void works(StringBuilder buf, int bufsize);
    }
}

原生标头

#ifdef W32_EXPORTS
#define W32_API __declspec(dllexport)
#else
#define W32_API __declspec(dllimport)
#endif

typedef char*(__stdcall *FnAllocStringBuilder)(int);
extern "C" W32_API long foo(FnAllocStringBuilder fpAllocate);
extern "C" W32_API void works(char *buf, int bufsize);

本机代码

#include "stdafx.h"
#include "w32.h"
#include <stdlib.h>

extern "C" W32_API long foo(FnAllocStringBuilder fpAllocate)
{
    char *src = "foo       X";
    int len = strlen(src) + 1;

    char *buf = fpAllocate(len);
    return strcpy_s(buf,len,src);
}

extern "C" W32_API void works(char *buf, int bufsize)
{
    strcpy_s(buf,bufsize,"works");
}

我有一个关于为什么会发生这种情况的理论。我怀疑编组StringBuilder涉及制作数据的副本,将其传递给 P/Invoke 调用,然后复制回StringBuilder. 我实际上无法验证这一点 though.

唯一的替代方法是需要StringBuilder首先被展平(它内部是一个链表char[]的),以及char[]固定,即使这样,这只适用于编组到指向 Unicode 字符字符串的指针,但不适用于 ANSI 或 COM 字符串。

因此,当你通过一个StringBuilder作为一个参数,.NET 有一个明显的位置可以将任何更改复制回来:就在 P/Invoke 返回之后。

当您传递返回返回值的委托时,情况并非如此StringBuilder。在这种情况下,.NET 需要创建一个包装器来转换int => StringBuilder函数变成int => char*功能。该包装器将创建char*缓冲区并填充它,但显然还无法复制任何更改。在该功能之后它也无法执行此操作takes代表回来了:现在还太早!

事实上,根本没有明显的地方可以发生反向复制。

所以我的猜测是,这就是发生的情况:当编组StringBuilder-返回委托,.NET只能执行单向转换,因此您所做的任何更改都不会反映在StringBuilder。这比完全无法召集这些代表要好一些。


至于解决方案:我建议首先询问本机代码缓冲区需要有多大,然后在第二次调用中传递适当大小的缓冲区。或者,如果您需要更好的性能,请猜测足够大的缓冲区,但允许本机方法传达需要更多空间。这样,大多数调用将只涉及一次 P/Invoke 转换。

这可以封装到一个更方便的函数中,您可以从托管世界中调用该函数,而不必担心缓冲区。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 PInvoke 本机回调返回 StringBuilder 或其他字符串缓冲区 的相关文章

  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 如何使用MemoryCache代替Timer来触发一个方法?

    以下方法通过等待已运行操作的结果来处理并发请求 对数据的请求可能会使用相同 不同的凭据同时出现 对于每组唯一的凭据 最多可以有一个GetCurrentInternal呼叫正在进行中 当准备就绪时 该呼叫的结果将返回给所有排队的服务员 pri
  • 使用 Unity 在构造函数中使用属性依赖注入

    好的 我在基类中定义了一个依赖属性 我尝试在其派生类的构造函数内部使用它 但这不起作用 该属性显示为 null Unity 在使用 container Resolve 解析实例后解析依赖属性 我的另一种选择是将 IUnityContaine
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • Process.Start() 方法在什么情况下返回 false?

    From MSDN https msdn microsoft com en us library e8zac0ca v vs 110 aspx 返回值 true 表示有新的进程资源 开始了 如果由 FileName 成员指定的进程资源 St
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • 使用 GhostScript.NET 打印 PDF DPI 打印问题

    我在用GhostScript NET http ghostscriptnet codeplex com打印 PDF 当我以 96DPI 打印时 PDF 打印效果很好 但有点模糊 如果我尝试以 600DPI 打印文档 打印的页面会被极大地放大
  • 当另一个线程可能设置共享布尔标志(最多一次)时,是否可以读取共享布尔标志而不锁定它?

    我希望我的线程能够更优雅地关闭 因此我尝试实现一个简单的信号机制 我不认为我想要一个完全事件驱动的线程 所以我有一个工作人员有一种方法可以使用关键部分优雅地停止它Monitor 相当于C lock我相信 绘图线程 h class Drawi
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐

  • 如何在“CollectionEditor”对话框中启用属性的默认值

    请先阅读整个问题以理解where我将能够重置属性的默认值 当定义一个可以可视化设计的自定义类时 可以实现一个集合编辑器来修改列表 数组 集合等属性 使用以下模式 Editor typeof CollectionEditor typeof U
  • 使用 Microsoft Jet OLEDB 的 CSV 列限制

    我正在从包含大约 350 列的 CSV 导入数据 这个 CSV 导入是固定的 我完全无法控制它 如果我尝试在 Excel 2003 中打开 CSV 由于列限制为 255 IV 它只能部分加载 当我使用 OleDb 和 Microsoft J
  • Python 挑战字符串编码

    我有以下提供者列表 俄语 providers u u041e u041e u041e u041a u0432 u0430 u0440 u0442 u0430 u043b u041b u0435 u043e u043f u043e u043b
  • 如何在 Spring.NET 中配置静态类的属性?

    如何通过 Spring NET 配置静态类 考虑下面的类 static class Abc public Interface xyz get set public void Show xyz show 也许解决方法可以帮助 这不是一个静态类
  • OpenCV imwrite 函数导致“未定义符号”

    我正在开发一个软件 它由一些带有 python 绑定的核心 C 代码组成 C 代码已经使用了大量 OpenCV 但现在我试图在两者之间保存图像 但我似乎无法使用imwrite功能 将其添加到 main cpp 中并使用 默认 构建在 ecl
  • 如何使用表单名称作为字符串创建新的表单实例

    使用表单名称创建封闭表单的新表单实例的代码 我想用变量替换长的选择案例列表 模块完整代码 在 Access 2010 中 我有一个 VBA 函数 当给定包含表单名称的字符串时 该函数会打开表单的新实例 通过将表单变量 frm 添加到集合中
  • 图片在浏览器中显示为垃圾字符

    谁能告诉我为什么当我尝试通过浏览器访问图像 URL 时 它显示一堆内容类型为文本 纯文本的垃圾字符 eg https www domainname com client image name jpg显示如下 3 1AQa q2 B R b3
  • 如何使用 php 将文件添加到 ziparchive 中新创建的文件夹中?

    如上图所示 我有组织在虚拟文件夹中的图像 在 mysql 数据库中 但不是真实文件夹中 我需要使所选文件夹可供使用下载为 zip 文件 我能够压缩图像 但是我们如何添加子目录以便向其中添加图像 我尝试使用addEmptyDir 但无法找到向
  • 当条码扫描仪发送以换行符结尾的数据时如何使按钮散焦

    我正在编写一个 C 条形码应用程序 我有一个 EAN 13 正则表达式来检测 Form1 KeyPress 函数中的条形码 我没有机制来检测输入来自哪里 这是我的问题 我的表单中有一个重置按钮 可以清除 dataGridView 中列出的所
  • 无法全局安装旧版本的 phpunit phar

    正如给出的https phpunit de manual current en installation html installation phar verification 全局安装PHAR的步骤是 wget https phar ph
  • DLIB:针对 194 个地标训练 Shape_predictor(helen 数据集)

    我正在训练DLIB s 形状预测器对于 194 个面部特征点 使用海伦数据集用于通过以下方式检测人脸特征点face landmark detection ex cppdlib 库 现在它给了我一个sp dat大约的二进制文件45 MB与给定
  • Live Sass 编译器 - @use 导致编译错误

    我在用着Live Sass 编译器 v3 0 0在我的 VS Code 中 每当我使用 use rule从另一个文件导入变量 但是 当我使用 Sass 命令行界面时 sass watch 编译我的文件 它会抛出没有错误 因此 我想问一下这是
  • macOS DriverKit:制作 PCI dext 来替换内置驱动程序

    我正在尝试在 DriverKit 中编写一个用户空间 PCI 驱动程序 用于教育 研究目的 我找到了一个来自 WorthDoingBadly 的示例其中包含 PCI 设备 dext 的样板代码 我已删除了漏洞利用代码 我已将其修改为通过以下
  • 检测 IE 中包含 PDF 的 iFrame 的 onload 事件

    我发现这个问题已经在这里被问过很多次了 有些解决方案部分有效 这就是场景 我需要加载一个包含 pdf 的 iframe 有可能找不到 PDF 我将在 iFrame 中显示错误页面 加载 iframe 后 我会查找标签使用 iframe co
  • 我如何在不使用 virtual 关键字的情况下重写这个 C++ 继承的成员函数?

    我有一个小程序来演示简单的继承 我正在定义一个派生自哺乳动物的 Dog 类 这两个类共享一个名为 ToString 的简单成员函数 当我不使用 virtual 关键字时 Dog 如何覆盖 Mammal 类中的实现 我是否需要使用 virtu
  • Android:修改录制的视频质量

    我正在使用 MediaRecorder 录制视频 假设视频的大小保持不变 我不清楚应该使用哪些参数来改变图像的质量 例如 我想始终创建 640x480 mp4 视频 我可以调整哪些参数来提高或降低质量 您可以尝试使用 recorder se
  • 自 ubuntu 升级以来未定义对“dlopen”的引用

    自从我升级到 ubuntu 13 10 和 gcc 4 8 1 以来 我遇到了对 dlopen 问题的未定义引用 makefile 已经工作多年了 特定的调用是 gcc rdynamic o ov dbutil ov dbutil o li
  • 离子闪屏和旋转器

    有没有办法在启动屏幕中自定义微调器 目前我正在使用 cordova flashscreen 插件 我想更改出现在启动屏幕上的微调器的颜色 In platforms android src org apache cordova splashs
  • 将sql查询转换为jpa

    我有一个疑问 SELECT d name count e id FROM department d LEFT OUTER JOIN employee e on e department id d id and e salary gt 500
  • 如何从 PInvoke 本机回调返回 StringBuilder 或其他字符串缓冲区

    我想要一种干净的方法来增加本机代码填充所需的 StringBuilder 的大小 下面的回调方法看起来很干净 但不知何故我们得到了缓冲区的副本而不是实际的缓冲区 我感兴趣解释和解决方案 最好坚持回调类型分配 因为如果它可以工作的话 它会很好