简体   繁体   English

传递 wchar_t 而不是 BSTR 会导致 E_OUTOFMEMORY 错误

[英]Pass wchar_t instead of BSTR causes E_OUTOFMEMORY error

I have a simple DirectShow library and i also have a client application that call functions from that library.我有一个简单的 DirectShow 库,并且我还有一个客户端应用程序可以调用该库中的函数。 The problem is that some functions accept BSTR as arguments, but i prefer to pass either std::string or char* .问题是某些函数接受BSTR作为 arguments,但我更喜欢传递std::stringchar* It is certain that if i use one of these types i'll get plenty of compiler errors.可以肯定的是,如果我使用其中一种类型,我会得到很多编译器错误。

I asked the reason and someone said that i can't use non of them, because they don't guarantee ABI unlike BSTR.我问了原因,有人说我不能使用它们,因为它们不像 BSTR 那样保证 ABI。

Also i tried wchar_t .我也试过wchar_t I passed it to my function instead of BSTR.我将它传递给了我的 function 而不是 BSTR。 Surprisingly it didn't generate any compiler error:令人惊讶的是它没有产生任何编译器错误:

std::string username = "john";
wchar_t wcstring[4] = {0};
MultiByteToWideChar(0, 0, username.c_str(), 4, wcstring, 4);

But when i call my function:但是当我打电话给我的 function 时:

HRESULT hr = pFoo->myDummyFunction(wcstring);

And run the program, It returns E_OUTOFMEMORY as HRESULT.并运行程序,它返回E_OUTOFMEMORY作为 HRESULT。 I'm curious to know why it happens.我很想知道为什么会这样。

If the method you are calling is declared as taking a BSTR parameter, then you must pass a real BSTR as the argument.如果您正在调用的方法被声明为采用 BSTR 参数,那么您必须传递一个真正的 BSTR 作为参数。 There is no other choice.没有其他选择。

I'm sorry it's not your preference.很抱歉,这不是你的偏好。 I agree there are all kinds of reasons why this is inconvenient.我同意这不方便的原因有很多。 However trying to pass a wchar_t* instead of a BSTR is like trying to pass a std::vector<wchar_t> to a function that expects a std::wstring .但是,尝试传递wchar_t*而不是BSTR就像尝试将std::vector<wchar_t>传递给需要std::wstring的 function 。 Hopefully you will agree that that would be nonsense even if the compiler didn't stop you.希望您会同意即使编译器没有阻止您,这也是无稽之谈。

A BSTR is not just a sequence of characters; BSTR 不仅仅是一个字符序列; it's a variable-sized struct with very well defined semantics that happens to include a null-terminated sequence of wchar_t as it's main member.它是一个可变大小的结构,具有非常明确的语义,恰好包含一个以 null 结尾的 wchar_t 序列作为它的主要成员。

What confuses you is that the compiler appears to allow them to be mixed.让您感到困惑的是编译器似乎允许它们混合使用。 That is because the BSTR was designed so that, in some very limited scenarios, a BSTR object could be used like if it was just a wchar_t* .这是因为 BSTR 的设计使得在一些非常有限的情况下,可以像使用wchar_t*一样使用BSTR object。 A BSTR can sometimes be used in place of a wchar_t*, but not the other way around .有时可以使用 BSTR 代替 wchar_t*,但反之则不行

That just means that the C++ compiler cannot tell the difference between a BSTR and a wchar_t*.这只是意味着 C++ 编译器无法区分 BSTR 和 wchar_t* 之间的区别。 In fact, the Windows headers define BSTR essentially as typedef wchar_t* BSTR so they are the same thing to the compiler, but the compiler doesn't know about the rest of the BSTR struct.事实上,Windows 头文件本质上将 BSTR 定义为typedef wchar_t* BSTR所以它们对编译器来说是一样的,但是编译器不知道 BSTR 结构的 rest。 That means the compiler cannot tell you when it's legal to use a BSTR and when it's legal to use a wchar_t*: it is your responsibility to pick the right one by yourself.这意味着编译器无法告诉您何时使用 BSTR 是合法的,何时使用 wchar_t* 是合法的:您有责任自己选择正确的。

About BSTR : 关于 BSTR

Beyond the null-terminated sequence of characters at the core of the BSTR, a BSTR also has a size prefix stored before the first character ;除了 BSTR 核心的以空字符结尾的字符序列之外,BSTR在第一个字符之前还存储有一个大小前缀; and a BSTR must be allocated in a specific heap controlled by the COM infrastructure in Windows which is why it must only be created by calling SysAllocString() and similar functions.并且必须在由 Windows 中的 COM 基础结构控制的特定堆中分配 BSTR,这就是为什么它只能通过调用 SysAllocString() 和类似函数来创建的原因。

Using a wchar_t* where you should be using a BSTR will lead to errors, crashes and undefined behavior depending on specifics.在应该使用 BSTR 的地方使用 wchar_t* 会导致错误、崩溃和未定义的行为,具体取决于具体情况。 We can't know why specifically you got the E_OUTOFMEMORY error, but it's not hard to make a guess: the function probably tries to use the size prefix while trying to make a copy of the BSTR.我们不知道为什么您会收到 E_OUTOFMEMORY 错误,但不难猜测:function 可能会在尝试复制 BSTR 时尝试使用大小前缀。 Because you passed a wchar_t* instead of a BSTR, the prefix has garbage in it, likely an absurdly large number, and the function tries to use that large number to allocate huge amounts of memory for the copy, which fails.因为您传递了 wchar_t* 而不是 BSTR,所以前缀中有垃圾,可能是一个大得离谱的数字,并且 function 尝试使用该大数字为副本分配大量 memory,但失败了。


If you want to use std::wstring or a std::string for your own code, go right ahead.如果你想为你自己的代码使用 std::wstring 或 std::string,go 就在前面。 I would do the same thing.我会做同样的事情。 But create a BSTR before calling that method, pass it as the argument, then free the BSTR and move on.但是在调用该方法之前创建一个 BSTR,将其作为参数传递,然后释放 BSTR 并继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM