2011-03-10 62 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