【问题标题】:_bstr_r vs _T("")_bstr_r 与 _T("")
【发布时间】:2014-09-22 13:32:25
【问题描述】:

我有一个注册为 COM 对象的 .net 库,当在 C++ 项目中导入 .tlb 文件时,我得到了这样的方法声明

  virtual HRESULT __stdcall GetBid (
    /*[in]*/ BSTR symbol,
    /*[out,retval]*/ double * pRetVal ) = 0;

对于 .NET 等效项

double GetBid(string symbol);

现在我试着这样称呼它

double bid;
ptr->GetBid(_T("AAPL"), &bid);

这不能按预期工作,因为在 .NET 端,字符串参数实际上是一个空字符串。

如果我换成这样的电话

double bid;
ptr->GetBid(_bstr_t("AAPL"), &bid);

一切都按预期进行。

为什么两个调用都编译得很好,但结果却不同?不应该将第一次调用转换为正确的字符串编组吗?

感谢任何有关 BSTR 魔法的幕后信息 :)

【问题讨论】:

  • 简单地说,wchar* C 字符串不是BSTR
  • 是的,但是当我传递给 BSTR 参数时,它不是由隐式运算符转换的。

标签: c# c++ com com-interop


【解决方案1】:

BSTR 有一个 32 位长度字符串之前。因此,BSTR 可以包含嵌入的空值。

_T("AAPL") 创建一个 wchar_t *,其结尾为 null,但没有长度前缀。

不过,在底层,两者都是 wchar_t *,所以调用可以编译并且不需要转换。你有点幸运,因为可能会发生比在另一边没有绳子更糟糕的事情。封送拆收器可能会查看 _T("AAPL") 倒数 32 位,并且碰巧得到一个很长的长度值,这很糟糕。 :-)

如果参数定义为 _bstr_t,您将获得自动转换,因为这会调用 _bstr_t(wchar_t *) 构造函数。

【讨论】:

  • 我想知道为什么Visual Studio在从.tlb生成头文件时不使用_bstr_t并使用BSTR?
  • 可以,但这取决于您在#import 语句中添加的内容。你使用 raw_interfaces_only 吗? msdn.microsoft.com/en-us/library/298h7faa.aspx
  • 是的,我做到了,这是我使用的 #import "e:\z\ManagedChange\ManagedChange\bin\Debug\ManagedChange.dll.tlb" named_guids raw_interfaces_only
  • 删除 raw_interfaces_only 它将生成“包装”接口。它们明显不同,并且更容易使用。但它可能会破坏您现有的代码,因为签名不同。例如,函数没有返回 HRESULT 并将返回值作为 [out] 参数,而是具有实际的返回值,并且 HRESULT 成为异常。它为您提供带有 raw_ 名称的其他签名,让您可以访问低级方法。
  • 这样好多了,原始接口也是生成的,但是有一个前缀 raw_。
【解决方案2】:

因为BSTR 是指向宽字符串的指针,但这并不意味着您可以只分配简单的 const wchar_t* 字符串。要使用 BSTR,您需要使用一些系统函数,SysAllocString() 行用于创建 BSTR。 _bstr_t 类封装了所有这些东西

【讨论】:

    猜你喜欢
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2013-03-18
    • 2013-03-08
    • 1970-01-01
    • 2014-12-11
    相关资源
    最近更新 更多