5

ATLIternalsから、BSTRはOLECHAR *とは異なり、BSTRにはCComBSTRとCStringがあることがわかりました。

BSTRのメモリの割り当てと解放のMSDNによると、呼び出し元/呼び出し先のメモリ管理の責任を知っていました。

MSDNからこの行を取得します。

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

私はまだbstr私の実装で適切に処理する方法を知りません。BSTRについてはまだ基本的な質問があるのでbstr、少なくともCOMインターフェイスの境界では、値(intなど)または参照(int *など)として扱う必要があります。

実装でBSTRをできるだけ早くCString/CComBSTRに変換したいと思います。値または参照セマンティクスは、変換の場合とはまったく異なります。私はCComBSTR.Attach、CComBSTR.AssignBSTRなどを掘り下げました。しかし、コードは私の疑問を解決することはできません。

MSDN CComBSTR.Attachにはコードの一部がありますが、BSTRのメモリの割り当てと解放に従わないため、間違っていると思います。ATL Internalsによると、SetSysStringは「渡された元のBSTRを解放します」。これを使用すると、CComBSTR.Attachと同様に、BSTR引数の規則に違反します。

全体として、実装で生のBSTRを処理するためにCStringを使用したいのですが、正しい方法がわかりません...プロジェクトでいくつかの作業コードを記述しましたが、私は正しいです。

コーディング言語について話させてください

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 ???
}
4

2 に答える 2

12

CComBSTRrawの単なるRAII ラッパーです。そのため、raw の代わりに自由に使用して、例外に対して安全なコードを記述したり、リソース (つまり raw BSTR) をリークしにくくしたりできます。 BSTRCComBSTRBSTR

BSTR入力パラメーターである場合は、 const wchar_t*(長さが前に付けられ、内部にNULs文字が含まれる可能性がある) と同じです。にs が埋め込まれていないL'\0'場合は、コンストラクターに渡すだけで、そのディープ コピーが作成され、ローカルで. これに対する変更は、元の では表示されません。std::wstring も使用できます (埋め込みs も処理できることに注意してください)。BSTRNULCStringCStringCStringBSTRstd::wstringNUL

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

代わりに、 が出力パラメータである場合BSTRは、のレベルの間接化を使用して渡されますBSTR*。この場合、メソッド内で を使用して安全にラップされたCComBSTR::Detach()を解放し、その所有権を呼び出し元に転送できます。BSTRCComBSTR

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)を使用し、 またはを使用してローカル作業を行うという考え方です。std::wstringCString

「お楽しみ」として、Eric Lippert の BSTR セマンティクスのガイド を検討してください。

于 2013-03-15T20:23:21.177 に答える
4

入力があるので、それをBSTRリリースする責任はありません。への変換CStringは簡単です:

CString sValue(bstr);

または、MBCS ビルドで Unicode 文字を維持したい場合:

CStringW sValue(bstr);

パラメータがあるときに元に戻す必要がある場合は[out]、次のようにします (単純なバージョン)。

VOID Foo(/*[out]*/ BSTR* psValue)
{
  CString sValue;
  *psValue = CComBSTR(sValue).Detach();
}

フルバージョンは:

STDMETHODIMP Foo(/*[out]*/ BSTR* psValue)
{
    _ATLTRY
    {
        ATLENSURE_THROW(psValue, E_POINTER); // Parameter validation
        *psValue = NULL; // We're responsible to initialize this no matter what
        CString sValue;
        // Doing our stuff to get the string value into variable
        *psValue = CComBSTR(sValue).Detach();
    }
    _ATLCATCH(Exception)
    {
        return Exception;
    }
    return S_OK;
}
于 2013-03-15T20:24:24.937 に答える