BSTR詳解一 -BSTR簡介和內部結構

1         Why need BSTR
COM是一種跨編程語言的平臺,須要提供語言無關的數據類型。多數編程語言有本身的字符串表示。
  • C++ 字符串是以0結束的ASCIIUnicode字符數組
  • Visual Basic字符串是一個ASCII字符數組加上表示長度的前綴。
  • Java字符串是以0結束的Unicode字符數組。
須要定義一種通用的字符串類型,能夠很容易的匹配到不一樣編程語言。C++中,就是BSTR
2         What is BSTR
2.1      BSTR 簡介
"Basic STRing"的簡稱,微軟在COM/OLE中定義的標準字符串數據類型。對於C++Windows頭文件wtypes.h中定義以下:
typedef wchar_t WCHAR;
typedef WCHAR OLECHAR;
typedef OLECHAR __RPC_FAR *BSTR;;
2.2      BSTR實現
COM中,字符用16-bit OLECHAR表示,這樣使COM能夠支持各類code pages,包括Unicode。對於windows系統,能夠簡單理解爲OLECHAR使用的就是Unicode OLECHAR串與單字節字符串很相似,是一個以null結尾的buffer。惟一的區別是每一個字符佔兩個字節,而不是一個
 
 0 1 2 3 4 5 6 7 8 9 0 1
| H | E | L | L | O | \0|
 ^
 OLCHAR
 
 
Figure 1. Format of an OLECHAR string.
 
使用以Null結尾的簡單字符串在COM component間傳遞不太方便。所以,標準BSTR是一個有長度前綴和null結束符的OLECHAR數組。BSTR的前4字節是一個表示字符串長度的前綴。BSTR長度域的值是字符串的字節數,而且不包括0結束符。因爲是Unicode串,因此字符數是字節數的一半。這種方式的優勢是容許程序員在BSTR串中間嵌入NULL字符。可是,BSTR的前四個字節表示長度,而OLECHAR數組的前四字節表示前兩個字符。這種狀況下,對於C++程序,如何實現BSTROLECHAR的交換?答案是COM提供了兩個BSTR分配用的APISysAllocString / SysReallocString。函數返回的指針指向BSTR的第一個字符,而不是BSTR在內存的第一個字節。
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0a000000 | H | E | L | L | O | \0|
                ^
              BSTR
 
Figure 2.  Format of a BSTR.
 
下面是SysAllocStringSysFreeString的僞代碼。
 
BSTR SimpleSysAllocString( const OLECHAR * sz)
{
    if ( sz == NULL) return NULL;
   
    BYTE* buf = new BYTE[sizeof(INT32) + (wcslen(sz)+1)*sizeof(OLECHAR) ];
   
    if(buf == NULL)
    {
        return NULL;
    }
    else
    {
        INT32 len = wcslen(sz) * sizeof(OLECHAR);
        *((INT32*) buf) = len;
        wcscpy( (WCHAR*)(buf+sizeof(INT32)), sz);
        return (BSTR)(buf+sizeof(INT32));
    }
}
 
 
VOID SimpleSysFreeString( BSTR bstr)
{
    if(bstr != NULL)
    {
       BYTE* start = (BYTE*)bstr - sizeof(INT32);
       delete []start;
    }
}
3         When to use BSTR
只有在你不得不用的時候。
 
使用BSTR通常有如下幾種狀況:
  • COM interface接口定義,而且不但願額外提供custom marshaling庫(MDIL生成或開發人員本身訂製),必須使用BSTR傳遞字符串。使用C/C++類型的字符串在COM DLL傳遞字符串,表面上可使用,但違背了COM的基本規則,而且給之後的擴展留下了隱患。例如,把一個In-process COM Object(簡單說COM DLL)改爲out-of-process objectCOM EXE)。理論上,客戶端的代碼應該不作任何改變。但若是是用了C/C++字符串,又但願只使用系統的automation mashallerOleaut32.dll),就會出錯。
  • 若是能夠提供custom marshaling,也推薦使用BSTR
  • 客戶要求接口必須使用BSTR,和客戶討論後,不能修改。
  • 使用的外部庫的接口使用BSTR
 
不使用的狀況:
  • 不推薦在IDL結構體中定義BSTR成員,會給結構體的複製和釋放帶來麻煩。最好直接使用限定最大長度的TCHAR數組。若是確實須要傳遞變長字符串,BSTR應該被定義成獨立的參數或者使用獨立的get/set接口。
  • 儘量縮小的BSTR及相關類型的做用域範圍。類的成員變量和函數參數不使用BSTR。局部變量要儘快釋放類的內部不使用BSTR。代碼處理邏輯中只在接口直接相關部分使用BSTR。接收到一個BSTR時,儘可能馬上變成C/C++的字符串副本進行處理。在須要傳遞BSTR參數前產生BSTR,用過當即釋放。
 
字符串相關類型的推薦選擇順序
優先級
類型
說明
最高
stl::string/wstring
·         功能最完善,可移植性最好。
 
CString
·         若是編碼規範限制使用STL的時候,推薦CString
·         VC 6的版本很不完善。.Net有明顯改進,須要進一步研究。
 
C/C++ basic typeTCHAR* / char* / LPTSTR / LPCTSTR / TCHAR[]
·         在結構體中,優先使用指定最大長度的字符數組。
·         效率最好
 
CComBSTR/ _bstr_t
·         在必須使用BSTR時的優先選擇。
·         ATLCOM component)工程或者工程中必須使用ATL中,優先選擇CComBSTR。通常Exe/dll若是_bstr_t能知足要求,優先使用_bstr_t
·         對於VC6,使用_bstr_t必定要慎重,最好只用做簡單臨時變量保存調被調用函數的傳入參數。由於_bstrt_t不能支持一些關鍵性操做,好比Detach
·         對於VC++ .Net推薦使用_bstr_t,它是C++擴展,不須要額外包含ATL的文件。
最低
BSTR
·         CO
相關文章
相關標籤/搜索