|
|
//=======================================================================
//
// Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
//
// File: autoupd.cpp
//
// Owner: YanL
//
// Description:
//
// AutoApdateSupport
//
//=======================================================================
#include "stdafx.h"
#include "WUV3IS.h"
#include <stdio.h>
#include <initguid.h>
#include <inseng.h>
#include <shlwapi.h>
#include <wininet.h>
#define USEWUV3INCLUDES
#include <wuv3.h>
#undef USEWUV3INCLUDES
#include <winspool.h>
#include <cstate.h>
#include <wustl.h>
#include <osdet.h>
#include "CV3.h"
#include "detect.h"
#include "callback.h"
#include "locstr.h"
#include "safearr.h"
#include "install.h"
#include "log.h"
#include "filecrc.h"
#include "newtrust.h"
#define REGKEY_WUV3TEST _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\wuv3test")
extern CState g_v3state; //defined in CV3.CPP
extern void ProcessInstallList(Varray<DEPENDPUID>& vFinalList, int& cFinalList);
static void Cleanup(PINVENTORY_ITEM pItem);
// find auto-update catalog and get all puids in dependency order
STDMETHODIMP CCV3::BuildCatalog(BOOL fGoOnline, DWORD dwType, BSTR bstrServerUrl) { LOG_block("CCV3::BuildCatalog"); if (fGoOnline) { LOG_out("fGoOnline = true"); } else { LOG_out("fGoOnline = false"); } try { // we don't want to check the launch server from this interface
m_bLaunchServChecked = TRUE; // Configure download
CWUDownload::s_fOffline = ! fGoOnline;
PUID puidCatalog = 0;
#ifdef _WUV3TEST
// catalog spoofing
auto_hkey hkey; if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) { DWORD dwPuidCatalog = 0; DWORD dwSize = sizeof(dwPuidCatalog); if (NO_ERROR == RegQueryValueEx(hkey, _T("AutoUpdateCatalog"), 0, 0, (LPBYTE)&dwPuidCatalog, &dwSize)) { LOG_out("Test override to catalog %d", dwPuidCatalog); puidCatalog = dwPuidCatalog; } } // only then do normal
if (0 == puidCatalog) { #endif
CCatalog* pCatalogList = ProcessCatalog(0, bstrServerUrl, 0, 0, WU_ALL_ITEMS, 0); if (NULL == pCatalogList) { LOG_error("Cannot open catalog list"); return E_FAIL; } for(int nCatalog = 0; nCatalog < pCatalogList->GetHeader()->totalItems; nCatalog ++) { PINVENTORY_ITEM pItem = pCatalogList->GetItem(nCatalog); if (NULL == pItem) { continue; } if (pItem->ps->state != WU_ITEM_STATE_PRUNED && (pItem->pf->d.flags & dwType)) { puidCatalog = pItem->pf->d.puid; LOG_out("Found AutoUpdate catalog %d", puidCatalog); break; } } #ifdef _WUV3TEST
} #endif
if (0 == puidCatalog) { LOG_error("Can't find AU catalog puid"); return E_FAIL; }
m_pCatalogAU = ProcessCatalog(puidCatalog, bstrServerUrl, 0, 0, WU_ALL_ITEMS, 0); if (NULL == m_pCatalogAU) { LOG_error("Cannot open catalog"); return E_FAIL; }
ReadHiddenPuids(); // download common images and other files
if (fGoOnline) { TCHAR szRtfDir[MAX_PATH]; GetWindowsUpdateDirectory(szRtfDir); PathAppend(szRtfDir, _T("RTF")); V3_CreateDirectory(szRtfDir); (void)DownloadCommonRTFFiles(FALSE, NULL); }
} catch(HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
// find auto-update catalog and get all puids in dependency order
STDMETHODIMP CCV3::GetPuidsList(LONG* pcnPuids, PUID** ppPuids) { LOG_block("CCV3::GetPuidsList"); HRESULT hrRet = S_OK; try { // Builds correct dependency array
Varray<DEPENDPUID> vFinalList; int cFinalList = 0; ProcessInstallList(vFinalList, cFinalList); if (0 == cFinalList) return E_INVALIDARG;
//output it
m_apuids.resize(cFinalList); PUID* pPuids = m_apuids; for (int nPuid = 0; nPuid < cFinalList; nPuid++) pPuids[nPuid] = vFinalList[nPuid].puid; *pcnPuids = m_apuids.size(); *ppPuids = m_apuids; } catch(HRESULT hr) { LOG_error("error %08X", hr); hrRet = hr; } return hrRet; }
static void UrlAppend(LPTSTR pszURL, LPCTSTR pszPath) { if (_T('/') != pszURL[lstrlen(pszURL) - 1]) lstrcat(pszURL, _T("/")); lstrcat(pszURL, pszPath); }
STDMETHODIMP CCV3::QueryDownloadFiles(long puid, void* pCallbackParam, PFN_QueryDownloadFilesCallback pCallback) { LOG_block("CCV3::QueryDownloadFiles"); LOG_out("puid %d", puid); try { USES_CONVERSION;
PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL)) return E_INVALIDARG;
// Buffers that we will use
TCHAR szURL[INTERNET_MAX_URL_LENGTH]; TCHAR szLocalFile[MAX_PATH];
// CIF
if (pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD) { PWU_VARIABLE_FIELD pvCif = pItem->pd->pv->Find(WU_DESC_CIF_CRC); if (NULL == pvCif) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
TCHAR szCifBaseName[16]; wsprintf(szCifBaseName, _T("%d.cif"), puid);
TCHAR szCifCRCName[64]; HRESULT hr = MakeCRCName(szCifBaseName, (WUCRC_HASH*)pvCif->pData, szCifCRCName, sizeof(szCifCRCName)); if (FAILED(hr)) return hr;
GetWindowsUpdateDirectory(szLocalFile); PathAppend(szLocalFile, szCifBaseName); lstrcpy(szURL, g_v3state.GetRootServer()); UrlAppend(szURL, _T("CRCCif")); UrlAppend(szURL, szCifCRCName); pCallback(pCallbackParam, puid, T2W(szURL), T2W(szLocalFile)); }
// read this first pages
PWU_VARIABLE_FIELD pvRTFCRC = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY); if (pvRTFCRC != NULL) { PWU_VARIABLE_FIELD pvRTFImages = pItem->pd->pv->Find(WU_DESC_RTF_IMAGES);
// build a multisz string of file names
BYTE mszFileNames[512]; int iLen = sprintf((char*)mszFileNames, "%d.htm", pItem->GetPuid()); mszFileNames[++iLen] = '\0'; if (pvRTFImages != NULL) { // we have images
memcpy(mszFileNames + iLen, pvRTFImages->pData, pvRTFImages->len - 4); } // local directory
TCHAR szLocalDir[MAX_PATH]; GetWindowsUpdateDirectory(szLocalDir); wsprintf(szLocalFile, _T("RTF\\%d"), pItem->GetPuid()); // reuse szLocalFile as a temp buffer
PathAppend(szLocalDir, szLocalFile);
for(int iFileNo = 0; true; iFileNo++) { TCHAR szLocalName[128]; TCHAR szServerName[128]; if (FAILED(GetCRCNameFromList(iFileNo, mszFileNames, pvRTFCRC->pData, szServerName, sizeof(szServerName), szLocalName))) { // end of the list
break; }
// build full paths
lstrcpy(szLocalFile, szLocalDir); PathAppend(szLocalFile, szLocalName);
lstrcpy(szURL, g_v3state.GetRootServer()); UrlAppend(szURL, _T("CRCRtf")); UrlAppend(szURL, szServerName);
LOG_out("%s - %s", szURL, szLocalFile); pCallback(pCallbackParam, puid, T2W(szURL), T2W(szLocalFile));
} // for
}
// Cabs
TCHAR szLocalDir[MAX_PATH]; GetWindowsUpdateDirectory(szLocalDir); wsprintf(szLocalFile, _T("Cabs\\%d"), puid); // reuse szLocalFile as a temp buffer
PathAppend(szLocalDir, szLocalFile);
//See if the package has a server override defined.
PWU_VARIABLE_FIELD pvServer = pItem->pd->pv->Find(WU_DESCRIPTION_SERVERROOT); LPCTSTR pszCabPoolServer = pvServer ? A2T((LPSTR)(pvServer->pData)) : g_v3state.GetCabPoolServer();
PWU_VARIABLE_FIELD pvCabs = pItem->pd->pv->Find(WU_DESCRIPTION_CABFILENAME); PWU_VARIABLE_FIELD pvCRCs = pItem->pd->pv->Find(WU_DESC_CRC_ARRAY);
if (NULL == pvCabs || NULL == pvCRCs) { // Active setup items can have no cabs
if( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } else { for(int iCabNo = 0; true; iCabNo++) { TCHAR szLocalCab[128]; TCHAR szServerCab[128]; if (FAILED(GetCRCNameFromList(iCabNo, pvCabs->pData, pvCRCs->pData, szServerCab, sizeof(szServerCab) , szLocalCab))) break;
PathCombine(szLocalFile, szLocalDir, szLocalCab);
lstrcpy(szURL, pszCabPoolServer); UrlAppend(szURL, _T("CabPool")); UrlAppend(szURL, szServerCab);
LOG_out("%s - %s", szURL, szLocalFile); pCallback(pCallbackParam, puid, T2W(szURL), T2W(szLocalFile)); } }
} catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::GetCatalogArray(VARIANT *pCatalogArray) { LOG_block("CCV3::GetCatalogArray"); try { return MakeReturnCatalogArray(m_pCatalogAU, WU_UPDATE_ITEMS, 0, pCatalogArray); } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK;
}
STDMETHODIMP CCV3::SelectAllPuids() { LOG_block("CCV3::SelectAllPuids"); try { for(int nItem = 0; nItem < m_pCatalogAU->GetHeader()->totalItems; nItem ++) { PINVENTORY_ITEM pItem = m_pCatalogAU->GetItem(nItem); if (NULL == pItem) { continue; } if (! pItem->ps->bHidden && ( WU_TYPE_ACTIVE_SETUP_RECORD == pItem->recordType || WU_TYPE_CDM_RECORD == pItem->recordType || WU_TYPE_RECORD_TYPE_PRINTER == pItem->recordType ) && ( WU_ITEM_STATE_INSTALL == pItem->ps->state || WU_ITEM_STATE_UPDATE == pItem->ps->state )) { PUID puid = (WU_TYPE_ACTIVE_SETUP_RECORD == pItem->recordType) ? pItem->pf->a.puid : pItem->pf->d.puid; if (!IsPuidHidden(puid)) g_v3state.m_selectedItems.Select(puid, TRUE); } } } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::UnselectAllPuids() { LOG_block("CCV3::UnselectAllPuids"); try { g_v3state.m_selectedItems.Clear(); } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::SelectPuid(long puid) { LOG_block("CCV3::SelectPuid"); try { if (IsPuidHidden(puid)) throw E_INVALIDARG;
g_v3state.m_selectedItems.Select(puid, TRUE); } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::UnselectPuid(long puid) { LOG_block("CCV3::UnselectPuid"); try { if (IsPuidHidden(puid)) throw E_INVALIDARG;
g_v3state.m_selectedItems.Unselect(puid); } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
static void RemoveFiles(long puid, bool fCif) { TCHAR szBaseName[16]; TCHAR szLocalFile[MAX_PATH]; if (fCif) { wsprintf(szBaseName, _T("%d.cif"), puid); GetWindowsUpdateDirectory(szLocalFile); PathAppend(szLocalFile, szBaseName); DeleteFile(szLocalFile); }
wsprintf(szBaseName, _T("Cabs\\%d"), puid); GetWindowsUpdateDirectory(szLocalFile); PathAppend(szLocalFile, szBaseName); DeleteNode(szLocalFile);
wsprintf(szBaseName, _T("RTF\\%d"), puid); GetWindowsUpdateDirectory(szLocalFile); PathAppend(szLocalFile, szBaseName); DeleteNode(szLocalFile); }
STDMETHODIMP CCV3::HidePuid(long puid) { LOG_block("CCV3::HidePuid"); try { PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL)) return E_INVALIDARG;
// Hide it in catalog
pItem->ps->bHidden = TRUE; pItem->ps->dwReason = WU_STATE_REASON_BACKEND;
// Unselect it
g_v3state.m_selectedItems.Unselect(puid); HidePuidAndSave(puid);
RemoveFiles(puid, pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD); } catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::InstallSelectedPuids(void* pCallbackParam, PFN_InstallCallback pCallback) { LOG_block("CCV3::InstallSelectedPuids");
try { // Builds correct dependency array
Varray<DEPENDPUID> vFinalList; int cFinalList = 0; ProcessInstallList(vFinalList, cFinalList);
//output it
for (int nPuid = 0; nPuid < cFinalList; nPuid++) { PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(vFinalList[nPuid].puid, &pItem, NULL)) throw E_FAIL;
SELECTITEMINFO info; info.bInstall = TRUE; info.puid = vFinalList[nPuid].puid; info.iStatus = ITEM_STATUS_SUCCESS; info.hrError = S_OK; InstallItemAU(pItem, &info); LOG_out("%d status %d error %d(%08X)\n", info.puid, info.iStatus, info.hrError, info.hrError); pCallback(pCallbackParam, info.puid, info.iStatus, info.hrError); } } catch(HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
STDMETHODIMP CCV3::CleanupCabsAndReadThis(void) { LOG_block("CCV3::CleanupCabsAndReadThis");
TCHAR szCabDir[MAX_PATH]; GetWindowsUpdateDirectory(szCabDir); PathAppend(szCabDir, _T("Cabs")); DeleteNode(szCabDir);
CleanupReadThis(); return S_OK; }
STDMETHODIMP CCV3::UnhideAllPuids(void) { LOG_block("CCV3::CleanupCabsAndReadThis"); RegDeleteKey(HKEY_LOCAL_MACHINE, REGISTRYHIDING_KEY); return S_OK; }
STDMETHODIMP CCV3::StatusReport(long puid, LPCSTR pszStatus) { LOG_block("CCV3::StatusReport"); try { PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL)) { LOG_error("invalid arg"); return E_INVALIDARG; } CWUDownload dl(g_v3state.GetIdentServer(), 8192);
// build the URL with parameters
TCHAR szURL[INTERNET_MAX_PATH_LENGTH]; wsprintf(szURL, _T("wutrack.bin?PUID=%d&PLAT=%d&LOCALE=%s&STATUS=%s&RID=%4.4x%4.4x"), pItem->GetPuid(), m_pCatalogAU->GetPlatform(), m_pCatalogAU->GetMachineLocaleSZ(), pszStatus, rand(), rand());
// ping the URL and receive the response in memory
PVOID pMemBuf; ULONG ulMemSize; if (dl.QCopy(szURL, &pMemBuf, &ulMemSize)) { // we don't care about the response so we just free it
LOG_error("%s", szURL); V3_free(pMemBuf); } else { LOG_out("%s", szURL); } } catch (HRESULT hr) { LOG_error("error %08X", hr); } return S_OK; }
STDMETHODIMP CCV3::DownloadReadThisPage(long puid) { LOG_block("CCV3::DownloadReadThisPage"); LOG_out("puid = %d", puid); try { PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL)) { LOG_error("no item"); return E_INVALIDARG; }
return DownloadReadThis(pItem);
} catch (HRESULT hr) { LOG_error("error %08X", hr); return hr; } return S_OK; }
void CCV3::InstallItemAU(PINVENTORY_ITEM pItem, PSELECTITEMINFO pinfo) { LOG_block("CCV3::InstallItemAU"); try { GetCurTime(&(pinfo->stDateTime));
CDiamond diamond; // local directory
TCHAR szLocalDir[MAX_PATH]; GetWindowsUpdateDirectory(szLocalDir);
TCHAR szTmp[40]; wsprintf(szTmp, _T("Cabs\\%d"), pinfo->puid); PathAppend(szLocalDir, szTmp);
// Decompress cab files
PWU_VARIABLE_FIELD pvCabs = pItem->pd->pv->Find(WU_DESCRIPTION_CABFILENAME); PWU_VARIABLE_FIELD pvCRCs = pItem->pd->pv->Find(WU_DESC_CRC_ARRAY);
if (NULL != pvCabs && NULL != pvCRCs) { for(int iCabNo = 0; true; iCabNo++) { TCHAR szLocalCab[128]; TCHAR szLocalFile[MAX_PATH]; // we don't care about server file name
if (FAILED(GetCRCNameFromList(iCabNo, pvCabs->pData, pvCRCs->pData, szLocalFile, sizeof(szLocalFile), szLocalCab))) break;
PathCombine(szLocalFile, szLocalDir, szLocalCab); // check signature of the download CAB file
// Don't show MS cert.
// use the VerifyFile function (see WU bug # 12251)
HRESULT hr = VerifyFile(szLocalFile, FALSE); if (FAILED(hr)) throw hr;
if( pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD && diamond.IsValidCAB(szLocalFile)) diamond.Decompress(szLocalFile, _T("*")); } }
switch (pItem->recordType) { case WU_TYPE_ACTIVE_SETUP_RECORD: { TCHAR szCIFFile[MAX_PATH]; TCHAR szCifBaseName[16]; wsprintf(szCifBaseName, _T("%d.cif"), pItem->GetPuid()); GetWindowsUpdateDirectory(szCIFFile); PathAppend(szCIFFile, szCifBaseName);
// Decompress if we need to
if (diamond.IsValidCAB(szCIFFile)) { TCHAR szTmpCif[MAX_PATH]; lstrcpy(szTmpCif, szCIFFile); lstrcpy(szTmpCif, _T(".cab")); MoveFile(szCIFFile, szTmpCif); diamond.Decompress(szTmpCif, szCIFFile); DeleteFile(szTmpCif); } LOG_out("calling InstallActiveSetupItem(szLocalDir=%s, szCIFFile=%s) for puid %d", szLocalDir, szCIFFile, pinfo->puid); InstallActiveSetupItem(szLocalDir, szCIFFile, pinfo, NULL); } break;
case WU_TYPE_CDM_RECORD: LOG_out("calling InstallDriverItem(szLocalDir=%s) for puid %d", szLocalDir, pinfo->puid); InstallDriverItem(szLocalDir, IsWindowsNT(), _T(""), pItem, pinfo); break;
case WU_TYPE_RECORD_TYPE_PRINTER: { PWU_VARIABLE_FIELD pvDriverName = pItem->pv->Find(WU_CDM_DRIVER_NAME); PWU_VARIABLE_FIELD pvArchitecture = pItem->pv->Find(WU_CDM_PRINTER_DRIVER_ARCH); if (NULL == pvDriverName || NULL == pvArchitecture) throw E_UNEXPECTED; // should never happen
LOG_out("calling InstallPrinterItem(szDriverName=%s, szLocalDir=%s) for puid %d", (LPCTSTR)pvDriverName->pData, szLocalDir, pinfo->puid); InstallPrinterItem((LPCTSTR)pvDriverName->pData, szLocalDir, (LPCTSTR)pvArchitecture->pData); } break;
case WU_TYPE_CDM_RECORD_PLACE_HOLDER: case WU_TYPE_SECTION_RECORD: case WU_TYPE_SUBSECTION_RECORD: case WU_TYPE_SUBSUBSECTION_RECORD: default: LOG_error(" cannot install recordtype %d for puid %d", pItem->recordType, pinfo->puid); throw E_UNEXPECTED; } } catch(HRESULT hr) { pinfo->iStatus = ITEM_STATUS_FAILED; pinfo->hrError = hr; } // Cleanup
RemoveFiles(pItem->GetPuid(), pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD); UpdateInstallHistory(pinfo, 1); }
void CCV3::ReadHiddenPuids() { auto_hkey hKey; if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRYHIDING_KEY, 0, KEY_READ, &hKey)) { DWORD dwSize; if ( NO_ERROR == RegQueryValueEx(hKey, _T("AutoUpdateItems"), NULL, NULL, NULL, &dwSize) && dwSize > 0 ) { m_abHiddenPuids.resize(dwSize); if (NO_ERROR != RegQueryValueEx(hKey, _T("AutoUpdateItems"), NULL, NULL, m_abHiddenPuids, &dwSize)) m_abHiddenPuids.resize(0); } } PUID* ppuidHidden =(PUID*)(LPBYTE)m_abHiddenPuids; for(int nOffset = 0; nOffset < m_abHiddenPuids.size(); nOffset += sizeof(PUID)) { PINVENTORY_ITEM pItem; if (g_v3state.GetCatalogAndItem(*ppuidHidden, &pItem, NULL)) { // Hide it in catalog
pItem->ps->bHidden = TRUE; pItem->ps->dwReason = WU_STATE_REASON_BACKEND; } ppuidHidden ++; }
}
bool CCV3::IsPuidHidden(PUID puid) { PUID* ppuidHidden =(PUID*)(LPBYTE)m_abHiddenPuids; for(int nOffset = 0; nOffset < m_abHiddenPuids.size(); nOffset += sizeof(PUID)) { if (*ppuidHidden == puid) return true; ppuidHidden ++; } return false; }
void CCV3::HidePuidAndSave(PUID puid) { // Bug 378289
// The following block of reading the registry value and putting it into m_abHiddenPuids has been added.
// This is because, in the earlier case the m_abHiddenPuids would be read the first time from the registry
// and would hold on to the registry values.
// Due to this it would not reflect the new changes made by the user (eg. Clear History), and would write back the old values in m_abHiddenPuids back onto the registry
// By making the following change m_abHiddenPuids contains the updated registry values.
m_abHiddenPuids.resize(0); auto_hkey hKey; if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRYHIDING_KEY, 0, KEY_READ, &hKey)) { DWORD dwSize; if ( NO_ERROR == RegQueryValueEx(hKey, _T("AutoUpdateItems"), NULL, NULL, NULL, &dwSize) && dwSize > 0 ) { m_abHiddenPuids.resize(dwSize); if (NO_ERROR != RegQueryValueEx(hKey, _T("AutoUpdateItems"), NULL, NULL, m_abHiddenPuids, &dwSize)) m_abHiddenPuids.resize(0); } }
if (IsPuidHidden(puid)) return;
int cbSize = m_abHiddenPuids.size(); m_abHiddenPuids.resize(cbSize + sizeof(PUID)); *(PUID*)((LPBYTE)m_abHiddenPuids + cbSize) = puid;
DWORD dwDisposition; if (NO_ERROR == RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRYHIDING_KEY, 0, _T(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition)) { if (0 == m_abHiddenPuids.size()) { RegDeleteValue(hKey, _T("AutoUpdateItems")); } else { RegSetValueEx(hKey, _T("AutoUpdateItems"), 0, REG_BINARY, m_abHiddenPuids, m_abHiddenPuids.size()); } } }
|