2013-03-15 6 views
5

Z książki ATL Internals, wiedziałem, że BSTR różni się od OLECHAR *, i są CComBSTR i CString dla BSTR.Czy mamy traktować typ BSTR w COM jako wartość lub referencję?

Według MSDN Allocating and Releasing Memory for a BSTR, znałem odpowiedzialność za zarządzanie pamięcią dla osoby dzwoniącej/osoby odwiedzającej.

Weź tę linię z MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

ja nadal nie wiem, jak obsługiwać bstr właściwie w moim realizacji. Ponieważ nadal mam podstawowe pytanie do BSTR-a - powinniśmy traktować bstr jako wartość (jak int) lub jako odniesienie (jak int *), przynajmniej na granicy interfejsu COM.

Chcę przekonwertować BSTR jak najszybciej do CString/CComBSTR w mojej implementacji. Wartość lub odniesienie semantyczne będą zupełnie inne dla konwersji. Wkopałem się w CComBSTR.Attach, CComBSTR.AssignBSTR itd. Ale kod nie rozwiąże moich wątpliwości.

MSDN CComBSTR.Attach ma wycinek kodu, czuję, że jest źle, ponieważ nie jest on zgodny z Allocating and Releasing Memory for a BSTR. ATL Internals powiedział, że SetSysString "zwolni oryginalny BST przekazany w", jeśli użyłbym go, naruszy to konwencję BSTR, podobnie jak CComBSTR.Attach.

Podsumowując, chcę używać CString do obsługi surowego BSTR w implementacji, ale nie znam prawidłowej metody ... Napisałem trochę kodu do moich projektów, ale zawsze czuję się zdenerwowany, odkąd nie wiem, czy mam rację.

Pozwól mi mówić kodowania językowi

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

Odpowiedz

11

CComBSTR tylko RAII wrapper wokół surowyBSTR. Dlatego zachęcamy do korzystania CComBSTR zamiast surowego BSTR pomóc pisanie kodu, który jest bezpieczny dla wyjątek, który sprawia, że ​​coraz trudniej jest wyciek zasobów (czyli surowego BSTR) itd

Jeśli BSTR jest wejście parametr, to tak jak const wchar_t* (z prefiksem długości i potencjalnie niektórymi znakami NUL s wewnątrz). Jeśli BSTR nie ma osadzonych wewnątrz, można go po prostu przekazać do konstruktora CString, który wykona jego głęboką kopię i będzie można lokalnie współpracować z urządzeniem CString. Modyfikacje tego CString nie będą widoczne na oryginalnym BSTR. Możesz również użyć std :: wstring (i pamiętaj, że std::wstring może obsłużyć także osadzone NUL s).

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

Natomiast, jeśli BSTR jest wyjście parametr , a następnie jest przekazywany za pomocą innego poziom pośredni, to znaczy BSTR*.W tym przypadku można użyć CComBSTR::Detach() wewnątrz metody, aby zwolnić BSTR bezpiecznie owinięte w CComBSTR i przenieść jej własność do rozmówcy:

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

Zasadniczo pomysł jest użycie BSTR (zawinięte w klasie RAII jak CComBSTR) tylko na granicy i wykonaj lokalne prace za pomocą std::wstring lub CString.

Jako "czytanie bouns", rozważ Eric Lippert's guide to BSTR semantics.

+0

Moje pytanie brzmi: Czy powinniśmy skopiować lub odesłać bstr? Małe qeustion jest jak ref Bstr z CString? jak skopiować bstr z wbudowanym NULL? – Raymond

+0

Co masz na myśli z kopią lub ref? Jeśli jest to parametr wejściowy, parametr "BSTR" przez wartość, inny przekaz "przez wskaźnik" 'BSTR *'. Jeśli masz wbudowane 'NUL's, możesz skopiować go w' std :: wstring', a nie w 'CString'. –

+0

Może obserwujesz problem z niewłaściwego punktu widzenia ... Pomyśl o 'BSTR' jak' const wchar_t * 'przydzielonym ze specjalnym przydziałem COM i prefiksem długości (aby mógł on zawierać' NUL's). –

4

Po wprowadzeniu BSTR na wejściu użytkownik nie ponosi odpowiedzialności za jego zwolnienie. Konwersja do CString jest proste:

CString sValue(bstr);

lub, jeśli wolisz zachować znaki Unicode na MBCS budować:

CStringW sValue(bstr);

Jeśli trzeba przekonwertować z powrotem, gdy masz [out] parametru, do (wersja prosta):

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

Pełna wersja to:

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; 
} 
Powiązane problemy