Visual Studio 2015 MFC中Windows更新搜索COM库异常原因咨询
环境:Visual Studio 2015,MFC
问题现象
执行以下代码时,IUpdateSearcher::EndSearch返回WU_E_WU_DISABLED,且代码从未进入if (FAILED(hr))分支:
hr = CoInitialize(NULL); if (FAILED(hr)) { jvResult[_T("result")] = JsonValue::number((int)ISPT_ResultEnum::ISPTResult_Fail); jvResult[_T("detail")][_T("error_log")] = JsonValue::string(l10n(IDS_INSPCT_ERRLOG_COM_INIT_FAIL).operator LPCWSTR()); return; }
但将上述代码中本地化字符串的行替换为硬编码字符串后,Windows更新搜索功能恢复正常:
jvResult[_T("detail")][_T("error_log")] = JsonValue::string(_T("Initial Fail"));
另外,先提前初始化本地化字符串并显示消息框后再调用CoInitialize,功能也正常:
CString strMsg = l10n(IDS_INSPCT_ERRLOG_COM_INIT_FAIL); BCGPCustomMessageBox(strMsg, theApp.m_nLanguage, MB_OK | MB_ICONINFORMATION); hr = CoInitialize(NULL); if (FAILED(hr)) { jvResult[_T("result")] = JsonValue::number((int)ISPT_ResultEnum::ISPTResult_Fail); jvResult[_T("detail")][_T("error_log")] = JsonValue::string(l10n(IDS_INSPCT_ERRLOG_COM_INIT_FAIL).operator LPCWSTR()); return; }
原因分析
l10n函数的隐式COM初始化
你的l10n本地化字符串加载函数内部,大概率调用了依赖COM的API——比如MFC资源加载相关的COM组件,或是BCG控件库的内部COM操作。在第一段代码里,l10n在CoInitialize之前执行,它会隐式调用CoInitializeEx(通常以单线程公寓STA模式完成初始化)。这就导致后续你自己调用CoInitialize(NULL)时,当前线程已经完成COM初始化,返回的hr是S_OK或S_FALSE,所以代码不会进入FAILED(hr)分支。线程COM模型冲突
Windows Update的IUpdateSearcher组件要求线程处于STA模式。如果l10n隐式初始化的COM模型和后续组件期望的模型不匹配,或者提前初始化导致线程COM状态异常,就会引发WU_E_WU_DISABLED错误——这个错误表面是Windows更新服务禁用,实际是COM组件调用失败的间接表现。提前初始化本地化字符串的作用
第三段代码中,提前调用l10n并显示消息框,相当于提前完成了COM初始化,此时后续调用CoInitialize(NULL)返回S_FALSE(表示已初始化),但线程的COM环境已经处于稳定的STA模式,IUpdateSearcher可以正常工作。而用硬编码字符串时,跳过了l10n的隐式COM初始化,你自己调用的CoInitialize(NULL)正确完成了STA模式初始化,组件也能正常工作。
解决方案
- 调整代码顺序:先调用
CoInitialize(NULL),再执行任何可能隐式初始化COM的操作(包括l10n资源加载)。 - 检查
l10n函数实现:确认内部是否有COM调用,必要时显式控制COM初始化时机,避免隐式初始化干扰后续逻辑。 - 验证COM初始化结果:即使
CoInitialize返回S_FALSE(已初始化),也要确保线程处于STA模式,可以用CoGetApartmentType检查当前线程的COM公寓类型,确保和IUpdateSearcher要求一致。
内容的提问来源于stack exchange,提问作者Chang dae Kim

