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

查看:191
本文介绍了我们将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分配和释放内存< a>,我知道调用者/被调用者的内存管理责任。

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

从MSDN获取此行,

code> HRESULT CMyWebBrowser :: put_StatusText(BSTR bstr)

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 / strong>参数,它就像一个 const wchar_t * (带长度前缀,可能有一些 NUL s L'\0'字符里面)。如果 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'\0' 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
}

$ b $相反,如果 BSTR 输出参数,则使用另一级别的间接传递,即 BSTR * 。在这种情况下,您可以使用 CComBSTR :: Detach()在您的方法中释放 BSTR CComBSTR ,并将其所有权转让给调用者:

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类中 em> ,并使用 std :: wstring CString 进行本地工作。

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.

作为bouns reading,请考虑

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

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

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