Visual 6.0 C++调用WMI获取Win32_OperatingSystem枚举属性时遇0x80041018错误
WMI调用Next函数返回0x80041018错误的解决办法
问题场景
在Windows XP系统下使用Visual C++ 6.0开发,尝试通过WMI枚举Win32_OperatingSystem类属性时,调用IEnumWbemClassObject::Next函数返回错误代码0x80041018,原代码缺少关键错误处理和规范的COM参数使用:
int CSystemInfo::Init() { HRESULT hRes = CoInitializeEx(0, COINIT_APARTMENTTHREADED); if(FAILED(hRes)) return 1; hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_DELEGATE, NULL, EOAC_NONE, NULL ); IWbemLocator *locator = NULL; hRes = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&locator ); IWbemServices *services = NULL; hRes = locator->ConnectServer( BSTR(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &services); hRes = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE ); IEnumWbemClassObject * pEnumerator = NULL; hRes = services->ExecQuery(BSTR("WQL"), BSTR("SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); IWbemClassObject *obj=NULL; ULONG ret_objs_num; hRes = WBEM_S_NO_ERROR; while(WBEM_S_NO_ERROR == hRes) { //ERROR 0x80040018 hRes = pEnumerator->Next(WBEM_INFINITE, 1, &obj, &ret_objs_num); if(FAILED(hRes) || obj== NULL || ret_objs_num==0) break; } return 0; }
错误原因分析
- BSTR参数不合法:直接用
BSTR()强制转换字符串字面量,VC6中这种方式无法生成符合WMI要求的有效BSTR,导致查询语法被判定为无效(对应错误码0x80041018即WBEM_E_INVALID_SYNTAX)。 - 缺失关键错误检查:
CoInitializeSecurity、CoCreateInstance、ConnectServer、ExecQuery等步骤的返回值未做失败判断,若前面步骤已出错,后续Next调用必然失败。 - 安全权限不匹配:
CoInitializeSecurity中使用RPC_C_IMP_LEVEL_DELEGATE,Windows XP环境下普通进程无法获取该权限,应使用更宽松的RPC_C_IMP_LEVEL_IMPERSONATE。 - COM对象未释放:代码中未调用
Release()释放所有COM指针,不仅造成内存泄漏,还可能破坏WMI的内部状态。
解决办法及修正代码
核心修复点
- 使用
SysAllocString创建合法BSTR,避免强制转换。 - 为每个COM调用添加严格的错误检查,提前终止错误流程。
- 调整
CoInitializeSecurity的 impersonation level 为RPC_C_IMP_LEVEL_IMPERSONATE。 - 正确释放所有COM对象,清理资源。
修正后的代码
#include <wbemcli.h> #include <comutil.h> #pragma comment(lib, "wbemuuid.lib") #pragma comment(lib, "comsupp.lib") int CSystemInfo::Init() { HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(hRes)) { return 1; } // 调整安全设置为XP兼容的 impersonation level hRes = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, // 替换原有的DELEGATE NULL, EOAC_NONE, NULL ); // 忽略RPC_E_TOO_LATE错误(若已初始化安全设置) if (FAILED(hRes) && hRes != RPC_E_TOO_LATE) { CoUninitialize(); return 2; } IWbemLocator* locator = NULL; hRes = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&locator ); if (FAILED(hRes)) { CoUninitialize(); return 3; } IWbemServices* services = NULL; BSTR strNamespace = SysAllocString(L"ROOT\\CIMV2"); hRes = locator->ConnectServer( strNamespace, NULL, NULL, NULL, 0, NULL, NULL, &services ); SysFreeString(strNamespace); if (FAILED(hRes)) { locator->Release(); CoUninitialize(); return 4; } // 设置代理 blanket hRes = CoSetProxyBlanket( services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hRes)) { services->Release(); locator->Release(); CoUninitialize(); return 5; } IEnumWbemClassObject* pEnumerator = NULL; BSTR strWQL = SysAllocString(L"WQL"); BSTR strQuery = SysAllocString(L"SELECT * FROM Win32_OperatingSystem"); hRes = services->ExecQuery( strWQL, strQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); SysFreeString(strWQL); SysFreeString(strQuery); if (FAILED(hRes)) { services->Release(); locator->Release(); CoUninitialize(); return 6; } IWbemClassObject* obj = NULL; ULONG ret_objs_num = 0; hRes = WBEM_S_NO_ERROR; while (hRes == WBEM_S_NO_ERROR) { hRes = pEnumerator->Next(WBEM_INFINITE, 1, &obj, &ret_objs_num); if (FAILED(hRes) || ret_objs_num == 0 || obj == NULL) { break; } // 这里可以添加属性读取逻辑,例如获取系统版本 VARIANT vtProp; VariantInit(&vtProp); if (SUCCEEDED(obj->Get(L"Caption", 0, &vtProp, NULL, NULL))) { // 处理vtProp中的数据,例如输出到日志 VariantClear(&vtProp); } obj->Release(); obj = NULL; } // 释放所有COM对象 if (pEnumerator) pEnumerator->Release(); if (services) services->Release(); if (locator) locator->Release(); CoUninitialize(); return 0; }
额外说明
- 确保项目链接
wbemuuid.lib和comsupp.lib(VC6中需手动添加)。 CoInitializeSecurity可能返回RPC_E_TOO_LATE,这是正常现象(若进程已初始化安全设置),可忽略该错误。- 读取WMI属性时需正确初始化和清理
VARIANT对象,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Bear WiliBear
相关产品推荐
相关产品推荐

