BSTR使用注意事項

1.    BSTR使用注意事項

1.1    BSTR是什麼?
l    BSTR的定義
    typedef OLECHAR *BSTR;
    從定義看,BSTR實質就是一個指向字符串的指針,它指向字符串的首地址。在32位Windows系統中,BSTR指向的是以NULL爲結束的Unicode字符串。
l    BSTR的內存結構


        與一般的字符串不一樣的是,BSTR指向的字符串是帶前綴的,前綴是一個DWORD(32位)的內存空間,保存的是字符串的字節長度(注意,不是字符串的長度,並且不包括NULL結束符佔用的空間),這個長度值是利用BSTR專用的函數族分配空間的同時填寫的。

1.2    BSTR的特殊性
l    BSTR字符串可以內嵌零個或多個NULL,因爲決定其長度的不是NULL,而是其前綴保存的數值,所以不能以NULL來判斷字符串的結束。;
l    必須用SysAllocString()和SysFreeString()函數族來分配和釋放,用SysStringLen()等取得字符串的長度;

1.3    BSTR相關函數族
l    內存分配和重分配函數
SysAllocString
SysAllocStringLen
SysAllocStringByteLen
SysReAllocString
SysReAllocStringLen
注:通過以上函數分配空間的同時將根據字符串實際佔用的字節數填寫前綴

l    字符串釋放函數
SysFreeString
注:這個函數的參數可以傳入NULL,即在調用此函數時可以不用判斷參數是否爲NULL

l    字符串(佔用空間)長度函數
SysStringLen
SysStringByteLen

1.4    如何避免BSTR造成的內存泄漏
l    對於BSTR的管理(申請、釋放和計算長度)嚴格使用上述對應的函數族,不要使用new、delete、CoTaskMemAlloc、CoTaskMemFree、sizeof 等。
l    不要在BSTR字符串中嵌入NULL
l    定義BSTR時要賦初值NULL
BSTR bstr = NULL;
l    調用SysFreeString後要給bstr賦NULL
SysFreeString(bstr);
bstr = NULL;
l    不要給BSTR直接初始化字符串
BSTR bstr = L“kkkkkk”;  -à BSTR bstr = SysAllocString (L“kkkkkk”);

因爲直接初始化字符串時前綴的值可能是一個隨機數,這樣的話,其他地方使用這個BSTR時將無法決定出字符串的長度,特別在跨進程傳送數據時將會出現致命錯誤。
l    在給一個BSTR賦值前,如果不能確定它目前是否指向一個有效的空間,最好先調一下SysFreeString,如:
SysFreeString(bstr);
bstr = SysAllocString(L“kkkkkk”);
l    不要將一個BSTR通過“=”賦給另一個BSTR
bstr1 = bstr2  -à  bstr1 = SysAllocString(bstr2);
避免調用SysFreeString(bstr1)和SysFreeString(bstr2)對同一塊內存空間釋放兩次。
l    參數爲[out]的BSTR注意點
比如函數GetBSTR([out] BSTR* bstr)
1、    對於客戶端
BSTR bstr = NULL;// 傳入的bstr必須爲NULL
GetBSTR(&bstr);
。。。。。。
SysFreeString(bstr);// 使用完bstr後別忘了釋放
bstr = NULL;
2、    對於服務端
HRESULT GetBSTR(BSTR* bstr)
{
// 一般來說,傳入的bstr不指向任何空間應該由客戶端保證的,所以下面的判斷和釋放不是必須的,但有的話可能更安全。
    if ( NULL != *bstr )
            SysFreeString(*bstr); 

        // 創建成員變量的拷貝,不要將其值直接給出去(特別對於進程內組件)
                *bstr = m_bstr;  -à *bstr = SysAllocString( m_str );
}
l    參數爲[in]的BSTR注意點
            HRESULT SetBSTR(/*[in]*/  BSTR bstr){
// 如果服務器需要保存傳入的bstr供以後使用,必須將成員變量釋放,然後重新分配。
                    SysFreeString(m_bstr);
m_bstr = bstr; -à m_bstr = SysAllocString( bstr );
}

l    參數爲[out]的數據結構中包含BSTR的注意點
typedef struct kk{
long i;
BSTR bstr;
} KK;

KK param;
param.bstr = NULL;
GetKK(&param);
。。。。。。
SysFreeString(param .bstr);// 這種內嵌在結構體內的BSTR非常容易忽略釋放
param .bstr = NULL;
l    BSTR作爲SysAllocString或SysReAllocString的參數時的注意點
如果bstr作爲SysAllocString或SysReAllocString的參數傳入,並且不確定這個傳入的bstr是否包含內嵌NULL時,爲保險起見,請務必改用下面兩函數。
SysAllocStringLen
SysReAllocStringLen
原因:因爲上述4個函數的參數類型都是OLECHAR FAR* 而不是BSTR,但後兩個函數多了傳入數量的參數。

1.5    BSTR的ATL封裝類CCOMBSTR
建議:必須在非常清楚CComBSTR各個函數(特別是賦值操作符和構造函數)如何使用和注意事項的情況下才使用它,否則建議使用BSTR,因爲使用不慎非常容易造成內存泄漏。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章