如何通过C++获取Windows最后一次成功更新时间
你当前调用PowerShell的方案性能差,核心原因是每次调用都要启动独立的powershell.exe进程,加载整个PowerShell运行时,开销非常大。要实现原生C++获取Windows最后一次成功更新的日期时间,不需要依赖外部程序,直接在进程内调用Windows Update Agent提供的COM接口即可,和你PowerShell脚本访问的是完全相同的数据源,返回结果完全一致,且调用开销只有毫秒级。
实现要点
- 核心逻辑和原PowerShell方案完全对应:创建
Microsoft.Update.AutoUpdateCOM对象,读取其Results.LastSearchSuccessDate属性 - 调用COM接口前需要先初始化COM套间,单线程套间即可满足需求
- 读取到的
LastSearchSuccessDate是OLEDATE类型,可通过系统自带APIVariantTimeToSystemTime转换为SYSTEMTIME结构,再按需格式化为字符串 - 所有COM接口指针、VARIANT变量用完后需要手动释放,避免资源泄漏
- 接口调用不需要管理员权限,普通用户权限下即可正常获取数据,和原PowerShell方案的权限要求一致
- 编译仅需要链接系统默认自带的
oleaut32.lib,不需要额外引入第三方依赖
可直接运行的示例代码
#include <windows.h> #include <comdef.h> #include <stdio.h> // 对应COM对象的CLSID和接口IID,无需额外引入头文件即可使用 const CLSID CLSID_AutomaticUpdates = {0x6398794D, 0x3C89, 0x4870, {0xA3, 0x68, 0x83, 0x99, 0x46, 0x7A, 0x96, 0x68}}; int main() { HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(hr)) return 1; IDispatch* pAutoUpdate = NULL; IDispatch* pResults = NULL; VARIANT vResults, vLastSuccessDate; SYSTEMTIME st; VariantInit(&vResults); VariantInit(&vLastSuccessDate); do { // 创建AutoUpdate COM实例 hr = CoCreateInstance(CLSID_AutomaticUpdates, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&pAutoUpdate); if (FAILED(hr)) break; // 读取Results属性 DISPID dispidResults; OLECHAR* szResultsProp = L"Results"; hr = pAutoUpdate->GetIDsOfNames(IID_NULL, &szResultsProp, 1, LOCALE_USER_DEFAULT, &dispidResults); if (FAILED(hr)) break; DISPPARAMS noArgs = {NULL, NULL, 0, 0}; hr = pAutoUpdate->Invoke(dispidResults, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &vResults, NULL, NULL); if (FAILED(hr) || vResults.vt != VT_DISPATCH) break; pResults = vResults.pdispVal; // 读取LastSearchSuccessDate属性 DISPID dispidLastDate; OLECHAR* szDateProp = L"LastSearchSuccessDate"; hr = pResults->GetIDsOfNames(IID_NULL, &szDateProp, 1, LOCALE_USER_DEFAULT, &dispidLastDate); if (FAILED(hr)) break; hr = pResults->Invoke(dispidLastDate, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &vLastSuccessDate, NULL, NULL); if (FAILED(hr) || vLastSuccessDate.vt != VT_DATE) break; // 时间格式转换与输出 if (VariantTimeToSystemTime(vLastSuccessDate.date, &st)) { wchar_t timeBuf[256] = {0}; swprintf(timeBuf, _countof(timeBuf), L"最后一次成功更新搜索时间: %d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); wprintf(L"%s\n", timeBuf); } } while (false); // 释放所有资源 if (pResults) pResults->Release(); if (pAutoUpdate) pAutoUpdate->Release(); VariantClear(&vLastSuccessDate); VariantClear(&vResults); CoUninitialize(); return FAILED(hr) ? 1 : 0; }
如果你觉得手写IDispatch调用逻辑繁琐,可以在代码开头加入下面的类型库导入语句,编译器会自动生成对应COM接口的强类型包装,代码可以进一步简化,不需要手动处理DISPID和VARIANT参数解析:
#import "wuapi.tlb" named_guids raw_interfaces_only
内容的提问来源于stack exchange,提问作者Sultan
相关产品推荐
相关产品推荐

