BSTR SysAllocString() 和 BSTR() 之间的区别?

问题描述 投票:0回答:2

我正在编写一个程序,它从命令行获取输入并使用该输入连接到远程 WMI 服务器并执行方法。我的代码如下:

#define _WIN32_DCOM
#include <comdef.h>
#include <WbemIdl.h>
#include <stdio.h>
#pragma comment(lib, "wbemuuid.lib")

int wmain(int argc, wchar_t* argv[]) {
    // <SNIP>

    /* Build dynamic string containing the hostname of the target and namespace.
       Example: \\DSKT-390047\ROOT\CIMV2 */
    wchar_t cimv2[256] = { 0 };
    swprintf_s(cimv2, 256, L"\\\\%ls\\ROOT\\CIMV2", argv[1]);

    IWbemServices* pSvc = NULL;
    hr = pLoc->ConnectServer(BSTR(cimv2), BSTR(argv[2]), BSTR(argv[3]), NULL,
    0, NULL, NULL, &pSvc);
    if (FAILED(hr)) {
        pLoc->Release();
        CoUninitialize();
        return 1;
    }

    // <SNIP>
}

ConnectServer()
方法需要8个参数,其中5个是
BSTR
类型。 Microsoft 详细说明,要创建
BSTR
类型,我必须这样做:

BSTR MyBstr = SysAllocString(L"foo");

但是,我看到一些开发人员也使用

BSTR(variable)
,其中变量的类型为
wchar_t*
,所以我想知道两者之间有什么区别?我找不到关于后者的太多信息。

我现在这样做可以吗?或者我应该先分配

BSTR
类型,使用它们,然后释放它们?

我认为我现在所做的方式避免了必须释放这些分配的对象的事实,但有些事情是不对的。

c++ c winapi com
2个回答
1
投票

(BSTR)
wchar_t*
类型的强制转换是一个严重的编程错误,虽然它可以编译并且可以工作,但当需要 BSTR 的函数尝试对其进行操作时,将会导致失败,因为 BSTR 类型的大小在指针之前携带,因此可能包含空字符。阅读更多这里。 它以这种方式创建是为了与需要 wchar_t* 的地方兼容
wchar_t*
,即您可以将 BSTR 传递给需要
wchar_t*
的函数。但反之则不然。
BSTR 也是以 null 结尾的,这意味着如果 BSTR 不包含空字符,则 wchar_t* 的转换可以在 wcslen 等函数中工作。这可能会有效地防止程序员发现他们的错误。

例如,尝试在 wchar_t* 上使用

SysStringLen

正确的做法是使用

_bstr_t

来换行。 _bstr_t f(L"Hello"); // pass f to a function that expects a BSTR.



1
投票
BSTR

确实带有以空结尾的字符串,如果您在 BSTR 和

wchar_t*
之间进行转换而不使用自动化 API,则不会出现任何问题。
但是,这些字符串类型经常参与编组,这意味着这些字符串背后有一个关于内存分配器的协议,然后整个字符串更像是使用给定分配器分配的内存块,通常被解释为字符串。

当您使用

SysString*

API 时,COM 子系统可以使用相同的 API 来正确识别内存块的大小并准确地编组您的调用,将字符串参数与其他地方完全相同(并且这个“其他地方”可以不同)线程、进程甚至远程系统)。如果将

wchar_t*
转换为
BSTR
,并且不使用适用于
BSTR
类型的 API,则参数传递的准确性将会丢失。然而,如果不涉及编组,那么通常没有区别。
总而言之,您应该使用 

BSTR

相关的 API 和分配来保持安全,而不是猜测在这种情况下是否确实需要这样做。为此,您还有好帮手,例如

bstr_t
wil::unique_bstr
等。
    

© www.soinside.com 2019 - 2024. All rights reserved.