使用 C++ 删除 WMI 实例

Deleting WMI instance with C++

我发现了一些使用 C# 和 VBS 删除 WMI 实例的示例,但是我需要用 C++ 实现它。

我的示例代码:

CoInitialize(NULL);

HRESULT hRes;

//Obtain the initial locator to WMI
CComPtr<IWbemLocator> pLoc = NULL;
hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &pLoc);
if(FAILED(hRes))
    return 1;

//Connect to WMI through the IWbemLocator::ConnectServer method
CComPtr<IWbemServices> pSvc = NULL;
//Connect to the root namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
hRes = pLoc->ConnectServer(L"ROOT\SUBSCRIPTION", NULL, NULL, 0, NULL, 0, 0, &pSvc);
if(FAILED(hRes))
    return 1;

hRes = pSvc->DeleteInstance(
           L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'",
           WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);

return 0;

据此我发现 here and here, my code should work. I surely have CommandLineEventConsumer named {709782F3-E860-488E-BD8A-89FBC8C1495C}

我的代码在 IWbemServices::DeleteInstance 上失败,错误代码 0x80041008(调用的参数之一不正确)。

如果有人发现我的代码中有错误,我将不胜感激。或者可能需要一些特权才能做到这一点?

IWbemServices::DeleteInstance 的第一个参数是 BSTRBSTR 与 UTF-16 编码的 C 风格字符串的不同之处在于它存储显式长度参数。即使 BSTRwchar_t* 类型,您也不能传递普通字符串文字来代替 BSTR.

要从字符串文字创建 BSTR,您需要调用 SysAllocString:

BSTR objPath = ::SysAllocString(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(
       objPath,
       WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);
::SysFreeString(objPath);

或者,由于您已经在 CComPtr 使用 ATL,您可以使用 CComBSTR 让您的生活更轻松:

CComBSTR objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(
       objPath,
       WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);


注意:IWbemLocator::ConnectServer也需要BSTRs作为参数。文档页面上提供的示例确实传递了一个普通的 C 风格字符串,因此当出现无效参数时,IWbemLocator 接口可能更宽容。

我找到了两个解决方案:

1.Remove WBEM_FLAG_RETURN_IMMEDIATELY 标志。

_bstr_t objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(objPath, 0, NULL, NULL);

2.Pass IWbemCallResult 结果。

_bstr_t objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
CComPtr<IWbemCallResult> pRes = NULL;
hRes = pSvc->DeleteInstance(objPath, WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pRes);

没有深入研究,但它是双向的。看起来规格并非 100% 正确。