2013-03-15 4 views
5

Von Buch ATL Internals wusste ich, dass BSTR unterscheidet sich von OLECHAR *, und es gibt CComBSTR und CString für BSTR.Sollen wir BSTR-Typ in COM als Wert oder Referenz behandeln?

Nach MSDN Allocating and Releasing Memory for a BSTR wusste ich Speicherverwaltung Verantwortung für Anrufer/Angerufener.

Nehmen Sie diese Linie von MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

Ich weiß noch nicht, wie bstr richtig in meiner Implementierung zu behandeln. Da ich noch eine grundlegende Frage für BSTR habe - sollten wir bstr als Wert behandeln (wie int) oder als Referenz (wie int *), zumindest auf der COM-Schnittstellengrenze.

Ich möchte BSTR so schnell wie möglich zu CString/CComBSTR in meiner Implementierung konvertieren. Die Wert- oder Referenzsemantik wird für die Konvertierung völlig unterschiedlich sein. Ich habe in CComBSTR.Attach, CComBSTR.AssignBSTR usw. gegraben. Aber der Code kann meine Zweifel nicht lösen.

MSDN CComBSTR.Attach hat einige Code-Schnipsel, ich denke, es ist falsch, da es nicht gehorcht Allocating and Releasing Memory for a BSTR. ATL Internals sagte, dass SetSysString "den ursprünglichen BSTR freigibt", wenn ich es benutze, wird es die BSTR-Argumentkonvention genau wie CComBSTR.Attach verletzen.

Alles in allem möchte ich CString verwenden, um rohe BSTR in der Implementierung zu handhaben, aber nicht den richtigen Weg ... Ich habe gerade Arbeitscode in meinen Projekten geschrieben, aber ich fühle mich immer nervös, seit ich nicht mehr Ich weiß nicht, ob ich Recht habe.

mir reden lassen Sprache Codierung

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

Antwort

11

CComBSTR ist nur ein RAII wrapper um rohBSTR. So fühlen sich frei CComBSTR statt roh BSTR zu verwenden das Schreiben von Code zu helfen, die Ausnahme-sicher ist, dass es schwieriger macht Ressourcen zu Leck (dh dem Rohstoff BSTR) usw.

Wenn die BSTR ist ein Eingang Parameter, Es ist genau wie ein const wchar_t* (mit der Länge vorangestellt und möglicherweise einige NUL s L'\0' Zeichen innen). Wenn die BSTR nicht innerhalb NUL s eingebettet ist, können Sie es einfach an einen CString Konstruktor übergeben, der eine Deep-Kopie davon macht, und Sie können lokal mit Ihrer CString arbeiten. Änderungen an diesem CString sind auf dem Original BSTR nicht sichtbar. Sie können auch std :: wstring verwenden (und beachten Sie, dass std::wstring auch eingebettete NUL s verarbeiten kann).

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

Stattdessen, wenn die BSTR ein Ausgang Parameter, dann wird sie unter Verwendung eines anderen Dereferenzierungsebene geleitet, d.h. BSTR*.In diesem Fall können Sie CComBSTR::Detach() in Ihrer Methode verwenden, um die BSTR sicher in die CComBSTR gewickelt zu lösen, und übertragen das Eigentum an den Anrufer:

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

Grundsätzlich ist die Idee in einer RAII Klasse BSTR (gewickelt zu verwenden wie) nur an der Grenze, und tun Sie die lokale Arbeit mit std::wstring oder CString.

als "bouns Lesen", warum Eric Lippert's guide to BSTR semantics.

+0

Meine große Frage ist, sollten wir kopieren oder ref bstr? Kleine Frage ist, wie man bstr mit CString referenziert? Wie kopiert man bstr mit eingebettetem NULL? – Raymond

+0

Was meinst du mit Kopie oder Ref? Wenn es eine Eingabe param Pass 'BSTR' nach Wert, sonst pass "durch den Zeiger"' BSTR * '. Wenn Sie eingebettet haben 'NUL's können Sie es in einem' std :: wstring' kopieren, nicht in einem 'CString'. –

+0

Vielleicht beobachten Sie das Problem aus einer falschen Sicht ... Denken Sie an eine 'BSTR' wie ein' const wchar_t * 'mit einem speziellen COM allocator zugeordnet und längen Präfix (so kann es eingebettet haben' NUL's). –

4

BSTR auf Eingang, sind Sie nicht verantwortlich, es zu veröffentlichen. Konvertieren in CString ist einfach:

CString sValue(bstr);

oder, wenn Sie es vorziehen, Unicode-Zeichen auf MBCS zu halten bauen:

CStringW sValue(bstr);

Wenn Sie konvertieren wieder benötigen, wenn Sie [out] Parameter haben, können Sie tun (einfache Version):

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

Vollversion ist:

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; 
} 
Verwandte Themen