我们应该将 COM 中的 BSTR 类型视为值还是引用?

2023-12-25

来自书本ATL内部结构,我知道BSTR与OLECHAR*不同,BSTR有CComBSTR和CString。

根据MSDN为 BSTR 分配和释放内存 http://msdn.microsoft.com/en-us/library/vstudio/xda6xzx7%28v=vs.110%29.aspx,我知道调用者/被调用者的内存管理责任。

从 MSDN 中获取这一行,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

我还是不知道如何处理bstr在我的实施中正确地执行。因为我对 BSTR 仍然有一个基本问题——我们应该治疗吗?bstr作为值(如 int)或作为引用(如 int*),至少在 COM 接口边界上。

我想在我的实现中尽快将 BSTR 转换为 CString/CComBSTR。值或引用语义对于转换来说将是完全不同的情况。我深入研究了CComBSTR.Attach、CComBSTR.AssignBSTR等,但代码无法解决我的疑问。

MSDN CComBSTR.Attach 有一些代码片段,我觉得它是错误的,因为它不遵守为 BSTR 分配和释放内存 http://msdn.microsoft.com/en-us/library/vstudio/xda6xzx7%28v=vs.110%29.aspx。 ATL Internals 表示 SetSysString 将“释放传入的原始 BSTR”,如果我使用它,它将违反 BSTR 参数约定,就像 CComBSTR.Attach 一样。

总而言之,我想在实现中使用 CString 来处理原始 BSTR,但不知道正确的方法...我在我的项目中编写了一些只是工作的代码,但我总是感到紧张,因为我不知道是否我是对的。

让我谈谈编码语言

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)
{
// What I do NOT know
CString str1;  // 1. copy bstr (with embeded NUL)
CString str2;  // 2. ref bstr

// What I know
CComBSTR cbstr1;
cbstr1.AssignBSTR(bstr); // 3. copy bstr 
CComBSTR cbstr2;
cbstr2.Attach(bstr); // 4. ref bstr, do not copy

// What I do NOT know
// Should we copy or ref bstr ???
}

CComBSTR只是一个RAII 包装器 http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization around raw BSTR。所以请放心使用CComBSTR而不是原始的BSTR帮助编写异常安全的代码,这使得泄漏资源(即原始 BSTR)变得更加困难,等等。

If the BSTR is an input参数,它就像一个const wchar_t*(带有长度前缀,并且可能有一些NULs L'\0'里面的字符)。如果BSTR没有NULs 嵌入内部,您可以简单地将其传递给CString构造函数,这将对其进行深层复制,并且您可以在本地使用您的CString。对此的修改CString在原件上将不可见BSTR。您也可以使用 std::wstring (并注意std::wstring可以处理嵌入式NUL也是如此)。

void DoSomething(BSTR bstrInput)
{
    std::wstring myString(bstrInput);
    // ... work with std::wstring (or CString...) inside here
}

相反,如果BSTR is an output参数,然后使用另一级间接传递,即BSTR*。在这种情况下,您可以使用CComBSTR::Detach()在你的方法中释放BSTR安全地包裹在CComBSTR,并将其所有权转移给调用者:

HRESULT DoSomething( BSTR* pbstrOut )
{
    // Check parameter pointer
    if (pbstrOut == nullptr)
        return E_POINTER;

    // Guard code with try-catch, since exceptions can't cross COM module boundaries.
    try
    {
        std::wstring someString;
        // ... work with std::wstring (or CString...) inside here

        // Build a BSTR from the ordinary string     
        CComBSTR bstr(someString.c_str());

        // Return to caller ("move semantics", i.e. transfer ownership
        // from current CComBSTR to the caller)
        *pbstrOut = bstr.Detach();

        // All right
        return S_OK;
    }
    catch(const std::exception& e)
    {
        // Log exception message...
        return E_FAIL;
    }
    catch(const CAtlException& e)
    {
        return e; // implicit cast to HRESULT
    }
}

基本上,这个想法是使用BSTR(封装在 RAII 类中,例如CComBSTR) only 在边界处,并使用进行本地工作std::wstring or CString.

作为“奖励阅读”,请考虑Eric Lippert 的 BSTR 语义指南 http://blogs.msdn.com/b/ericlippert/archive/2003/09/12/52976.aspx.

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

我们应该将 COM 中的 BSTR 类型视为值还是引用? 的相关文章

随机推荐

  • 是否可以在javascript中创建固定长度的数组?

    在Javascript中 是否可以创建一个保证长度保持不变的数组 例如 数组A创建的长度为 2 随后 任何调用的尝试A push or A pop 或设置值A 5 将失败 A length永远是 2 这是输入数组的方式 例如Float32A
  • 选择列表框中的项目后打开新表单

    我的表单上有一个列表框和一个按钮 列表框包含 3 个元素 房屋 人物 户外 我还创建了 3 个表单来表示列表框中的值 我希望用户突出显示列表框中的项目 单击按钮后我想打开用户选择的表单 我怎样才能实现这个目标 我已经尝试过这个链接 通过单击
  • groovy 脚本中提供的名称无效(机制级别:KrbException:无法找到默认领域)

    我有一个连接到 MSSQL 数据库的 groovy 脚本 几周前它工作得很好 但今天我上传了 mac os 的最后一个版本 我的脚本给了我这个例外 Caught java sql SQLException I O Error GSS Fai
  • d3.js:强制布局中建议的节点位置

    我想创建一个图表 其中节点具有建议的位置 但我也想使用力布局来确保节点本身不重叠 这在d3中可能吗 是的 您可以通过以下方式执行此操作 禁用默认的重力和电荷力 实施碰撞检测 http mbostock github com d3 talk
  • Dockerhub 的访问令牌

    我创建了一个存储库hub docker com现在想要使用我的凭据将我的映像推送到 Dockerhub 我想知道是否必须使用我的用户名和密码 或者是否可以创建某种访问令牌来推送 docker 映像 我想做的是使用docker image来自
  • 如何找到 php_smart_string.h 而不是 php_smart_str.h?

    It s me tmp pear install inclued 0 1 3 make bin bash tmp pear install inclued 0 1 3 libtool mode compile cc I I tmp pear
  • 创建 DLL 以在两个进程之间共享内存

    我需要使用 DLL 来实现类似于 Linux 共享内存的功能 我的Windows编程经验很少 但我认为有可能实现我的目标 我想要类似下面的东西 DLL int x void write int temp x temp int read re
  • Webpack 错误:请手动安装 sqlite3 包

    我正在使用 Electron 和 Sequelize 构建一个应用程序 我开始配置数据库 然后 我收到此错误 未捕获的错误 请手动安装 sqlite3 包 在新的 ConnectionManager home matheusdrdj Doc
  • 快速递增 Int!不工作

    我理解选项是如何工作的 但这让我陷入了困境 我有一个变量叫做num我想增加它 所以我做了以下操作 var num Int 0 num ERROR Unary operator cannot be applied to an operand
  • 如何在 Playground 中运行异步回调

    许多 Cocoa 和 CocoaTouch 方法都具有在 Objective C 中作为块实现的完成回调以及在 Swift 中作为闭包实现的回调 然而 当在 Playground 中尝试这些时 永远不会调用完成 例如 Playground
  • 如何在Android中以编程方式从网络下载文件?

    在我的应用程序中 从 Web 下载大量文件 这些文件大小约为 200Mb 已压缩 如何在 Android 中以编程方式下载文件 实际上我关心的是代码的性能 如何处理其间的错误和网络问题 这是我最近为此编写的一些代码 try URL u ne
  • 来自 sqlalchemy 的 psycopg2 register_composite

    是否可以以某种方式使用函数注册复合材料 http initd org psycopg docs extras html psycopg2 extras register composite来自 psycopg2 当我使用 sqlalchem
  • 有没有办法可以将 FormattedText 包含在 Xamarin.Forms 的 .alert 中?

    我有一个格式化的字符串 在代码中 它不止于此 但这只是一个示例 var fs new FormattedString fs fs Spans Add new Span Text ABC ForegroundColor Color FromH
  • 将 Inno Setup 中许可证向导页面上的单选按钮替换为复选框

    有没有简单的方法可以用 Inno Setup 中的单个 选中 未选中 复选框替换许可证向导页面上的标准 2 个单选按钮 而无需创建自定义页面 由于没有设置可以在许可证单选按钮和某些许可证复选框之间切换 至少只是因为在WizardForm 你
  • 虚函数和 std::function?

    考虑以下 C 17 代码 include
  • Firebase Firestore子集合安全查询

    我的 Cloud Firestore 数据库中有以下规则 service cloud firestore match databases database documents match performances performanceId
  • 读取不确定的值是未定义的行为吗?

    该问题出现在该问题答案的评论中当类型转换为 int 时 C C bool 类型是否始终保证为 0 或 1 https stackoverflow com questions 4276207 is c c bool type always g
  • 将 pandas 数据框插入 Postgres

    我有一个 pandas 数据框 我想将其插入到 Django 项目中的 Postgres 数据库中 数据框有5列 数据库表有6列 而且数据框列和数据库列顺序不同 那么 在合并两者之前 我是否必须确保数据框和数据库表中的列顺序相同 请建议我如
  • SAS 无法识别日期格式

    我有以下字符日期格式 3 1990 4 1990 5 1990 我尝试了以下代码 data work temps set indata newdate input strip Date MMYYSw rename newdate date
  • 我们应该将 COM 中的 BSTR 类型视为值还是引用?

    来自书本ATL内部结构 我知道BSTR与OLECHAR 不同 BSTR有CComBSTR和CString 根据MSDN为 BSTR 分配和释放内存 http msdn microsoft com en us library vstudio