Why isn't IUpdateSession::WebProxy working on

2019-02-18 18:25发布

I've got some in-house code that performs a Microsoft Update scan using the Windows Update API. Because some of the clients do not have direct internet access, I explicitly set the WebProxy property to point to our local proxy server. During testing (on Windows 7) this seemed to work perfectly. Now I'm testing it on Windows 10 (see footnote 1) and it seems that the proxy setting is being ignored.

The Windows Update client was revised significantly in Windows 10, so it is possible that this is a bug or undocumented limitation in the new version of the client, but on the other hand I have little previous experience using COM so I might be doing something wrong.

Observed results, using the test code posted below:

  • The code works as desired on Windows 7, regardless of what security context it is run in, and regardless of whether or not the client has direct internet access and/or a proxy server configured in the user's Internet settings.

  • The code also works on Windows 10, provided the client has direct internet access.

  • The code mostly works on Windows 10 if the client does not have direct internet access but the user that runs it has a suitable proxy server configured in their Internet settings. (See footnote 2.)

  • The code does not work on Windows 10 if the client does not have direct internet access and the user that runs it does not have a suitable proxy configured. Instead of connecting to the proxy specified in the code, it attempts to connect to a series of external IP addresses; once all of these connection attempts have finally timed out, it returns 0x80072ee2, ERROR_INTERNET_TIMEOUT, on the line shown. (I can get very similar behaviour on Windows 7 by leaving out the part of the code that sets the proxy server.)

Also, if I deliberately change the proxy URL in the code to point to a non-existent server, the code stops working on Windows 7, as expected, but the behaviour on Windows 10 is unchanged. So it really does look as though Windows Update is simply ignoring the WebProxy property. (The property is being set; I can read it back from the IUpdateSession object.)

Changing the Delivery Optimization Download Mode does not appear to help. I've tried all of the different modes that are available via Group Policy. Adding a trailing slash to the proxy URL broke the code for Windows 7 and made no difference for Windows 10. Using a bare DNS name rather than a URL worked on Windows 7 but made no difference on Windows 10.

Since the code is ultimately intended to become part of a system service and/or be run remotely, configuring proxy settings at the user level is not an ideal option, though I might be able to fall back on that if no other solution is available.

This is the code I've been testing, a cut-down version of the original code. The test code does not actually process the results, if any, since the problem occurs before that point. I've hidden the real DNS name of our proxy server, but the URL is of the form shown. Anyone wanting to test the code in their own environment will of course need to point it at their own proxy anyway.

#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);
}

Is there anything I can do to make this work on Windows 10 the same way as it does on Windows 7?


(1) I am running Windows 10 LTSB 2016. This is basically the same as Windows 10 version 1607, also known as Windows 10 Anniversary Update. Most of my clients don't have the March updates but are otherwise up to date. I've also confirmed that the problem still occurs on a client with the March updates installed.

(2) During testing, using the user-configured proxy has failed on two occasions, both on newly reinstalled machines; once it starts working, it keeps working. In this scenario, the scan does still attempt to connect to various external IP addresses, but the fact that these connections time out does not cause the scan to fail. I suspect this all has something to do with the Delivery Optimization download mode, but I'm still experimenting.


Addendum: the case where the user account the code is running as has a suitable proxy server configured in their Internet Settings only works when the code is run interactively. In a non-interactive context, e.g., a service or scheduled task, this does not work. At present, it appears to me to be impossible on a Windows 10 machine to access Microsoft Update from a service unless you have direct internet access.

0条回答
登录 后发表回答