question

NAVEENKUMARK-5372 avatar image
0 Votes"
NAVEENKUMARK-5372 asked XiaopoYang-MSFT commented

WUA API empty download URL for cumulative updates

I am using a C++ program which uses WUA API to scan for updates against Microsoft Update Catalog. Things were working fine for quite a while, but in recent days, I am seeing certain KB articles are not providing download URL. These are especially cumulative updates.

I have verified Microsoft Update Catalog for same KB article, but there I can find the updates available and able to download from there. Please help on this.

Client operating system: Windows 10 version 21H1 (OS Build 19043.1586)

Code snippet:



include <wuapi.h>

include <comdef.h>

include <atlbase.h>


int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);

 IUpdateSession          *lpUpdateSession;
 HRESULT hr = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&lpUpdateSession);

 if(hr != S_OK)
 {
     _tprintf( _T("%s - 0x%X\n"), _T("Failed to create update session.\n\n"), hr);
     return -1;
 }

 IUpdateSearcher         *lpUpdateSearcher;
 if((hr = lpUpdateSession->CreateUpdateSearcher(&lpUpdateSearcher)) != S_OK)
 {
     _tprintf( _T("Failed to create searcher 0x%X\n\n"),hr);
     return -1;
 }

 IUpdateServiceManager   *lpUpdateServiceManager;
 if((hr = CoCreateInstance(CLSID_UpdateServiceManager, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateServiceManager, (LPVOID*)&lpUpdateServiceManager)) != S_OK)
 {
     _tprintf( _T("Created Update service Manager failed 0x%X\n\n"),hr);
     return -1;
 }

 lpUpdateSession->put_ClientApplicationID(bstr_t("MyApp"));

 IUpdateSearcher         *pSearcher;
 hr = lpUpdateSession->CreateUpdateSearcher(&pSearcher);
 pSearcher->put_ServiceID(bstr_t("7971f918-a847-4430-9279-4a52d1efe18d")); //Microsoft Update Catalog
 pSearcher->put_ServerSelection(ssOthers);

 BSTR bstrSearchCriteria = bstr_t("");
 _TCHAR tszCriteria[1024] = _T("");
 bstrSearchCriteria = bstr_t("Type='Software'");

 ISearchResult           *pSearchResult;
 if((hr=pSearcher->Search(bstrSearchCriteria, &pSearchResult))!= S_OK)
 {
     _tprintf( _T("Failed to perform Search: 0x%X\n"),hr);
     return -1;
 }
 IUpdateCollection *pUpdateCollection;
 pSearchResult->get_Updates(&pUpdateCollection);

 long lFoundUpdateCount = 0;
 pUpdateCollection->get_Count(&lFoundUpdateCount);

 _tprintf( _T("Found %ld updates.\n"), lFoundUpdateCount );
 for ( long l = 0; l < lFoundUpdateCount; l++ )
 {
     IUpdate *lpUpdate = NULL;
     hr = pUpdateCollection->get_Item(l, &lpUpdate);
     if (hr == S_OK)
     {
         //KB Article ID
         CComQIPtr<IStringCollection> lpKBArticles;
         hr = lpUpdate->get_KBArticleIDs(&lpKBArticles);
         if(SUCCEEDED(hr) && lpKBArticles != NULL)
         {
             long lKBArticlesCount = 0;
             lpKBArticles->get_Count(&lKBArticlesCount);
             for(long kb = 0; kb < lKBArticlesCount; kb++)
             {
                 BSTR bstrKB;
                 lpKBArticles->get_Item(kb, &bstrKB);
                 _tprintf(_T("\nKB%s\n"), (const _TCHAR*)bstr_t(bstrKB) );
             }
         }

         //Installed/missing
         VARIANT_BOOL bInstalled;
         lpUpdate->get_IsInstalled(&bInstalled);
         if( bInstalled == VARIANT_FALSE )
         {
             _tprintf( _T("Missing\n") );
         }
         else
         {
             _tprintf( _T("Installed\n") );
         }

         //Download URL
         CComQIPtr<IUpdateCollection> BundledUpdate;
         if(lpUpdate->get_BundledUpdates(&BundledUpdate) == S_OK)
         {
             long count = -1;
             BundledUpdate->get_Count(&count);

             if (count == 0)
             {
                 _tprintf( _T("Empty download URL\n"));
             }
             else
             {
                 _tprintf( _T("DownloadURL(s):\n"));

                 for(long update = 0; update < count; update++)
                 {
                     CComQIPtr<IUpdateDownloadContentCollection> retVal;
                     CComQIPtr<IUpdateDownloadContent> retItem;
                     CComQIPtr<IUpdate> retUpdate;
                     BundledUpdate->get_Item(update, &retUpdate);
                     retUpdate->get_DownloadContents(&retVal);
                     hr = retVal->get_Item(0, &retItem);
                     if(hr != S_OK)
                     {
                         continue;
                     }

                     BSTR bstrDownloadURL;
                     retItem->get_DownloadUrl(&bstrDownloadURL);
                     _tprintf( _T("%s\n"), (const _TCHAR*)bstr_t(bstrDownloadURL));
                 }
             }
         }
     }
 }
 return 0;

}


I am getting download URL for almost all patches, but 2 KB articles I am getting empty download URL. Below is sample output.


KB890830
Installed
DownloadURL(s):
http://download.windowsupdate.com/d/msdownload/update/software/uprl/2022/02/windows-kb890830-x64-v5.98_b56cfec6692828d2b240b0978e09fa22ddf23994.exe

KB5010472
Missing
DownloadURL(s):
http://download.windowsupdate.com/d/msdownload/update/software/updt/2022/01/windows10.0-kb5010472-x64-ndp48_07d328da3e495d688287607c0c4748cb4a327b90.cab

KB890830
Installed
DownloadURL(s):
http://download.windowsupdate.com/d/msdownload/update/software/uprl/2022/03/windows-kb890830-x64-v5.99_66336e634eff1ead4e953f09165eda1da29298fb.exe

KB5011487
Installed
Empty download URL

KB4023057
Installed
Empty download URL








windows-apic++
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hello, @NAVEENKUMARK-5372 . I’m trying to consult about the behavior.

1 Vote 1 ·

Hello @XiaopoYang-MSFT , Thanks. Looking forward to your response.

0 Votes 0 ·

Any clue on reported problem @XiaopoYang-MSFT ?

0 Votes 0 ·
Show more comments

1 Answer

XiaopoYang-MSFT avatar image
0 Votes"
XiaopoYang-MSFT answered XiaopoYang-MSFT commented

Hello @NAVEENKUMARK-5372 , "Those are non-bundled updates. So, they should just do something like:"

 #include <wuapi.h>
 #include <comdef.h>
 #include <atlbase.h>
 int _tmain(int argc, _TCHAR* argv[])
 {
     CoInitialize(NULL);
    
     IUpdateSession* lpUpdateSession;
     HRESULT hr = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&lpUpdateSession);
     if (hr != S_OK)
     {
         _tprintf(_T("%s - 0x%X\n"), _T("Failed to create update session.\n\n"), hr);
         return -1;
     }
     /*IUpdateSearcher* lpUpdateSearcher;
     if ((hr = lpUpdateSession->CreateUpdateSearcher(&lpUpdateSearcher)) != S_OK)
     {
         _tprintf(_T("Failed to create searcher 0x%X\n\n"), hr);
         return -1;
     }
     IUpdateServiceManager* lpUpdateServiceManager;
     if ((hr = CoCreateInstance(CLSID_UpdateServiceManager, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateServiceManager, (LPVOID*)&lpUpdateServiceManager)) != S_OK)
     {
         _tprintf(_T("Created Update service Manager failed 0x%X\n\n"), hr);
         return -1;
     }*/
     lpUpdateSession->put_ClientApplicationID(bstr_t("MyApp"));
     IUpdateSearcher* pSearcher;
     hr = lpUpdateSession->CreateUpdateSearcher(&pSearcher);
     pSearcher->put_ServiceID(bstr_t("7971f918-a847-4430-9279-4a52d1efe18d")); //Microsoft Update Catalog
     //pSearcher->put_ServerSelection(ssOthers);
     pSearcher->put_ServerSelection(ssWindowsUpdate);
     BSTR bstrSearchCriteria = bstr_t("");
     _TCHAR tszCriteria[1024] = _T("");
     bstrSearchCriteria = bstr_t("Type='Software'");
     ISearchResult* pSearchResult;
     if ((hr = pSearcher->Search(bstrSearchCriteria, &pSearchResult)) != S_OK)
     {
         _tprintf(_T("Failed to perform Search: 0x%X\n"), hr);
         return -1;
     }
     IUpdateCollection* pUpdateCollection;
     pSearchResult->get_Updates(&pUpdateCollection);
     long lFoundUpdateCount = 0;
     pUpdateCollection->get_Count(&lFoundUpdateCount);
     _tprintf(_T("Found %ld updates.\n"), lFoundUpdateCount);
     for (long l = 0; l < lFoundUpdateCount; l++)
     {
         IUpdate* lpUpdate = NULL;
         hr = pUpdateCollection->get_Item(l, &lpUpdate);
         if (hr == S_OK)
         {
             //KB Article ID
             CComQIPtr<IStringCollection> lpKBArticles;
             hr = lpUpdate->get_KBArticleIDs(&lpKBArticles);
             if (SUCCEEDED(hr) && lpKBArticles != NULL)
             {
                 long lKBArticlesCount = 0;
                 lpKBArticles->get_Count(&lKBArticlesCount);
                 for (long kb = 0; kb < lKBArticlesCount; kb++)
                 {
                     BSTR bstrKB;
                     lpKBArticles->get_Item(kb, &bstrKB);
                     _tprintf(_T("\nKB%s\n"), (const _TCHAR*)bstr_t(bstrKB));
                 }
             }
             //Installed/missing
             VARIANT_BOOL bInstalled;
             lpUpdate->get_IsInstalled(&bInstalled);
             if (bInstalled == VARIANT_FALSE)
             {
                 _tprintf(_T("Missing\n"));
             }
             else
             {
                 _tprintf(_T("Installed\n"));
             }
             //Download URL
             /*CComQIPtr<IUpdateCollection> BundledUpdate;
             if (lpUpdate->get_BundledUpdates(&BundledUpdate) == S_OK)
             {
                 long count = -1;
                 BundledUpdate->get_Count(&count);
                 if (count == 0)
                 {
                     _tprintf(_T("Empty download URL\n"));
                 }
                 else
                 {
                     _tprintf(_T("DownloadURL(s):\n"));
                     for (long update = 0; update < count; update++)
                     {
                         CComQIPtr<IUpdateDownloadContentCollection> retVal;
                         CComQIPtr<IUpdateDownloadContent> retItem;
                         CComQIPtr<IUpdate> retUpdate;
                         BundledUpdate->get_Item(update, &retUpdate);
                         retUpdate->get_DownloadContents(&retVal);
                         hr = retVal->get_Item(0, &retItem);
                         if (hr != S_OK)
                         {
                             continue;
                         }
                         BSTR bstrDownloadURL;
                         retItem->get_DownloadUrl(&bstrDownloadURL);
                         _tprintf(_T("%s\n"), (const _TCHAR*)bstr_t(bstrDownloadURL));
                     }
                 }
             }*/
    
             //Download URL
             long bundledUpdateCount{};
    
             // Is it a bundled update?
             CComQIPtr<IUpdateCollection> bundledUpdates;
             if (lpUpdate->get_BundledUpdates(&bundledUpdates) == S_OK)
             {
                 bundledUpdates->get_Count(&bundledUpdateCount);
             }
    
             if (bundledUpdateCount > 0)
             {
                 _tprintf(_T("This is a bundled update.  We will iterate each update.\n"));
    
                 _tprintf(_T("DownloadURL(s):\n"));
    
                 for (long update = 0; update < bundledUpdateCount; update++)
                 {
                     CComQIPtr<IUpdateDownloadContentCollection> retVal;
                     CComQIPtr<IUpdateDownloadContent> retItem;
                     CComQIPtr<IUpdate> retUpdate;
                     bundledUpdates->get_Item(update, &retUpdate);
                     retUpdate->get_DownloadContents(&retVal);
                     hr = retVal->get_Item(0, &retItem);
                     if (hr != S_OK)
                     {
                         continue;
                     }
                     BSTR bstrDownloadURL;
                     retItem->get_DownloadUrl(&bstrDownloadURL);
                     _tprintf(_T("%s\n"), (const _TCHAR*)bstr_t(bstrDownloadURL));
                 }
    
                 _tprintf(_T("\n"));
             }
             else
             {
                 _tprintf(_T("This is not a bundled update.\n"));
    
                 _tprintf(_T("DownloadURL(s):\n"));
    
                 CComQIPtr<IUpdateDownloadContentCollection> retVal;
                 CComQIPtr<IUpdateDownloadContent> retItem;
                 lpUpdate->get_DownloadContents(&retVal);
                 hr = retVal->get_Item(0, &retItem);
                 if (hr != S_OK)
                 {
                     continue;
                 }
                 BSTR bstrDownloadURL;
                 retItem->get_DownloadUrl(&bstrDownloadURL);
                 _tprintf(_T("%s\n\n"), (const _TCHAR*)bstr_t(bstrDownloadURL));
             }
    
         }
     }
     return 0;
 }

198949-image.png


image.png (24.5 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @XiaopoYang-MSFT , Thanks for the response.

Is there any special meaning for this not-bundled updates? I have tried accessing the downloadURL manually, but it gives access denied.

198980-wu-tld-url-error.jpg

Usually I will download the patch from downloadURL in one place and deploy them offline to LAN machines to save bandwidth. Is there any way we can achieve the same for these patches?


0 Votes 0 ·

Hello @NAVEENKUMARK-5372 , When Windows Update found the update, it temporarily created the download link to download it. Thus, it is not possible to use the link later.

0 Votes 0 ·