我们应该将 COM 中的 BSTR 类型视为值还是引用? [英] Shall we treat BSTR type in COM as value or reference?

查看:20
本文介绍了我们应该将 COM 中的 BSTR 类型视为值还是引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ATL Internals一书中,我知道BSTR与OLECHAR*不同,BSTR有CComBSTR和CString.

From book ATL Internals, I knew BSTR is different from OLECHAR*, and there are CComBSTR and CString for BSTR.

根据 MSDN 分配和释放内存对于 BSTR,我知道调用者/被调用者的内存管理责任.

According MSDN Allocating and Releasing Memory for a BSTR, I knew memory management responsibility for caller/callee.

从 MSDN 中获取这一行,

Take this line from MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

我仍然不知道如何在我的实现中正确处理 bstr.因为我仍然有一个关于 BSTR 的基本问题——我们应该将 bstr 视为一个值(如 int)还是一个引用(如 int*),至少在 COM 接口边界上.

I still do not know how to handle bstr properly in my implementation. Since I still have a basic question for BSTR -- should we treat bstr as a value (like int) or as a reference (like int*), at least on COM interface boundary.

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

I want to convert BSTR as soon as possible to CString/CComBSTR in my implementation. Value or Reference semantic will be totally different case for the conversion. I've digged into CComBSTR.Attach, CComBSTR.AssignBSTR, etc. But the code cannot solve my doubts.

MSDN CComBSTR.Attach 有一些代码片段,我觉得它是错误的,因为它不遵守 为 BSTR 分配和释放内存.ATL Internals 说 SetSysString 会释放传入的原始 BSTR",如果我使用它,它将违反 BSTR 参数约定,就像 CComBSTR.Attach 一样.

MSDN CComBSTR.Attach has some code snip, I feel it is wrong since it is not obey Allocating and Releasing Memory for a BSTR. ATL Internals said SetSysString will 'free the original BSTR passed in', if I used it, it will violate BSTR argument convention, just like CComBSTR.Attach.

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

All in all, I want to using CString to handle raw BSTR in implementation, but do not know the correct way...I've written some just work code in my projects, but I always feel nervous since I don't know whether I am correct.

让我谈谈编码语言

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 包装器 围绕 raw BSTR.所以可以随意使用 CComBSTR 而不是原始 BSTR 来帮助编写异常安全的代码,这使得泄漏资源(即原始 BSTR)更难,等等.

CComBSTR is just a RAII wrapper around raw BSTR. So feel free to use CComBSTR instead of raw BSTR to help writing code that is exception-safe, that makes it harder to leak resources (i.e. the raw BSTR), etc.

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

If the BSTR is an input parameter, it's just like a const wchar_t* (with length prefixed, and potentially some NULs L'' characters inside). If the BSTR doesn't have NULs embedded inside, you can simply pass it to a CString constructor, that will make a deep-copy of it, and you can locally work with your CString. Modifications to that CString won't be visible on the original BSTR. You can use std::wstring as well (and note that std::wstring can handle embedded NULs as well).

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

相反,如果 BSTR 是一个 输出 参数,那么它会使用另一个间接级别传递,即 BSTR*.在这种情况下,您可以在您的方法中使用 CComBSTR::Detach() 来释放安全包裹在 CComBSTR 中的 BSTR,并传输其调用者的所有权:

Instead, if the BSTR is an output parameter, then it is passed using another level of indirection, i.e. BSTR*. In this case, you can use CComBSTR::Detach() inside your method to release the BSTR safely wrapped into the CComBSTR, and transfer its ownership to the caller:

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(包装在像CComBSTR这样的RAII类中)在边界,并使用 std::wstringCString 完成本地工作.

Basically, the idea is to use BSTR (wrapped in a RAII class like CComBSTR) only at the boundary, and do the local work using std::wstring or CString.

作为有益的阅读",请考虑Eric Lippert 的 BSTR 语义指南.

As a "bouns reading", consider Eric Lippert's guide to BSTR semantics.

这篇关于我们应该将 COM 中的 BSTR 类型视为值还是引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆