2013-03-15 30 views
5

Từ sách Nội dung ATL, tôi biết BSTR khác với OLECHAR *, và có CComBSTR và CString cho BSTR.Chúng ta có nên xử lý loại BSTR trong COM dưới dạng giá trị hoặc tham chiếu không?

Theo MSDN Allocating and Releasing Memory for a BSTR, tôi biết trách nhiệm quản lý bộ nhớ đối với người gọi/callee.

Hãy dòng này từ MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

tôi vẫn không biết làm thế nào để xử lý bstr đúng trong việc thực hiện của tôi. Vì tôi vẫn có một câu hỏi cơ bản cho BSTR - chúng ta có nên coi bstr là một giá trị (như int) hay như một tham chiếu (như int *), ít nhất là trên ranh giới giao diện COM.

Tôi muốn chuyển đổi BSTR càng sớm càng tốt thành CString/CComBSTR trong quá trình triển khai. Giá trị hoặc ngữ nghĩa tham chiếu sẽ là trường hợp hoàn toàn khác cho chuyển đổi. Tôi đã đào vào CComBSTR.Attach, CComBSTR.AssignBSTR, vv Nhưng mã không thể giải quyết những nghi ngờ của tôi.

MSDN CComBSTR.Attach có một số mã snip, tôi cảm thấy nó sai vì nó không tuân theo Allocating and Releasing Memory for a BSTR. ATL Internals cho biết SetSysString sẽ 'giải phóng BSTR ban đầu được thông qua trong', nếu tôi sử dụng nó, nó sẽ vi phạm quy ước đối số BSTR, giống như CComBSTR.Attach. Tất cả trong tất cả, tôi muốn sử dụng CString để xử lý BSTR thô trong thực hiện, nhưng không biết chính xác cách ... Tôi đã viết một số mã chỉ trong các dự án của tôi, nhưng tôi luôn cảm thấy lo lắng vì tôi không Không biết tôi có đúng không.

Hãy để tôi nói chuyện với mã hóa ngôn ngữ

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

Trả lời

11

CComBSTR chỉ là một RAII wrapper xung quanh liệuBSTR. Vì vậy, cảm thấy tự do để sử dụng CComBSTR thay vì nguyên BSTR để giúp viết code đó là ngoại lệ an toàn, mà làm cho nó khó khăn hơn để rò rỉ nguồn lực (tức là BSTR thô) vv

Nếu BSTR là một đầu vào tham số, nó giống như một const wchar_t* (có độ dài được đặt trước và có khả năng một số ký tự NUL s L'\0' bên trong). Nếu số BSTR không được gắn bên trong, bạn chỉ cần chuyển nó vào một hàm tạo CString, sẽ tạo bản sao sâu của nó và bạn có thể làm việc cục bộ với CString của mình. Sửa đổi cho rằng CString sẽ không hiển thị trên BSTR gốc. Bạn cũng có thể sử dụng std :: wstring (và lưu ý rằng std::wstring cũng có thể xử lý nhúng NUL s).

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

Thay vào đó, nếu BSTR là kết quả tham số , sau đó nó được thông qua sử dụng một mức gián tiếp, ví dụ: BSTR*.Trong trường hợp này, bạn có thể sử dụng CComBSTR::Detach() bên trong phương pháp của bạn để giải phóng BSTR an toàn quấn vào CComBSTR, và chuyển quyền sở hữu của mình cho người gọi:

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

Về cơ bản, ý tưởng là sử dụng BSTR (bọc trong một lớp RAII giống như CComBSTR) chỉ tại ranh giới và thực hiện công việc địa phương bằng cách sử dụng std::wstring hoặc CString.

Khi "đọc danh từ", hãy xem xét Eric Lippert's guide to BSTR semantics.

+0

Câu hỏi lớn của tôi là chúng ta nên sao chép hoặc ref bstr? Qeustion nhỏ là làm thế nào để ref bstr với CString? làm thế nào để sao chép bstr với nhúng NULL? – Raymond

+0

Bạn có ý nghĩa gì với bản sao hoặc ref? Nếu đó là một tham số đầu vào vượt qua 'BSTR' theo giá trị, thì khác vượt qua" bằng con trỏ "' BSTR * '. Nếu bạn đã nhúng 'NUL', bạn có thể sao chép nó trong một 'std :: wstring', không phải trong' CString'. –

+0

Có thể bạn đang quan sát vấn đề từ một quan điểm sai ... Hãy suy nghĩ về một 'BSTR' giống như một' const wchar_t * 'được cấp phát với một trình cấp phát COM đặc biệt và có độ dài tiền tố (để nó có thể nhúng' NUL '). –

4

BSTR khi nhập, bạn không chịu trách nhiệm phát hành nó. Chuyển đổi sang CString là dễ dàng:

CString sValue(bstr);

hoặc, nếu bạn muốn giữ các ký tự Unicode trên MBCS xây dựng:

CStringW sValue(bstr);

Nếu bạn cần phải chuyển đổi trở lại khi bạn có [out] tham số, bạn do (phiên bản đơn giản):

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

Phiên bản đầy đủ là:

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; 
} 
Các vấn đề liên quan