我有一些内部代码,可以使用 Windows Update API 执行 Microsoft Update 扫描。由于某些客户端无法直接访问互联网,因此我明确设置了WebProxy
属性指向我们的本地代理服务器。在测试期间(在 Windows 7 上),这似乎工作得很好。现在我正在 Windows 10 上测试它(参见脚注 1),似乎代理设置被忽略。
Windows 更新客户端wasWindows 10 中进行了重大修改,因此possible这是新版本客户端中的一个错误或未记录的限制,但另一方面,我以前几乎没有使用 COM 的经验,所以我可能做错了什么。
使用下面发布的测试代码观察结果:
该代码在 Windows 7 上按预期工作,无论它在什么安全上下文中运行,也无论客户端是否具有直接 Internet 访问和/或在用户的 Internet 设置中配置的代理服务器。
该代码也适用于 Windows 10,前提是客户端可以直接访问互联网。
代码mostly如果客户端无法直接访问 Internet,但运行它的用户在其 Internet 设置中配置了合适的代理服务器,则可在 Windows 10 上运行。 (见脚注 2。)
代码确实not如果客户端无法直接访问互联网并且运行客户端的用户没有配置合适的代理,则可以在 Windows 10 上运行。它不会连接到代码中指定的代理,而是尝试连接到一系列外部IP地址;一旦所有这些连接尝试最终超时,它将在所示行上返回 0x80072ee2、ERROR_INTERNET_TIMEOUT。 (通过省略设置代理服务器的代码部分,我可以在 Windows 7 上获得非常相似的行为。)
此外,如果我故意将代码中的代理 URL 更改为指向不存在的服务器,则代码将按预期在 Windows 7 上停止工作,但 Windows 10 上的行为保持不变。所以看起来 Windows 更新确实只是忽略了WebProxy
财产。 (该属性正在设置;我可以从IUpdateSession
目的。)
更改交付优化下载模式似乎没有帮助。我已经尝试了通过组策略提供的所有不同模式。在代理 URL 中添加尾部斜杠会破坏 Windows 7 的代码,并且对于 Windows 10 没有任何影响。使用裸 DNS 名称而不是 URL 在 Windows 7 上有效,但在 Windows 10 上没有任何影响。
由于代码最终旨在成为系统服务的一部分和/或远程运行,因此在用户级别配置代理设置并不是理想的选择,尽管如果没有其他解决方案可用,我可能可以依靠它。
这是我一直在测试的代码,是原始代码的精简版本。测试代码实际上并不处理结果(如果有),因为问题发生在该点之前。我隐藏了代理服务器的真实 DNS 名称,但 URL 的形式如下所示。任何想要在自己的环境中测试代码的人当然都需要将其指向自己的代理。
#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周年更新。我的大多数客户都没有三月份的更新,但在其他方面都是最新的。我还确认安装了三月更新的客户端上仍然出现该问题。
(2) 测试过程中,使用用户配置的代理两次失败,都是在新重装的机器上;一旦开始工作,它就会继续工作。在这种情况下,扫描仍会尝试连接到各种外部 IP 地址,但这些连接超时的事实不会导致扫描失败。我suspect这一切都与传递优化下载模式有关,但我仍在尝试。
附录:运行代码的用户帐户在其 Internet 设置中配置了合适的代理服务器的情况仅在代码交互运行时才有效。在非交互式上下文中,例如服务或计划任务,这确实not工作。目前,在我看来,除非可以直接访问互联网,否则在 Windows 10 计算机上不可能通过服务访问 Microsoft Update。