2011-03-10 65 views
9

將LPTSTR直接投射到BSTR是合法的嗎?你可以將LPTSTR投射到BSTR嗎?

根據我的understanding of BSTR,將LPTSTR直接投射到BSTR會給您帶來長度損壞的前綴。示例代碼明確指出,字符串文字不能存儲到BSTR。任何人都可以確認我LPTSTR/LPCTSTR不能直接轉換到BSTR而不會破壞長度前綴嗎?

編輯:

我的困惑是看不到這對COM對象的調用使用。事實證明,編譯COM DLL時,會生成一個.tli文件,它會創建一箇中間方法。該方法採用類型_bstr_t_bstr_t可以在其構造函數中使用LPTSTR,所以一切正常。

回答

8

如果你的程序是unicode的,因此您的LPTSTRLPWSTR,您可以使用SysAllocString從一個指針轉換爲寬字符字符串BSTR

直接投射是不可能的,因爲兩者具有不同的存儲器表示。

如果您使用C++,則可以使用_bstr_t類來簡化BSTR字符串的使用。

1

它不可能是因爲然後LPTSTR之前的內存中的四個字節將被視爲結果BSTR的長度。這可能會導致內存保護錯誤(不太可能),但肯定會導致BSTR的長度可能比原始的LPTSTR長。所以當有人試圖讀取或寫入時,他們可能會訪問無效的內存。

+3

字符串數據不會被解釋爲長度。緊接着的字節將是。 BSTR指向長度+字符串結構的字符串部分。 – 2011-03-10 15:30:53

+0

@本:謝謝你的澄清,我不知道。我會相應地修改答案。 – Jon 2011-03-10 15:33:28

0

不,你不能直接施放它們。但是,您可以創建一個既能執行這兩個操作的字符 C字符串沒有4個字節的標題。但是,中間的位是相同的,所以如果你發現自己需要兩種表示方式,則創建一個包裝類,它構造一個帶有4字節頭和空終止符的字符串,但可以將訪問者返回給BSTR部分和C字符串。

此代碼旨在作爲一個不完整的例子,我沒有編譯過!

class YetAnotherStringType //just what the world needs 
{ 
    public: 
    YetAnotherStringType(const char *str) 
    { 
    size_t slen = strlen(str); 
    allocate(slen); 
    set_size_dword(slen); 
    copy_cstr(str, slen);  
    } 

    const char *get_cstr() const 
    { 
    return &m_data[4]; 
    } 

    const BSTR get_bstr() const 
    { 
    return (BSTR*)m_data; 
    } 

    void copy_cstr(const char *cstr, int size = -1) 
    { 
     if (size == -1) 
     size = strlen(cstr); 
     memcpy(&m_data[4], cstr, size + 1); //also copies first null terminator 
     m_data[5 + size] = 0; //add the second null terminator 
    } 

    void set_size_dword(size_t size) 
    { 
    *((unsigned int*)m_data) = size; 
    } 

    void allocate(size_t size) 
    { 
    m_data = new char[size + 6]; //enough for double terminator 
    } 

    char *m_data; 
}; 
+0

'BSTR'有一個雙空終止符。 – Jon 2011-03-10 15:04:52

+0

@Jon:啊,對不起。我在這裏閱讀了這個網頁,並且讀到他們沒有 - 我誤解了它。他們似乎在說,標題不包含空終止符(!?) – Luther 2011-03-10 15:16:58

+0

已經有一個字符串可以同時執行:'_bstr_t'來自'' – 2011-03-10 15:45:13

1

甲LPTSTR是一個指向字符數組(或TCHAR是精確的) BSTR是structur(或複合數據)由 *長度前綴 *數據串 *終結者

所以鑄造行不通

0

不,你不能 - 如果相信它的代碼是BSTR調用SysStringLen()它會遇到未定義的行爲,因爲該函數依賴於某些實現特定的服務數據。

0

你不能投,你必須轉換。您可以使用內置編譯器固有的_bstr_t(來自comutil.h)來幫助您輕鬆完成此操作。示例:

#include <Windows.h> 
#include <comutil.h> 

#pragma comment(lib, "comsuppwd.lib") 

int main() 
{ 
    LPTSTR p = "Hello, String"; 
    _bstr_t bt = p; 
    BSTR bstr = bt; 
    bstr; 
} 
+0

@John Dibling:嗨。我給的例子不起作用嗎?如果不是,你能解釋一下爲什麼要這樣嗎 – Luther 2011-03-10 15:27:20

+1

@路德:有兩件事。 1)爲什麼當MS已經提供了一個類來爲你做這件事(_bstr_t)時寫一堆代碼? 2)你寫的代碼可能工作也可能不工作;我不確定。你應該調用'SysAllocString'來創建一個BSTR,但是你試圖使用你自己構建一個BSTR的內部工作的知識。此外,BSTR的字符串部分是Unicode。你的,我認爲,不是。 – 2011-03-10 15:41:10

+0

@John Dibling:謝謝你的迴應。我沒有試圖重新發明輪子,代碼只是爲了說明一個觀點。我們這裏的人在詢問有關鑄造,而不是構建和複製BSTR。他可能有充足的理由來施放而不是重建(緊張的內存需求,內部循環中的很多調用,不想碰堆等等),而我在那裏繪製的類應該達到這個目的。如果BSTR是UniCode,那麼用wchar_t *替換char *。有時候最好自己寫一些代碼,如果標準方式不按照你喜歡的方式完成工作。 – Luther 2011-03-10 16:15:30

0

一般來說不是,但有一些方法可以使它們在某種程度上通過助手類和宏(參見下文)兼容。

的主要原因是1:1映射將永遠不可能是一個BSTR(因此CComBSTR可以包含在字符串中'\0',因爲最終它是一個計數的字符串類型


你最好的。選擇用C++時會去的ATL類CComBSTR代替BSTR適當的。在這兩種情況下,你可以使用ATL的/ MFC轉換宏CW2A和朋友。

還要注意的是,文件(MSDN)說: :

轉換爲 和BSTR串的推薦方法是使用 CComBSTR類。轉換爲BSTR, 將現有字符串傳遞給CComBSTR的 構造函數。要從BSTR轉換 ,請使用 COLE2 [C] DestinationType [EX],例如 COLE2T

...它適用於您的用例。

請參閱John Dibling的替代答案(_bstr_t)。

4

如果你試圖傳遞LPCTSTR S作爲BSTR是你會發現,你會隨機炸燬你附近的任何互操作編組代碼。編組將拉出一個LPCTSTR的4字節前綴(這是隨機數據),然後嘗試並馬歇爾字符串。

你會發現4字節前綴是緩衝區之前的堆棧內容,或者是來自之前字符串的更好的字符數據。然後您將嘗試以兆字節爲單位的數據... :-)

使用CComBSTR包裝並使用.Detach()如果您需要保留BSTR指針。

如果編譯器在這一個上吐出一個警告,那就好了。

+0

剛剛被這個咬傷,將三個L「我的字符串」參數傳遞給一個.Net COM方法,期望3個BSTR,並且只有一個在互操作編組中存活。沒有來自編譯器的警告VS2008/W4 – Lallen 2016-06-20 12:06:39

+0

4字節前綴表示BSTR的長度。 – lsalamon 2016-11-16 10:32:44