可以将 LPTSTR 转换为 BSTR 吗?

发布于 2024-10-21 06:21:36 字数 436 浏览 1 评论 0原文

将 LPTSTR 直接转换为 BSTR 是否合法?

根据我对 BSTR 的理解,直接将 LPTSTR 转换为 BSTR 将给你留下一个损坏的长度前缀。示例代码明确指出字符串文字不能存储到 BSTR。任何人都可以帮我确认 LPTSTR/LPCTSTR 不能直接转换为 BSTR 而不破坏长度前缀吗?

编辑:

我的困惑是因为看到它在对 COM 对象的调用中使用。事实证明,在编译 COM dll 时,会生成一个 .tli 文件,该文件创建了一个中间方法。此方法采用 _bstr_t 类型。 _bstr_t 可以在其构造函数中使用 LPTSTR,因此一切都会顺利进行。

Is it legal to cast a LPTSTR directly to a BSTR?

Based on my understanding of BSTR, casting a LPTSTR to a BSTR directly will leave you with a corrupted length prefix. The example code explicitly states that a string literal cannot be stored to a BSTR. Can anyone confirm for me that a LPTSTR/LPCTSTR cannot be cast directly to a BSTR without corrupting the length prefix?

EDIT:

My confusion is from seeing this used in a call to a COM object. It turns out that when compiling the COM dll, a .tli file is generated that creates an intermediate method. This method takes type _bstr_t. The _bstr_t can take LPTSTR in its constructor, so everything works smoothly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

一世旳自豪 2024-10-28 06:21:36

如果您的程序是 unicode 并且您的 LPTSTR 因此是 LPWSTR,则可以使用 SysAllocString 将宽字符串指针转换为 BSTR

直接转换是不可能的,因为两者具有不同的内存表示形式。

如果您使用 C++,则可以使用 _bstr_t< /a> 类来简化 BSTR 字符串的使用。

If your program is unicode and your LPTSTR therefore is a LPWSTR, you can use SysAllocString to convert from a pointer to a wide character string to BSTR.

A direct cast is not possible because the two have different memory representations.

If you use C++, you can use the _bstr_t class to simplify the usage of BSTR strings.

假情假意假温柔 2024-10-28 06:21:36

如果您尝试将 LPCTSTR 作为 BSTR 传递,您会发现您将随机破坏您接近的任何互操作编组代码。编组将提取 LPCTSTR 的 4 字节前缀(这是随机数据),并尝试对字符串进行编组。

您会发现 4 字节前缀实际上是缓冲区之前的堆栈内容,甚至是之前字符串中的更好的字符数据。然后,您将尝试编组兆字节的数据...:-)

使用 CComBSTR 包装器,如果需要保留 BSTR<,请使用 .Detach() /代码> 指针。

如果编译器对此发出警告,那就太好了。

If you are trying to pass LPCTSTRs as BSTRs you will find that you will randomly blow up any interop marshalling code you get near. The marshalling will pull the 4 byte prefix (which is random data) for an LPCTSTR and try and Marshall the string.

You will find that the 4 byte prefix turns out to be the stack contents prior to your buffer, or even better character data from the string before it. You will then try to marshall megabytes of data... :-)

use the CComBSTR wrappers and use .Detach() if you need to keep the BSTR pointer.

Be nice if the compiler spat out a warning on this one.

北风几吹夏 2024-10-28 06:21:36

LPTSTR 是指向 char 数组(或者准确地说是 TCHAR)的指针
BSTR 是一个结构(或复合数据),包括
* 长度前缀
* 数据字符串
* 终结者

所以铸造将不起作用

A LPTSTR is a pointer to a char array (or TCHAR to be exact)
BSTR is a structur (or composite data) consist of
* Length prefix
* Data string
* Terminator

so casting will not work

樱花落人离去 2024-10-28 06:21:36

No, you cannot - if the code that believes it is a BSTR calls SysStringLen() it will run into undefined behavior since that function relies on some implementation-specific service data.

白色秋天 2024-10-28 06:21:36

不可能,因为这样的话,LPTSTR 之前的内存中的四个字节将被视为结果 BSTR 的长度。这可能会当场导致内存保护故障(不太可能),但肯定会导致 BSTR 的长度可能比原始 LPTSTR< 的长度大得多。 /代码>。因此,当有人尝试从中读取或写入时,他们可能会访问无效内存。

It cannot be, because then the four bytes in memory preceding the LPTSTR would be considered as the length of the resulting BSTR. This might cause a memory protection fault on the spot (not very likely), but it would certainly result in a BSTR with a length that could be way larger than the length of the original LPTSTR. So when someone tries to read or write from that they may access invalid memory.

若能看破又如何 2024-10-28 06:21:36

你不能施放,你必须转换。您可以使用内置编译器内部_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;
}

You cannot cast, you must convert. You can use the built-in compiler intrinsic _bstr_t (from comutil.h) to help you do this easily. Sample:

#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;
}
不爱素颜 2024-10-28 06:21:36

不,你不能直接施放它们。但是,您可以创建一个同时执行这两种操作的字符串。
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;
};

No, you cannot cast them directly. However, you can make a string that does both.
A C-String doesn't have a 4-byte header. However, the bit in the middle is the same so if you find yourself needing both representations, make a wrapper class that constructs a string with a 4byte header and a null terminator but can return accessors to the BSTR portion and the C-String.

This code is intended as an incomplete example, I haven't compiled this!

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;
};
说好的呢 2024-10-28 06:21:36

一般来说不会,但是有一些方法可以通过辅助类和宏使它们在某种程度上兼容(见下文)。

1:1 映射永远不可能的主要原因是 BSTR(因此 CComBSTR 可以在字符串,因为最终它是一个计数字符串类型。


在使用 C++ 时,您的最佳选择是使用 ATL 类 CComBSTR 来代替 BSTR 。可以使用 ATL/MFC 转换宏 CW2A 和朋友

还要注意文档(MSDN)说:

推荐的转换方式
并从 BSTR 字符串中使用
CComBSTR 类。要转换为 BSTR
将现有字符串传递给
CComBSTR 的构造函数。转换
从 BSTR 中,使用
COLE2[C]DestinationType[EX],例如
COLE2T

...这适用于您的用例。

请参阅 John Dibling 的答案以获取替代方案 (_bstr_t)。

Generally speaking no, but there are ways to make them compatible to some extent via helper classes and macros (see below).

The main reason why a 1:1 mapping will never be possible is that a BSTR (and consequently CComBSTR can contain '\0' in the string, because ultimately it is a counted string type.


Your best choice when using C++ would be to go for the ATL class CComBSTR in place of BSTR proper. In either case you can make use of the ATL/MFC conversion macros CW2A and friends.

Also note that the documentation (MSDN) says:

The recommended way of converting to
and from BSTR strings is to use the
CComBSTR class. To convert to a BSTR,
pass the existing string to the
constructor of CComBSTR. To convert
from a BSTR, use
COLE2[C]DestinationType[EX], such as
COLE2T.

... which applies to your use case.

Please see John Dibling's answer for an alternative (_bstr_t).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文