我有一些使用Windows Update API执行Microsoft Update扫描的内部代码。 由于某些客户没有直接的互联网访问,我明确地设置WebProxy
属性指向我们的本地代理服务器。 在testing期间(在Windows 7上),这似乎完美地工作。 现在我正在Windows 10上testing它(请参阅脚注1),而且似乎忽略了代理设置。
Windows Update客户端在Windows 10中进行了重大修改,因此这可能是新版本客户端中的一个错误或无证的限制,但是另一方面,我以前使用COM的经验不多,所以我可能会做错事。
观察结果,使用下面贴出的testing代码:
无论运行什么安全上下文,以及客户端是否在用户的Internet设置中configuration了直接Internet访问和/或代理服务器,该代码都可以在Windows 7上按需要运行。
该代码也适用于Windows 10,前提是客户端可以直接访问互联网。
如果客户端没有直接的互联网访问,但是运行它的用户在他们的Internet设置中configuration了合适的代理服务器,则代码主要在Windows 10上运行。 (见脚注2)
如果客户端没有直接的互联网访问,并且运行它的用户没有configuration合适的代理,则该代码在Windows 10上不起作用。 它不是连接到代码中指定的代理,而是尝试连接到一系列外部IP地址; 一旦所有这些连接尝试最终都超时,它将在显示的行上返回0x80072ee2,ERROR_INTERNET_TIMEOUT。 (我忽略了设置代理服务器的部分代码,从而可以在Windows 7上获得非常类似的行为。)
此外,如果我故意将代理中的代理URL更改为指向不存在的服务器,则代码将停止在Windows 7上工作,如预期的那样,但Windows 10上的行为不变。 所以它确实看起来像Windows Update只是忽略了WebProxy
属性。 (该属性正在设置;我可以从IUpdateSession
对象中读取它。)
更改传递优化下载模式似乎没有帮助。 我尝试了所有可通过组策略使用的不同模式。 向代理URL添加尾部斜杠违反了Windows 7的代码,对于Windows 10没有任何影响。使用裸露的DNS名称而不是Windows 7上的URL,但在Windows 10上没有任何区别。
由于代码最终打算成为系统服务的一部分和/或远程运行,所以在用户级别configuration代理设置不是一个理想的select,尽pipe如果没有其他解决scheme可用,我可能会回头。
这是我一直在testing的代码,原始代码的一个缩减版本。 testing代码实际上没有处理结果,如果有的话,因为问题发生在该点之前。 我已经隐藏了我们的代理服务器的真实DNS名称,但URL的格式如图所示。 任何想要在自己的环境中testing代码的人都需要将自己的代理指向它。
#include <windows.h> #include <wuapi.h> #include <stdio.h> #define stringize1(x) L#x #define stringize(x) stringize1(x) #define fail() fail_fn(L"Fatal error at line " stringize(__LINE__)) void fail_fn(wchar_t * msg) { wprintf(L"%s\n", msg); exit(1); } int wmain(int argc, wchar_t ** argv) { IUpdateSearcher* updateSearcher; IWebProxy* webProxy; IUpdateServiceManager2* serviceManager; IUpdateServiceRegistration* serviceRegistration; IUpdateSession* updateSession; ISearchResult* results; BSTR searchString, proxyString, bstrServiceID; HRESULT hr; if((hr = CoInitialize(NULL)) != S_OK) { fail(); } hr = CoCreateInstance(&CLSID_UpdateServiceManager, NULL, CLSCTX_INPROC_SERVER, &IID_IUpdateServiceManager2, (void **)&serviceManager); if (hr != S_OK) fail(); bstrServiceID = SysAllocString(L"7971f918-a847-4430-9279-4a52d1efe18d"); serviceManager->lpVtbl->AddService2(serviceManager, bstrServiceID, asfAllowPendingRegistration | asfRegisterServiceWithAU, NULL, &serviceRegistration); if (hr != S_OK) fail(); hr = CoCreateInstance(&CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, &IID_IUpdateSession, (LPVOID*)&updateSession); if (hr != S_OK) fail(); hr = CoCreateInstance(&CLSID_WebProxy, NULL, CLSCTX_INPROC_SERVER, &IID_IWebProxy, (void **)&webProxy); if (hr != S_OK) fail(); hr = webProxy->lpVtbl->put_AutoDetect(webProxy, VARIANT_FALSE); if (hr != S_OK) fail(); proxyString = SysAllocString(L"http://proxy.contoso.co.nz:80"); if (proxyString == NULL) fail(); hr = webProxy->lpVtbl->put_Address(webProxy, proxyString); if (hr != S_OK) fail(); hr = updateSession->lpVtbl->put_WebProxy(updateSession, webProxy); if (hr != S_OK) fail(); hr = updateSession->lpVtbl->CreateUpdateSearcher(updateSession, &updateSearcher); if (hr != S_OK) fail(); hr = updateSearcher->lpVtbl->put_ServerSelection(updateSearcher, ssOthers); if (hr != S_OK) fail(); hr = updateSearcher->lpVtbl->put_ServiceID(updateSearcher, bstrServiceID); if (hr != S_OK) fail(); searchString = SysAllocString(L"IsInstalled=0 and Type='Software'"); hr = updateSearcher->lpVtbl->Search(updateSearcher, searchString, &results); if (hr != S_OK) /* fails here */ { wprintf(L"Error %0x\n", hr); fail(); } wprintf(L"Update search completed successfully.\n"); CoUninitialize(); exit(0); }
有什么我可以做的,使其在Windows 10上的工作方式就像它在Windows 7上一样?
(1)我正在运行Windows 10 LTSB 2016.这与Windows 10版本1607(也称为Windows 10周年更新)基本相同。 我的大多数客户没有3月份的更新,但是在其他方面是最新的。 我也已经确认问题仍然发生在安装了March更新的客户端上。
(2)在testing期间,使用用户configuration的代理在两个新的重新安装的机器上失败; 一旦开始工作,它会继续工作。 在这种情况下,扫描仍尝试连接到各种外部IP地址,但这些连接超时的事实不会导致扫描失败。 我怀疑这一切都与交付优化下载模式有关,但我仍在试验。
附录:用户帐户代码正在运行的情况,因为在Internet设置中configuration了合适的代理服务器,只有在交互式运行代码时才有效。 在非交互式上下文中,例如服务或计划任务,这是行不通的。 目前,除非您有直接的互联网访问,否则在我看来,Windows 10计算机无法从服务访问Microsoft Update。