windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wuv3is/cv3.cpp
2020-09-26 16:20:57 +08:00

3731 lines
93 KiB
C++

//=======================================================================
//
// Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
//
// File: cv3.cpp
//
// Purpose: V3 control main code
//
//=======================================================================
#include "stdafx.h"
#include "WUV3IS.h"
#include <stdio.h>
#include <initguid.h>
#include <inseng.h>
#include <shlwapi.h>
#define USEWUV3INCLUDES
#include <wuv3.h>
#undef USEWUV3INCLUDES
#include <winspool.h>
#include <cstate.h>
#include <wustl.h>
#include <osdet.h>
#include "printers.h"
#include "progress.h"
#include "newtrust.h"
#include "history.h"
#include "CV3.h"
#include "detect.h"
#include "callback.h"
#include "locstr.h"
#include "safearr.h"
#include "install.h"
#include "log.h"
#include "template.h"
#include "filecrc.h"
#include <shlguid.h>
#include <wininet.h>
#include <servpaus.h>
#include "..\..\inc\wuverp.h"
const TCHAR REGPATH_EXPLORER[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
const TCHAR REGKEY_WINUPD_DISABLED[] = _T("NoWindowsUpdate");
#define EXENAME_128BIT _T("128BIT.EXE")
//
// State management class. All retrieved catalogs are stored here. When the
// control exits then this class cleans up the memory used by each catalog
// stored with the state module. So the application must not delete any catalogs
// that have been added to state storage.
//
CState g_v3state;
TCHAR CCV3::s_szControlVer[20] = _T("\0");
void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath);
void DownloadFileVerInfo(CWUDownload* pDownload);
PBYTE DownloadOemInfo(CWUDownload *pDownload, CDiamond *pDiamond);;
void DownloadCabs(LPCTSTR szLocalDir, CWUDownload* pDownload, CDiamond* pDiamond, PBYTE pCabList, PBYTE pCRCList, IWUProgress* pProgress, BOOL bUnCab);
void DownloadCif(LPCTSTR szLocalDir, CDiamond* pDiamond, PINSTALLINFOSTRUCT pInstallInfo);
void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress);
void DetectPlatAndLang();
void DetectActiveSetupWU(CWUDownload* pDownload, CDiamond* pDiamond, CCatalog* pCatalog);
void DownloadItem(LPCTSTR pszLocalDir, CWUDownload *pDownload, CDiamond *pDiamond, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress);
void InstallItem(LPCTSTR pszLocalDir, PSELECTITEMINFO pStatusInfo, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress);
DWORD WINAPI RebootThreadProc(LPVOID pv);
void CheckDescDiagInfo(CCatalog* pCatalog);
bool IsArabicOrHebrew()
{
WORD wCurPrimeLang = PRIMARYLANGID(LOWORD(g_v3state.GetBrowserLocale()));
return LANG_HEBREW == wCurPrimeLang || LANG_ARABIC == wCurPrimeLang;
}
//
// CDescriptionMerger class
//
// a local class used to merge description files
//
class CDescriptionMerger
{
public:
CDescriptionMerger()
: m_pMap(NULL),
m_pDiamond(NULL)
{
}
~CDescriptionMerger()
{
if (m_pMap != NULL)
delete m_pMap;
if (m_pDiamond != NULL)
delete m_pDiamond;
}
HRESULT CheckMerge(PINSTALLINFOSTRUCT pInstallInfo);
private:
CCRCMapFile* m_pMap;
CDiamond* m_pDiamond;
HRESULT ReadMapFile(CCatalog* pCatalog);
};
//
// CCV3 class
//
// this function is called when our ref count becomes zero
void CCV3::FinalRelease()
{
LOG_block("CCV3::FinalRelease");
//
// reset state
//
g_v3state.Reset();
//
// make sure we undo registration of MS trust key if we registred it
//
CConnSpeed::WriteToRegistry();
}
// this function is called after our object is created, this is the prefered
// place to do initialization
HRESULT CCV3::FinalConstruct()
{
LOG_block("CCV3::FinalConstruct");
wsprintf(CCV3::s_szControlVer, _T("5,04,%d,%d"), VER_PRODUCTBUILD,VER_PRODUCTBUILD_QFE);
TCHAR szLogFN[MAX_PATH];
TCHAR szDate[50];
TCHAR szTime[50];
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, sizeof(szDate)/sizeof(szDate[0]));
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER, NULL, NULL, szTime, sizeof(szTime)/sizeof(szTime[0]));
LOG_out("Windows Update V3 Internet Site Control, Version %s",s_szControlVer);
LOG_out("Session starting %s at %s", szDate, szTime);
//
// set up the application log
//
GetWindowsUpdateDirectory(szLogFN);
lstrcat(szLogFN, HISTORY_FILENAME);
g_v3state.AppLog().SetLogFile(szLogFN);
CConnSpeed::ReadFromRegistry();
m_bValidInstance = FALSE;
//
// seed the random number generator
//
srand((int)GetTickCount());
return S_OK;
}
// The get catalog method retrieves a catalog array from the server. The get catalog method only
// accesses the server if the catalog is not already resident on the clients computer system.
// This allows the VB script page call this method to quickly obtain filtered catalog record information.
STDMETHODIMP CCV3::GetCatalog(
IN long puidCatalog,
IN BSTR bstrServerUrl,
IN long platformId,
IN BSTR bstrBrowserLanguage, // BUGBUG - why is browser locale a string and not a long
IN long lFilters,
IN long lFlags,
OUT RETVAL VARIANT *pCatalogArray
)
{
HRESULT hr;
CCatalog* pCatalog;
LOG_block("CCV3::GetCatalog");
try
{
pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags);
//If we are retrieving the sub-catalog list then the return VB script array
//needs to be different.
if (pCatalog->GetCatalogPuid() == WU_CATALOG_LIST_PUID)
{
hr = MakeReturnCatalogListArray(pCatalog, lFilters, lFlags, pCatalogArray);
if (FAILED(hr))
throw hr;
}
else
{
hr = MakeReturnCatalogArray(pCatalog, lFilters, lFlags, pCatalogArray);
if (FAILED(hr))
throw hr;
}
}
catch(HRESULT hr)
{
// create an empty array so that script doesn't throw a UBound error
LPSAFEARRAY psa;
SAFEARRAYBOUND rgsabound[2];
VariantInit(pCatalogArray);
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 0;
rgsabound[1].lLbound = 0;
rgsabound[1].cElements = 8;
psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
V_VT(pCatalogArray) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pCatalogArray) = psa;
// we can't return a failure code, because that prevents script from
// honoring the return value.
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CCV3::GetCatalogHTML(
IN long puidCatalog,
IN BSTR bstrServerUrl,
IN long platformId,
IN BSTR bstrBrowserLanguage,
IN long lFilters,
IN long lFlags,
OUT RETVAL VARIANT *pCatalogHTML
)
{
HRESULT hr;
CCatalog* pCatalog;
// we are currently not using the templates feature
// the code for this templates are wrapped in HTML_TEMPLATE define
#ifdef HTML_TEMPLATE
TRACE("GetCatalogHTML: %d", puidCatalog);
try
{
pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags);
hr = MakeCatalogHTML(pCatalog, lFilters, pCatalogHTML);
if (FAILED(hr))
throw hr;
}
catch(HRESULT hr)
{
return hr;
}
return S_OK;
#endif
return E_NOTIMPL;
}
/*
* The process catalog function constructs or retireves the requested
* V3 catalog. A pointer to the retrieved or constructed catalog is
* returned to the caller if successfull or an HRESULT error code is
* thrown if not.
*/
CCatalog *CCV3::ProcessCatalog(
IN PUID puidCatalog,
IN BSTR bstrServerUrl,
IN long platformId,
IN BSTR bstrBrowserLanguage,
IN long lFilters,
IN long lFlags
)
{
USES_CONVERSION;
CCdm cdm;
BOOL bCheckInNeeded;
CDiamond dm;
CBitmask bmAS;
CBitmask bmCDM;
CCatalog* pCatalog;
TCHAR szIdentServer[MAX_PATH];
char szBuffer[1024];
PINVENTORY_ITEM pCatalogItem;
int i;
HRESULT hr;
LOG_block("CCV3::ProcessCatalog");
LOG_out("puidCatalog = %d, bstrServerUrl = %s", puidCatalog, OLE2T(bstrServerUrl));
LOG_out("tick count is %d", GetTickCount());
// assume that the catalog is in state storage.
bCheckInNeeded = FALSE;
//
// if catalog is not already in state storage go retrieve and prune it.
//
if ( !(pCatalog = g_v3state.Get(puidCatalog)) )
{
if (NULL == bstrBrowserLanguage) // AutoUpdate
{
// We'll use this flag to determine whether to show UI when we call VerifyFile
g_v3state.m_nClient = WUV3_CLIENT_AUTOUPDATE;
LOG_out("Client Set to AutoUpdate");
LOG_out("Client is currently %s", (CWUDownload::s_fOffline) ? "Offline" : "Online");
}
//
// check if the ident server is trusted as well as read the valid server
// list from ident.cab into memory
//
lstrcpy(szIdentServer, OLE2T(bstrServerUrl));
RemoveLastSlash(szIdentServer);
g_v3state.CheckTrustedServer(szIdentServer, &dm);
//
// check the server the control was launch from. At this point the
// ident cab is already loaded
// this function will do the work only once and it will throw if
// the server is not valid
//
CheckLaunchServer();
//
// create a new catalog object
//
pCatalog = new CCatalog(g_v3state.GetContentServer(), puidCatalog);
if (NULL == pCatalog)
{
LOG_out("ProcessCatalog: Creation of new Catalog failed. GetLastError() = %d", GetLastError());
throw HRESULT_FROM_WIN32(GetLastError());
}
if (NULL != bstrBrowserLanguage) // AutoUpdate whould set it to NULL
{
pCatalog->SetBrowserLocale(OLE2T(bstrBrowserLanguage));
}
//
// Create a download object for the content
//
CWUDownload dl(pCatalog->GetCatalogServer(), 8192);
//
// read the catalog
//
pCatalog->Read(&dl, &dm);
//
// read the bitmask file
//
bmAS.Read(&dl, &dm, puidCatalog, BITMASK_ACTIVESETUP_TYPE, pCatalog->GetBitmaskName());
if (!g_v3state.m_pdwPlatformList)
{
TCHAR szOsdetServer[MAX_PATH];
lstrcpy(szOsdetServer, _T("OSDET."));
AppendExtForOS(szOsdetServer);
DownloadFileVerInfo(&dl);
DownloadDLL(&dm, &dl, szOsdetServer, NULL);
DetectPlatAndLang();
LOG_out("Platform %d", g_v3state.m_pdwPlatformList[0]);
LOG_out("Machine Language 0x%8.8x", GetMachineLangDW());
LOG_out("User UI Language 0x%8.8x", GetUserLangDW());
}
if (NULL == bstrBrowserLanguage) // AutoUpdate
{
// For Windows XP, AU can't use the system language - we need to use the MUI user language
//pCatalog->SetBrowserLocale(pCatalog->GetMachineLocaleSZ());
pCatalog->SetBrowserLocale(pCatalog->GetUserLocaleSZ());
}
if (puidCatalog == WU_CATALOG_LIST_PUID)
{
// inventory.plt is platform 0 by convention
pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]);
}
else
{
// normal inventory item sub catalog.
if (!platformId)
{
// if the caller did not pass in a platformId then we
// need to detect the current platform and use that value
// in the catalog. In this case we luck out since the first
// platform id returned from osdet.dll is the client machines platform.
pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]);
}
else
{
pCatalog->SetPlatform(platformId);
}
}
// inventory.plt catalog only does bitmask pruning
if ( puidCatalog == WU_CATALOG_LIST_PUID )
{
// if puidCatalog is 0 then we are retrieving the inventory.plt list of
// catalogs. We need to handle this catalog differently.
pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pdwPlatformList, g_v3state.m_iTotalPlatforms);
}
else
{
// we are retrieving a normal inventory catalog.
// since we need the OEM table to perform bitmask detection on an inventory catalog
// we first check to see if the oem table has already been read. If it has not we
// download. Note: We use full local caching on the OEM table. This is important for
// maximum performance.
if ( !g_v3state.m_pOemInfoTable ) //Pointer OEM info table that OEM detection needs.
{
byte_buffer bufOemInfo;
if (! DownloadToBuffer( _T("oeminfo.bin"), &dl, &dm, bufOemInfo))
throw HRESULT_FROM_WIN32(GetLastError());
g_v3state.m_pOemInfoTable = bufOemInfo.detach();
}
// perform active setup record bitmask pruning.
pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pOemInfoTable);
// since windows 95 & NT4.0 do not support PnP drivers we cannot add any device driver records.
//
// NOTE: The catalog.Prune() method hides the device driver insertion record. So we do not need
// to do anything if the OS does not allow device driver installations.
if (DoesClientPlatformSupportDrivers())
{
LOG_out("Support drivers on this platform");
// if there are device driver records to be added.
if ( pCatalog->GetRecordIndex(WU_TYPE_CDM_RECORD_PLACE_HOLDER) != -1 )
{
LOG_out("Have drivers on this platform");
// if there are no drivers for this platform
// the bitmask will be missing and the Read()
// method will throw. In this case, we do nothing.
try
{
bmCDM.Read(&dl, &dm, puidCatalog, BITMASK_CDM_TYPE, NULL);
cdm.CreateInventoryList(&bmCDM, &dl, &dm, puidCatalog, g_v3state.m_pOemInfoTable);
pCatalog->AddCDMRecords(&cdm);
}
catch(HRESULT hr)
{
LOG_out("ProcessCatalog: bitmask.cdm or inventory.cdm missing.");
}
}
else
{
LOG_out("Don't have drivers on this platform");
}
}
else
{
LOG_out("Don't support drivers on this platform");
}
pCatalog->ProcessExclusions(&dl);
//
// do active setup detection
//
DetectActiveSetupWU(&dl, &dm, pCatalog);
// perform catalog inventory link processing and use selected registry item hiding.
pCatalog->Prune();
}
if (puidCatalog == WU_CATALOG_LIST_PUID)
{
// description files for catalog list
//
// NOTE: With 3.1 we dropped the description fields for catalog list
// we fill the structure with blank descriptions
for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
{
continue;
}
if (pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED)
{
(void)pCatalog->BlankDescription(pCatalogItem);
}
}
}
else
{
//
// read descriptions for the catalog items
// 1. read gang description file
// 2. (pass 1) read individual descriptions for items that did not get descriptions by
// by using browser language
// 3. (pass 2) read individual descriptions for itmes that still did not get descriptions
// by using machine language
//
hr = pCatalog->ReadDescriptionGang(&dl, &dm);
// check to see if we need to download any individual descriptions
BOOL bNeedIndividual = FALSE;
if (FAILED(hr))
{
bNeedIndividual = TRUE;
}
else
{
for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
{
continue;
}
if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL))
{
// need to download it
bNeedIndividual = TRUE;
break;
}
} // for
}
for (int iPass = 1; iPass <= 2; iPass++)
{
if (!bNeedIndividual)
{
break;
}
hr = S_OK;
bNeedIndividual = FALSE;
//
// we need to download individual description files
//
TCHAR szMapFile[MAX_PATH];
TCHAR szMapFileLocal[MAX_PATH];
BYTE* pMapMem;
DWORD dwMapLen;
// build path for crc map file
wsprintf(szMapFile, _T("%d_%s.des"),
pCatalog->GetPlatform(),
(iPass == 1) ? pCatalog->GetBrowserLocaleSZ() : pCatalog->GetMachineLocaleSZ());
//because the map file name isn't a CRC, we can't guarantee that it is the right one - always delete and re-download
GetWindowsUpdateDirectory(szMapFileLocal);
lstrcat(szMapFileLocal, szMapFile);
if(!CWUDownload::s_fOffline)
{
DeleteFile(szMapFileLocal);
}
hr = DownloadFileToMem(&dl, szMapFile, &dm, &pMapMem, &dwMapLen);
if (SUCCEEDED(hr))
{
// create a crc map object with the memory image of the file
CCRCMapFile DescMap(pMapMem, dwMapLen);
CWUDownload dlRoot(g_v3state.GetRootServer(), 8192);
for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
{
continue;
}
if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL))
{
DWORD dwDisp = 0;
hr = pCatalog->ReadDescription(&dlRoot, &dm, pCatalogItem, &DescMap, &dwDisp);
if (FAILED(hr))
{
// description not found
if (iPass == 1)
{
bNeedIndividual = TRUE;
hr = S_OK;
}
else
{
switch(dwDisp)
{
case DISP_PUID_NOT_IN_MAP:
wsprintfA(szBuffer, "Puid #%d not found in map file - removing from catalog", pCatalogItem->GetPuid());
LOG_out(szBuffer);
pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED;
hr = S_OK;
break;
case DISP_DESC_NOT_FOUND:
wsprintfA(szBuffer, "Missing description file for puid #%d - removing from catalog", pCatalogItem->GetPuid());
LOG_out(szBuffer);
pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED;
hr = S_OK;
break;
}
break;
}
}
}
} // for i
V3_free(pMapMem);
}
else
{
if (iPass == 1)
{
bNeedIndividual = TRUE;
hr = S_OK;
}
}
} // for iPass
if (FAILED(hr))
{
throw hr;
}
#ifdef _WUV3TEST
// validate descriptions
CheckDescDiagInfo(pCatalog);
#endif // _WUV3TEST
}
bCheckInNeeded = TRUE;
LOG_out("catalog for %d NOT found in state cache, create it", puidCatalog);//added by wei
}
else //added by wei
{
LOG_out("catalog for %d found in state cache, return it", puidCatalog);
}
// in the case where the catalog is already in state storage we simply make
// the catalog array and return.
// NOTE: if this catalog came from state storage then there is no reason to check it in.
if (bCheckInNeeded)
{
// finally check the pruned catalog into state storage.
g_v3state.Add(puidCatalog, pCatalog);
}
// if we got here that also means that CheckLaunchServer has validated us
// mark this instance as a valid one
m_bValidInstance = TRUE;
return pCatalog;
}
STDMETHODIMP CCV3::ChangeItemState(
IN long puid,
IN long lNewItemState
)
{
HRESULT hrRet = S_OK;
try
{
hrRet = ProcessChangeItemState(puid, lNewItemState);
}
catch (HRESULT hr)
{
hrRet = hr;
}
return hrRet;
}
HRESULT CCV3::ProcessChangeItemState(
IN long puid,
IN long lNewItemState
)
{
HKEY hKey;
BOOL bChanged;
int i;
int iTotalItems;
Varray<PINVENTORY_ITEM> pItemList;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
//if the requested state is SELECT by itself, we default to SELECT | INSTAL
if (lNewItemState == ITEM_STATE_SELECT_ITEM)
{
lNewItemState = ITEM_STATE_SELECT_ITEM | ITEM_STATE_INSTALL_ITEM;
}
if (!(iTotalItems = g_v3state.GetItemList(puid, pItemList)))
{
TRACE("ChangeItemState called with invalid PUID %d", puid);
return E_INVALIDARG;
}
bChanged = FALSE;
for (i = 0; i < iTotalItems; i++)
{
//
// show/hide
//
if (lNewItemState & ITEM_STATE_HIDE_ITEM)
{
if ( !pItemList[i]->ps->bHidden )
{
pItemList[i]->ps->bHidden = TRUE;
bChanged = TRUE;
}
}
else if (lNewItemState & ITEM_STATE_SHOW_ITEM)
{
if ( pItemList[i]->ps->bHidden )
{
pItemList[i]->ps->bHidden = FALSE;
bChanged = TRUE;
}
}
//
// select
//
if (lNewItemState & ITEM_STATE_SELECT_ITEM)
{
// default is to select the item for install.
if (lNewItemState & ITEM_STATE_INSTALL_ITEM)
{
if (!pItemList[i]->ps->bChecked )
{
pItemList[i]->ps->bChecked = TRUE;
bChanged = TRUE;
g_v3state.m_selectedItems.Select(puid, TRUE);
}
}
if ( lNewItemState & ITEM_STATE_REMOVE_ITEM )
{
// remove only removes requested item.
g_v3state.m_selectedItems.Select(puid, FALSE);
bChanged = TRUE;
}
}
//
// unselect
//
if ( lNewItemState & ITEM_STATE_UNSELECT_ITEM )
{
if ( pItemList[i]->ps->bChecked )
{
if (pItemList[i]->ps->bChecked )
{
pItemList[i]->ps->bChecked = FALSE;
bChanged = TRUE;
}
// add item and all of its dependent items to selected items array.
// remove item from selected items array.
//
// NOTE: This will only remove the item
// if the select count is 0.
g_v3state.m_selectedItems.Unselect(puid);
}
}
//
// personalize hide/unhide
//
if (lNewItemState & ITEM_STATE_PERSONALIZE_HIDE)
{
pItemList[i]->ps->bHidden = TRUE;
pItemList[i]->ps->dwReason = WU_STATE_REASON_PERSONALIZE;
bChanged = RegistryHidingUpdate(puid, TRUE);
}
if (lNewItemState & ITEM_STATE_PERSONALIZE_UNHIDE)
{
bChanged = RegistryHidingUpdate(puid, FALSE);
if (bChanged)
{
pItemList[i]->ps->bHidden = FALSE;
pItemList[i]->ps->dwReason = WU_STATE_REASON_NONE;
}
}
}
if (!bChanged)
return E_INVALIDARG;
return S_OK;
}
int __cdecl SortComparePriority(const void* p1, const void* p2)
{
DWORD d1 = ((DEPENDPUID*)p1)->dwPriority;
DWORD d2 = ((DEPENDPUID*)p2)->dwPriority;
// reverse order compare
if (d1 > d2)
return -1;
else if (d1 < d2)
return +1;
else
return 0;
}
// Now sort if by priority
static Varray<PUID> g_vPuidParent;
static int g_cPuidParent;
void ListDependenciesFirst(Varray<DEPENDPUID>& vInitList, int cInitList, Varray<DEPENDPUID>& vFinalList, int& cFinalList)
{
// sort initial list
if (cInitList > 1)
qsort((void *)(&vInitList[0]), cInitList, sizeof(DEPENDPUID), SortComparePriority);
for (int iInitList = 0; iInitList < cInitList; iInitList++)
{
// check if we are in the parent array;
for (int i = 0; i < g_cPuidParent; i++)
{
if (g_vPuidParent[i] == vInitList[iInitList].puid)
break;
}
if (i != g_cPuidParent)
continue; // didn't get to the very end
// Get catalog
CCatalog* pCatalog;
PINVENTORY_ITEM pItem;
if (!g_v3state.GetCatalogAndItem(vInitList[iInitList].puid, &pItem, &pCatalog))
{
continue;
}
// Get dependancies
Varray<DEPENDPUID> vTmpList;
int cTmpList = 0;
pCatalog->GetItemDirectDependencies(pItem, vTmpList, cTmpList);
if (cTmpList)
{
// set vInitList[iList].pTopLevelItem, for them
for(int j = 0; j < cTmpList; j ++)
{
if (NULL == vInitList[iInitList].pTopLevelItem)
vTmpList[j].pTopLevelItem = pItem;
else
vTmpList[j].pTopLevelItem = vInitList[iInitList].pTopLevelItem;
}
// prepend them
g_vPuidParent[g_cPuidParent ++] = vInitList[iInitList].puid;
ListDependenciesFirst(vTmpList, cTmpList, vFinalList, cFinalList);
g_cPuidParent --;
}
// Check if it's included by now
for (i = 0; i < cFinalList; i++)
{
if (vFinalList[i].puid == vInitList[iInitList].puid)
break;
}
if (i != cFinalList)
continue; // didn't get to the very end
// now add the item if it's not there
vFinalList[cFinalList ++] = vInitList[iInitList];
}
}
void ProcessInstallList(Varray<DEPENDPUID>& vFinalList, int& cFinalList)
{
LOG_block("CCV3::ProcessInstallList");
PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems();
int cSel = g_v3state.m_selectedItems.GetTotal();
if (cSel == 0)
return;
// Build selection list
Varray<DEPENDPUID> vSelectList;
int cSelectList = 0;
DEPENDPUID d = {0};
for (int iSel = 0; iSel < cSel; iSel++)
{
d.puid = pSel[iSel].puid;
d.puidParent = 0;
d.pTopLevelItem = NULL; // that is important
CCatalog* pCatalog;
PINVENTORY_ITEM pItem;
if (!g_v3state.GetCatalogAndItem(d.puid, &pItem, &pCatalog))
{
continue;
}
// look up priority and add the item to the array
d.dwPriority = 0;
PWU_VARIABLE_FIELD pvPri = pItem->pd->pv->Find(WU_DESC_INSTALL_PRIORITY);
if (pvPri != NULL)
d.dwPriority = *((DWORD*)(pvPri->pData));
vSelectList[cSelectList ++] = d;
}
// build final list
g_cPuidParent = 0;
ListDependenciesFirst(vSelectList, cSelectList, vFinalList, cFinalList);
//
// now, clear the select and reselect the items (including dependendcies) for installation in order
//
g_v3state.m_selectedItems.Clear();
for (int i = 0; i < cFinalList; i++)
{
LOG_out("Final List %d Pri=%d Parent=%d TopLevel=%s",
vFinalList[i].puid, vFinalList[i].dwPriority,
vFinalList[i].puidParent, (vFinalList[i].pTopLevelItem == NULL ? "NULL" : "Not NULL"));
// select the item
g_v3state.m_selectedItems.Select(vFinalList[i].puid, TRUE);
}
}
STDMETHODIMP CCV3::InstallSelectedItems(
IN BSTR bstrUnused, //Server Directory if blank then the server used with the catalog was retrieved is used.
IN long lFlags, //Flags currently only WU_NOSPECIAL_FLAGS and WU_COPYONLY_NO_INSTALL supported.
IN BSTR bstrNotUsed,
OUT RETVAL VARIANT *pResultsArray
)
{
LOG_block("CCV3::InstallSelectedItems");
int iTotalItems = 0;
TCHAR szTempDir[MAX_PATH];
TCHAR szLocalDir[MAX_PATH];
CDiamond dm;
PSELECTITEMINFO pInfo = NULL;
Varray<INSTALLINFOSTRUCT> InstallArr;
int InstallCnt = 0;
DWORD dwTotalBytes = 0;
Varray<DEPENDPUID> vFinalList;
int cFinalList = 0;
int i;
int t;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
try
{
CWUProgress Progress(_Module.GetModuleInstance());
CServPauser ServPauser;
CDescriptionMerger DescMerger;
g_v3state.m_bRebootNeeded = FALSE;
//
// process depenendencies and priorities of the item
//
ProcessInstallList(vFinalList, cFinalList);
iTotalItems = g_v3state.m_selectedItems.GetTotal();
pInfo = g_v3state.m_selectedItems.GetItems();
// pause task scheduler
ServPauser.PauseTaskScheduler();
//
// go thru all the selected items and build the InstallArr
//
for (i = 0, InstallCnt = 0; i < iTotalItems; i++)
{
if (pInfo[i].bInstall)
{
if (!g_v3state.GetCatalogAndItem(pInfo[i].puid, &InstallArr[InstallCnt].pItem, &InstallArr[InstallCnt].pCatalog))
{
continue;
}
//
// remove the "Checked" status from the item
//
InstallArr[InstallCnt].pItem->ps->bChecked = FALSE;
dwTotalBytes += (InstallArr[InstallCnt].pItem->pd->size * 1024);
//
// create download objects. We use the GetCabPoolServer to get the server.for cabpool
// we create objects for only one element and assign pdl of each install element to this object
//
// NOTE: We are ignoring the szServer passed in and we will eventually remove it from interface
//
if (InstallCnt == 0)
{
TRACE("InstallSelectedItems: creating download objects for %s and %s", g_v3state.GetCabPoolServer(), InstallArr[0].pCatalog->GetCatalogServer());
InstallArr[0].bServerNew = TRUE;
InstallArr[0].pdl = new CWUDownload(g_v3state.GetCabPoolServer(), 8192);
InstallArr[0].pdlRoot = new CWUDownload(g_v3state.GetRootServer(), 8192);
}
else
{
InstallArr[InstallCnt].pdl = InstallArr[0].pdl;
InstallArr[InstallCnt].pdlRoot = InstallArr[0].pdlRoot;
InstallArr[InstallCnt].bServerNew = FALSE;
}
InstallArr[InstallCnt].pInfo = &pInfo[i];
GetCurTime(&(InstallArr[InstallCnt].pInfo->stDateTime));
InstallArr[InstallCnt].pInfo->iStatus = ITEM_STATUS_FAILED; //init to failed
InstallArr[InstallCnt].iSelIndex = i;
InstallArr[InstallCnt].dwLocaleID = 0; // use systems
InstallArr[InstallCnt].dwPlatform = 0; // use systems
InstallArr[InstallCnt].bHistoryWritten = FALSE;
InstallArr[InstallCnt].bDownloaded = FALSE;
InstallArr[InstallCnt].pTopLevelItem = NULL;
//
// if the item is hidden, set the pTopLevelItem using the dependcies list
//
if (InstallArr[InstallCnt].pItem->ps->bHidden)
{
PUID puidDep = InstallArr[InstallCnt].pItem->GetPuid();
//
//check puidDep, i.e. check if the function GetPuid() is returning valid info
//
if (puidDep > 0)
{
for (int iDep = 0; iDep < cFinalList; iDep++)
{
if (vFinalList[iDep].puid == puidDep)
{
InstallArr[InstallCnt].pTopLevelItem = vFinalList[iDep].pTopLevelItem;
break;
}
}
}
}
//
// merge the descriptions if machine/browser languages are different so that
// we have the correct installation information based on machine language
//
BLOCK
{
HRESULT hr = DescMerger.CheckMerge(&InstallArr[InstallCnt]);
if (FAILED(hr))
{
TRACE("Failed while mergeing description");
throw hr;
}
}
InstallCnt++;
}
}
//
// get the directory where we will download CABs
//
GetWindowsUpdateDirectory(szTempDir);
AddBackSlash(szTempDir);
Progress.StartDisplay();
Progress.SetDownloadTotal(dwTotalBytes);
Progress.SetInstallTotal(InstallCnt * 3);
//
// Create directory for and download each item
//
for (i = 0; i < InstallCnt; i++)
{
wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid);
V3_CreateDirectory(szLocalDir);
InstallArr[i].bDownloaded = TRUE; //assume the download will be fine
try
{
DownloadItem(szLocalDir, InstallArr[i].pdl, &dm, &InstallArr[i], &Progress);
}
catch (HRESULT hr)
{
InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED;
InstallArr[i].bDownloaded = FALSE;
//
// check to see if the Cancel button was pressed
//
if (WaitForSingleObject(Progress.GetCancelEvent(), 0) == WAIT_OBJECT_0)
throw hr;
}
// even though the download for this item has succeeded, we reset the status to 'failed'
// until we actually finish the installation
InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED;
}
Progress.SetDownload(); //100%
//
// Install each package and delete its directory
//
for (i = 0; i < InstallCnt; i++)
{
wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid);
Progress.SetInstallAdd(1);
if (InstallArr[i].bDownloaded)
{
// if this is an exclusive component, hide the install progress. We assume
// that, apart from dependencies, this will be the only component being installed
// since it is by definition exclusive. In that case, this will be the last component
// and install progress will be hidden so that the component's own setup UI is displayed
if (InstallArr[i].pItem->pd->flags & DESCRIPTION_EXCLUSIVE)
{
Progress.SetStyle(CWUProgress::ProgStyle::OFF);
}
// install the item
InstallItem(szLocalDir, InstallArr[i].pInfo, &InstallArr[i], &Progress);
}
Progress.SetInstallAdd(1);
DeleteNode(szLocalDir);
UpdateInstallHistory(InstallArr[i].pInfo, 1);
InstallArr[i].bHistoryWritten = TRUE;
if ((InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS) || (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED))
{
//update item status to CURRENT
InstallArr[i].pItem->ps->state = WU_ITEM_STATE_CURRENT;
//indicate that a reboot is required
if (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED)
g_v3state.m_bRebootNeeded = TRUE;
}
//remove the selected flag from the item
InstallArr[i].pItem->ps->bChecked = FALSE;
Progress.SetInstallAdd(1);
}
Progress.SetInstall(); //100%
// create return array
MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray);
// remove all items from selected items
g_v3state.m_selectedItems.Clear();
// close server connections
for (i = 0; i < iTotalItems; i++)
{
if (InstallArr[i].bServerNew)
{
delete InstallArr[i].pdl;
delete InstallArr[i].pdlRoot;
}
}
Progress.EndDisplay();
// delete any cached readthisfirst pages
CleanupReadThis();
}
catch (HRESULT hr)
{
if (pInfo != NULL)
{
// create return array
MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray);
}
else
{
return hr;
}
//
// if there was an error, we don't want to reboot
//
g_v3state.m_bRebootNeeded = FALSE;
//
// remove all items from m_selected
//
g_v3state.m_selectedItems.Clear();
// close server connections
for (i = 0; i < iTotalItems; i++)
{
if (InstallArr[i].bServerNew)
{
delete InstallArr[i].pdl;
delete InstallArr[i].pdlRoot;
}
if (!InstallArr[i].bHistoryWritten)
UpdateInstallHistory(InstallArr[i].pInfo, 1);
}
// delete any cached readthisfirst pages
CleanupReadThis();
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CCV3::GetInstallMetrics(
OUT RETVAL VARIANT *pMetricsArray
)
{
PSELECTITEMINFO pInfo;
PINVENTORY_ITEM pItem;
int iTotalSelectedItems;
try
{
iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal();
pInfo = g_v3state.m_selectedItems.GetItems();
MakeInstallMetricArray(pInfo, iTotalSelectedItems, pMetricsArray);
}
catch(HRESULT hr)
{
return hr;
}
return S_OK;
}
STDMETHODIMP CCV3::GetEula(
OUT RETVAL VARIANT *pEulaArray
)
{
PSELECTITEMINFO pInfo;
PINVENTORY_ITEM pItem;
int i;
int iTotalSelectedItems;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
try
{
//
// Walk though item array for each install item. Each item selected for installation
// is store in a puid array that is part of the g_v3state class. This is a performance
// enhancement. If we did not do this then we would need to walk through the entire
// state structure for each catalog for every item and check it's installation state.
//
iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal();
pInfo = g_v3state.m_selectedItems.GetItems();
MakeEulaArray(pInfo, iTotalSelectedItems, pEulaArray);
}
catch(HRESULT hr)
{
return hr;
}
return S_OK;
}
STDMETHODIMP CCV3::GetInstallHistory(
OUT RETVAL VARIANT *pHistoryArray
)
{
int i;
int iTotalItems;
Varray<HISTORYSTRUCT> History;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
try
{
//
// Walk though item array for each install item. Each item selected for installation
// is store in a puid array that is part of the g_v3state class. This is a performance
// enhancement. If we did not do this then we would need to walk through the entire
// state structure for each catalog for every item and check it's installation state.
//
ReadHistory(History, iTotalItems);
MakeInstallHistoryArray(History, iTotalItems, pHistoryArray);
}
catch(HRESULT hr)
{
return hr;
}
return S_OK;
}
STDMETHODIMP CCV3::GetDependencyList(
IN long puid,
OUT RETVAL VARIANT *pDependentItemsArray
)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::GetCatalogItem(
IN long puid,
OUT RETVAL VARIANT *pCatalogItem
)
{
PINVENTORY_ITEM pItem;
HRESULT hrRet = S_OK;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
try
{
if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL))
hrRet = E_INVALIDARG;
else
hrRet = MakeReturnItemArray(pItem, pCatalogItem);
}
catch (HRESULT hr)
{
hrRet = hr;
}
return hrRet;
}
BOOL ConfirmUninstall(PINVENTORY_ITEM pItem)
{
USES_CONVERSION;
PWU_VARIABLE_FIELD pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
//
// Prefix bug NTBUG9#114181 warning (25): bounds violation (overflow) using buffer 'szResStr'
//
TCHAR szResStr[512];
if (LoadString(_Module.GetModuleInstance(), IDS_UNINSTALLCHECK, szResStr, sizeof(szResStr)/sizeof(TCHAR)) == 0)
{
TRACE("Unable to get resource string for uninstall check");
return FALSE;
}
TCHAR szMsg[1024];
wsprintf(szMsg, szResStr, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T(""));
DWORD dwMBFlags = MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_SETFOREGROUND;
if (IsArabicOrHebrew())
dwMBFlags |= MB_RTLREADING | MB_RIGHT;
if (MessageBox(GetActiveWindow(), szMsg, GetLocStr(IDS_APP_TITLE), dwMBFlags) != IDOK)
{
return FALSE;
}
return TRUE;
}
// confirms reboot, cleans up and reboot using a thread
BOOL CleanupAndReboot()
{
TCHAR szBuf[512];
// NOTE: we assume that GetLocStr will not return strings that will overflow this buffer
wsprintf(szBuf, _T("%s\n\n%s"), GetLocStr(IDS_REBOOT1), GetLocStr(IDS_REBOOT2));
// adadi Oct 6, 1999: arabic + hebrew hack
// we need to add the RTL flag if we're running on loc, but not enabled BIDI systems
// we don't want the dialog flipped with EN text on an enabled system
DWORD dwMBFlags = MB_ICONQUESTION | MB_YESNO | MB_TASKMODAL | MB_SETFOREGROUND;
if (IsArabicOrHebrew())
dwMBFlags |= MB_RTLREADING | MB_RIGHT;
UINT id = MessageBox(GetActiveWindow(), szBuf, GetLocStr(IDS_APP_TITLE), dwMBFlags);
if (id == IDNO)
return FALSE;
// cleanup
g_v3state.Reset();
CConnSpeed::WriteToRegistry();
// create a thread to reboot
DWORD dwThreadID;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RebootThreadProc, NULL, 0, &dwThreadID);
if (hThread != NULL)
{
// we close the handle because we don't need it. The thread will be destroyed after threadproc terminates
CloseHandle(hThread);
}
return TRUE;
}
DWORD WINAPI RebootThreadProc(LPVOID pv)
{
// Wait for 1 second and reboot the system
Sleep(1000);
(void)V3_RebootSystem();
return 0;
}
STDMETHODIMP CCV3::RemoveSelectedItems()
{
USES_CONVERSION;
PSELECTITEMINFO pInfo;
PINVENTORY_ITEM pItem;
PWU_VARIABLE_FIELD pvUninstall;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
try
{
//we need the os type for any device driver installs.
int iTotalItems = g_v3state.m_selectedItems.GetTotal();
HRESULT hr = NOERROR;
g_v3state.m_bRebootNeeded = FALSE;
pInfo = g_v3state.m_selectedItems.GetItems();
for (int i=0; i<iTotalItems; i++)
{
if (!pInfo[i].bInstall)
{
//
// if item has been selected for removal...
// confirm that the user wants to install the item. The user will be prompted
// for each uninstall
//
if (!g_v3state.GetCatalogAndItem(pInfo[i].puid, &pItem, NULL))
{
continue;
}
if (!ConfirmUninstall(pItem))
{
// do not uninstall this item
continue;
}
GetCurTime(&(pInfo[i].stDateTime));
if (pItem->recordType == WU_TYPE_CDM_RECORD)
{
hr = UninstallDriverItem(pItem, &pInfo[i]);
}
else
{
pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY);
if (pvUninstall != NULL)
{
//
// its possible that uninstall will reboot. We have no way of knowing that
// so we set the status initially to ITEM_STATUS_UNINSTALL_STARTED which
// gets translated to "Started" entry in the log
//
pInfo[i].iStatus = ITEM_STATUS_UNINSTALL_STARTED;
UpdateRemoveHistory(&pInfo[i], 1);
hr = UninstallActiveSetupItem(A2T((LPSTR)pvUninstall->pData));
}
else
{
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
pInfo[i].iStatus = ITEM_STATUS_SUCCESS;
pInfo[i].hrError = NOERROR;
pItem->ps->state = WU_ITEM_STATE_INSTALL;
}
else
{
pInfo[i].iStatus = ITEM_STATUS_INSTALLED_ERROR;
pInfo[i].hrError = hr;
//Fix #736: we leave the item state unchanged if the uninstall fails
}
pItem->ps->bChecked = FALSE;
//
// write history log for final status. We will write only the error case for active setup
// items which have already written "Started". For drivers we do not write the "Started"
// entry so we will write the history now for both success and failure
//
if (pItem->recordType == WU_TYPE_CDM_RECORD || pInfo[i].iStatus == ITEM_STATUS_INSTALLED_ERROR)
{
UpdateRemoveHistory(&pInfo[i], 1);
}
}
}
//
// remove all items from m_selected
//
g_v3state.m_selectedItems.Clear();
//
// reboot if an uninstall has indicated that we have to reboot
//
if (g_v3state.m_bRebootNeeded)
{
(void)CleanupAndReboot();
}
g_v3state.m_bRebootNeeded = FALSE;
}
catch(HRESULT _hr)
{
g_v3state.m_bRebootNeeded = FALSE;
return _hr;
}
return S_OK;
}
//
// NOTE: This method is no longer supported. We simply return S_OK for compatibility. We will remove
// this method
//
STDMETHODIMP CCV3::IsCatalogAvailable(
IN long puidCatalog, //Name of catalog to be read from the server.
IN BSTR bstrServerUrl //The http://servername/share location for the catalog to be retrieved.
)
{
HRESULT hr = S_OK;
return hr;
}
STDMETHODIMP CCV3::FinalizeInstall(IN long lFlags)
{
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
if (lFlags & FINALIZE_DOREBOOT)
{
if (g_v3state.m_bRebootNeeded)
{
(void)CleanupAndReboot();
}
}
g_v3state.m_bRebootNeeded = FALSE;
return NOERROR;
}
STDMETHODIMP CCV3::SetStrings(IN VARIANT* vStringsArr, IN long lType)
{
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
return SetStringsFromSafeArray(vStringsArr, lType);
}
STDMETHODIMP CCV3::FixCompatRollbackKey(VARIANT_BOOL *pbRegModified)
{
const TCHAR* pszIEVersionRegKey = _T("Software\\Microsoft\\Internet Explorer");
const TCHAR* pszIEUserAgentCompatKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\User Agent\\Post Platform");
const TCHAR* pszIEVersionRegValueName = _T("Version");
const TCHAR* pszIEUserAgentCompatValueName = _T("compat");
TCHAR szIEVersionValue[40];
DWORD dwDataType = 0;
DWORD dwDataLength = sizeof(szIEVersionValue);
HKEY IEVerKey = NULL;
HKEY IEUserAgentKey = NULL;
*pbRegModified = FALSE;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
//check the version key first - we don't care what the UA string says unless we have rolled back to IE4
if(ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszIEVersionRegKey, 0, KEY_QUERY_VALUE, &IEVerKey))
{
if(ERROR_SUCCESS == RegQueryValueEx(IEVerKey,pszIEVersionRegValueName,0,&dwDataType, (LPBYTE)szIEVersionValue,&dwDataLength))
{
if (szIEVersionValue[0] == '4') //check whether the first character is "4"
{
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,pszIEUserAgentCompatKey,0,KEY_SET_VALUE, &IEUserAgentKey))
{
if(ERROR_SUCCESS == RegDeleteValue(IEUserAgentKey,pszIEUserAgentCompatValueName))
{
*pbRegModified = TRUE;
}
RegCloseKey(IEUserAgentKey);
}
}
else // otherwise, this is IE5 - we'll piggyback another reg change onto this function
{
UpdateToolsURL();
}
}
RegCloseKey(IEVerKey);
}
return S_OK;
}
void CCV3::UpdateToolsURL()
{
LOG_block("UpdateToolsURL");
const TCHAR DEFAULT_WU_URL[] = _T("http://windowsupdate.microsoft.com/");
const TCHAR WU_TOOLMENU_PARAM[] = _T("IE");
const TCHAR REGKEY_IE_URLS[] = _T("Software\\Microsoft\\Internet Explorer\\Help_Menu_Urls");
const TCHAR REGVALUENAME_WU_URL[] = _T("3");
const TCHAR REGKEY_WU_URL[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate");
const TCHAR REGVALUENAME_WU_Start_URL[] = _T("URL");
const TCHAR WU_STARTMENU_PARAM[] = _T("Start");
HKEY hkIEURLKey = 0;
HKEY hkWUURLKey = 0;
DWORD dwDisposition = REG_OPENED_EXISTING_KEY;
TCHAR tszUpdateURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
TCHAR tszStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
TCHAR tszNewStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
wsprintf( tszUpdateURL, _T("%s?%s"), DEFAULT_WU_URL, WU_TOOLMENU_PARAM );
if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_IE_URLS, 0, (LPTSTR)NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkIEURLKey, &dwDisposition ) )
{
if( ERROR_SUCCESS == RegSetValueEx( hkIEURLKey, REGVALUENAME_WU_URL, 0, REG_SZ, (LPBYTE) tszUpdateURL, lstrlen(tszUpdateURL) * sizeof(TCHAR) ) )
{
LOG_out("Updated Tools URL to %s", tszUpdateURL);
}
RegCloseKey( hkIEURLKey );
}
//take the existing WU regkey and make sure it has "?Start" appended to it
// this will misbehave in the following two cases:
// 1) if the URL key exists but is invalid (such as spaces) - can only hapen if a user manually edits the key
// 2) if the URL contains a fragment (# + parameter)
// both of these will result in a start menu URL that is invalid. (the Start Menu link would be broken already if either of these cases existed)
if (NO_ERROR == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WU_URL, 0, (LPTSTR)NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | KEY_READ, NULL, &hkWUURLKey, &dwDisposition ))
{
DWORD dwSize = sizeof(tszStartMenuURL);
(void) RegQueryValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, 0, (LPBYTE)&tszStartMenuURL, &dwSize);
if(0 != lstrcmp(tszStartMenuURL, _T(""))) // if the reg value isn't blank
{
LOG_out("Current Start Menu URL: %s", tszStartMenuURL);
if( NULL == _tcsstr(tszStartMenuURL, _T("?"))) // if there isn't already a querystring on the URL, make the url currenturl?param
{
wsprintf(tszNewStartMenuURL, _T("%s?%s"), tszStartMenuURL, WU_STARTMENU_PARAM);
RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL);
}
else // if there's already a parameter
{
if(NULL != _tcsstr(tszStartMenuURL, WU_STARTMENU_PARAM))//if it already has "Start", bail
{
// do nothing
}
else//otherwise make the url currenturl?param&newparam
{
wsprintf(tszNewStartMenuURL, _T("%s&%s"), tszStartMenuURL, WU_STARTMENU_PARAM);
RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL);
}
}
}
else // if the reg value is blank, use the default WU URL + "?Start"
{
wsprintf(tszNewStartMenuURL, _T("%s?%s"), DEFAULT_WU_URL, WU_STARTMENU_PARAM);
RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
LOG_out("Updated Start Menu URL to %s", tszNewStartMenuURL);
}
RegCloseKey(hkWUURLKey);
}
}
// This function converts our internal V3 catalog structure into a safearray of variants
// that the VBScript web page uses. The format of the safe array will be:
// array(i,0) = NUMBER puid
// array(i,1) = STRING TITLE
// array(i,2) = STRING Description
// array(i,3) = NUMBER Item Status
// array(i,4) = NUMBER Download Size in Bytes
// array(i,5) = NUMBER Download Time in seconds
// array(i,6) = STRING Uninstall Key
// array(i,7) = STRING Read This Url
HRESULT CCV3::MakeReturnCatalogArray(
CCatalog *pCatalog, //Pointer to catalog structure to be converted.
long lFilters, //Filters to apply, see GetCatalog for the actual descriptions.
long lFlags, //Flags that control the amount of information returned in each array record.
VARIANT *pvaVariant //pointer to returned safearray.
)
{
USES_CONVERSION;
PUID puid;
PWSTR pTitle;
PWSTR pDescription;
PSTR pUninstall;
PWSTR pReadThisUrl;
HRESULT hr;
LPVARIANT rgElems;
LPSAFEARRAY psa;
SAFEARRAYBOUND rgsabound[2];
PINVENTORY_ITEM pItem;
PWU_VARIABLE_FIELD pv;
PWU_VARIABLE_FIELD pvTitle;
PWU_VARIABLE_FIELD pvDescription;
PWU_VARIABLE_FIELD pvUninstall;
PWU_VARIABLE_FIELD pvRTF;
PWU_VARIABLE_FIELD pvAltName;
int i;
int t;
int size;
int downloadTime;
TCHAR szRTF[MAX_PATH];
if ( !pvaVariant )
return E_INVALIDARG;
VariantInit(pvaVariant);
hr = NOERROR;
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 0;
rgsabound[1].lLbound = 0;
rgsabound[1].cElements = 8;
// count number records to return
for(i=0; i<pCatalog->GetHeader()->totalItems; i++)
{
pItem = pCatalog->GetItem(i);
if (NULL == pItem)
{
continue;
}
if ( !FilterCatalogItem(pItem, lFilters) )
continue;
rgsabound[0].cElements++;
}
psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
if (!psa)
return E_OUTOFMEMORY;
// plug references to the data into the SAFEARRAY
if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems)))
return hr;
for(i = 0, t = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
pItem = pCatalog->GetItem(i);
if (NULL == pItem)
{
continue;
}
if (!FilterCatalogItem(pItem, lFilters))
{
TRACE("Filtering (%d) skipped PUID %d while building SaveArray", lFilters, pItem->GetPuid());
continue;
}
if (!pItem->pd)
{
TRACE("PUID %d skipped while building SaveArray - no description", pItem->GetPuid());
continue;
}
size = pItem->pd->size;
downloadTime = CalcDownloadTime(size, pItem->pd->downloadTime);
pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid);
if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) )
pTitle = (PWSTR)pvTitle->pData;
else
pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR
if (pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION))
pDescription = (PWSTR)pvDescription->pData;
else
pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR
// uninstall/altname field
pUninstall = ""; // SafeArray should return empty string, not NULL BSTR
if (pItem->recordType == WU_TYPE_CDM_RECORD)
{
//NOTE: we are simply returning a key that says script should put the uninstall button
// currently we will always display this button but we will change this to only
// display it when the driver can be uninstalled
pUninstall = "DriverUninstall";
}
else if (pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD)
{
if ((pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY)))
{
pUninstall = (char *)pvUninstall->pData;
}
}
else
{
// for everything else, we pass the AltName field if provided
if ((pvAltName = pItem->pd->pv->Find(WU_DESC_ALTNAME)))
{
pUninstall = (char *)pvAltName->pData;
}
}
// read this first page
if ((pvRTF = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY)))
{
TCHAR szTemp[MAX_PATH];
GetWindowsUpdateDirectory(szTemp);
wsprintf(szRTF, _T("file://%sRTF\\%d\\%d.htm"), szTemp, pItem->GetPuid(), pItem->GetPuid());
pReadThisUrl = szRTF;
}
else
{
pReadThisUrl = _T(""); // SafeArray should return empty string, not NULL BSTR
}
try
{
TRACE("PUID %d added to SaveArray with ReturnStatus %d", pItem->GetPuid(), GetItemReturnStatus(pItem));
/*
// Noisy Debug Only
TRACE("\t%S",pTitle);
TRACE("\t%S", pDescription);
TRACE("\t%d", GetItemReturnStatus(pItem));
TRACE("\t%d", size);
TRACE("\t%d", downloadTime);
TRACE("\t%s", pUninstall);
TRACE("\t%s", pReadThisUrl);
*/
AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements,
"%d%s%s%d%d%d%s%s",
puid,
pTitle,
pDescription,
GetItemReturnStatus(pItem),
size,
downloadTime,
A2W(pUninstall),
pReadThisUrl);
t++;
}
catch(HRESULT hr)
{
TRACE("Exception thrown calling AddSafeArrayRecord");
for (; t; t--)
DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d%d%d%s%s");
SafeArrayUnaccessData(psa);
VariantInit(pvaVariant);
throw hr;
}
}
SafeArrayUnaccessData(psa);
V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvaVariant) = psa;
return NOERROR;
}
// This function converts our internal V3 catalog structure for inventory.plt catalogs into a
// safearray of variants that the VBScript web page uses. The format of the safe array will be:
// array(i,0) = NUMBER puid
// array(i,1) = STRING TITLE
// array(i,2) = STRING Description
// array(i,3) = NUMBER Item Status
HRESULT CCV3::MakeReturnCatalogListArray(
CCatalog *pCatalog, //Pointer to catalog structure to be converted.
long lFilters, //Filters to apply, see GetCatalog for the actual descriptions.
long lFlags, //Flags that control the amount of information returned in each array record.
VARIANT *pvaVariant //pointer to returned safearray.
)
{
PUID puid;
PWSTR pTitle;
PWSTR pDescription;
HRESULT hr;
LPVARIANT rgElems;
LPSAFEARRAY psa;
SAFEARRAYBOUND rgsabound[2];
PINVENTORY_ITEM pItem;
PWU_VARIABLE_FIELD pv;
PWU_VARIABLE_FIELD pvTitle;
PWU_VARIABLE_FIELD pvDescription;
PWU_VARIABLE_FIELD pvUninstall;
int i;
int t;
int size;
int downloadTime;
if ( !pvaVariant )
return E_INVALIDARG;
VariantInit(pvaVariant);
hr = NOERROR;
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 0;
rgsabound[1].lLbound = 0;
rgsabound[1].cElements = 4;
// count number records to return
for(i=0; i<pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pItem = pCatalog->GetItem(i)))
{
continue;
}
if ( !FilterCatalogItem(pItem, lFilters) )
continue;
rgsabound[0].cElements++;
}
psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
if ( !psa )
return E_OUTOFMEMORY;
// plug references to the data into the SAFEARRAY
if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems)))
return hr;
for(i=0,t=0; i<pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pItem = pCatalog->GetItem(i)))
{
continue;
}
if ( !FilterCatalogItem(pItem, lFilters) )
continue;
//array(i,0) = NUMBER puid
//array(i,1) = STRING TITLE
//array(i,2) = STRING Description
//array(i,3) = NUMBER Item Status
pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid);
if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) )
pTitle = (PWSTR)pvTitle->pData;
else
pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR
if ( pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION) )
pDescription = (PWSTR)pvDescription->pData;
else
pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR
try
{
AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d",
puid, pTitle, pDescription, GetItemReturnStatus(pItem));
t++;
}
catch(HRESULT hr)
{
for (; t; t--)
DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d");
SafeArrayUnaccessData(psa);
VariantInit(pvaVariant);
throw hr;
}
}
SafeArrayUnaccessData(psa);
V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pvaVariant) = psa;
return NOERROR;
}
void DetectActiveSetupWU(
CWUDownload* pDownload, // CWUDLOAD download class to be used to download detection DLLs.
CDiamond* pDiamond, // Diamond Expansion class.
CCatalog* pCatalog // catalog that detection CIF is to be created from.
)
{
USES_CONVERSION;
int cItemsDetected = 0;
PWU_VARIABLE_FIELD pVar;
DWORD dwDetectStatus;
CComponentDetection CompDet;
LOG_block("DetectActiveSetupWU");
//check input argument if valid
if (NULL == pCatalog)
{
return ;
}
for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
PINVENTORY_ITEM pItem = pCatalog->GetItem(i);
//check if the function GetItem has returned valid value
if (NULL == pItem)
{
continue;
}
if (pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD || (pItem->ps->state == WU_ITEM_STATE_PRUNED))
continue;
if (!IsValidGuid(&pItem->pf->a.g))
continue;
WCHAR wszGuid[64];
if (StringFromGUID2(pItem->pf->a.g, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0])) == 0)
continue;
PUID puid = pItem->GetPuid();
LOG_out("puid %d", puid);
if (puid <= 0)
{
continue;
}
//
// we have a valid component to detect
//
cItemsDetected++;
// guid
CompDet.SetValue(CComponentDetection::ccGUID, W2A(wszGuid));
// version
char szVersion[64];
VersionToString(&pItem->pf->a.version, szVersion);
CompDet.SetValue(CComponentDetection::ccVersion, szVersion);
//
// detection dll variable fields
//
char szDllName[128];
szDllName[0] = '\0';
if (pItem->pv->Find(WU_DETECT_DLL_REG_KEY_EXISTS))
{
// WUDETECT.DLL,RegKeyExists special case
CompDet.SetValue(CComponentDetection::ccDetectVersion, "wudetect.dll,RegKeyExists");
strcpy(szDllName, "wudetect.bin");
}
if ((pVar = pItem->pv->Find(WU_DETECT_DLL_GENERIC)))
{
LPSTR ptr;
// generic detection DLL including WUDETECT.DLL,RegKeyVersion case
CompDet.SetValue(CComponentDetection::ccDetectVersion, (LPCSTR)pVar->pData);
// parse out detection dll name from DetectVersion= value
if ((ptr = (PSTR)_memccpy(szDllName, (char *)pVar->pData, '.', sizeof(szDllName))))
{
*(ptr - 1) = 0;
}
strcat(szDllName, ".bin");
}
//
// download the dll. Download DLL takes care of caching
//
if (szDllName[0] != '\0')
{
TCHAR szPath[MAX_PATH];
// construct full path for the detection dll
wsprintf(szPath, _T("Detect/%d/%s"), pCatalog->GetPlatform(), A2T(szDllName));
DownloadDLL(pDiamond, pDownload, A2T(szDllName), szPath);
}
//
// other variable length fields
//
if ((pVar = pItem->pv->Find(WU_KEY_CUSTOMDETECT)))
{
// custom data
CompDet.SetValue(CComponentDetection::ccCustomData, (LPCSTR)pVar->pData);
}
if ((pVar = pItem->pv->Find(WU_KEY_UNINSTALLKEY)))
{
// UninstallKey, remove quotes first
char szKeyVal[MAX_PATH];
LPCSTR pszKeyDat = (LPCSTR)pVar->pData;
if (pszKeyDat[0] == '"')
{
strcpy(szKeyVal, (pszKeyDat + 1));
int iKenLen = strlen(szKeyVal);
if (iKenLen > 0)
szKeyVal[iKenLen - 1] = '\0';
}
else
{
strcpy(szKeyVal, pszKeyDat);
}
CompDet.SetValue(CComponentDetection::ccUninstallKey, szKeyVal);
}
// locale
if (!(pVar = pItem->pv->Find(WU_DET_CIF_LOCALE)))
{
CompDet.SetValue(CComponentDetection::ccLocale, "*");
}
else
{
CompDet.SetValue(CComponentDetection::ccLocale, (LPCSTR)pVar->pData);
}
/*
DEBUG CODE ONLY
LOG_out("[%d]", pItem->GetPuid());
char buf[512];
if (CompDet.GetValue(CComponentDetection::ccGUID, buf, sizeof(buf))) LOG_out("%s=%s", "GUID", buf);
if (CompDet.GetValue(CComponentDetection::ccVersion, buf, sizeof(buf))) LOG_out("%s=%s", "Version", buf);
if (CompDet.GetValue(CComponentDetection::ccUninstallKey , buf, sizeof(buf))) LOG_out("%s=%s", "UninstallKey", buf);
if (CompDet.GetValue(CComponentDetection::ccDetectVersion, buf, sizeof(buf))) LOG_out("%s=%s", "DetectVersion", buf);
if (CompDet.GetValue(CComponentDetection::ccRegKeyVersion , buf, sizeof(buf))) LOG_out("%s=%s", "RegKeyVersion", buf);
if (CompDet.GetValue(CComponentDetection::ccLocale , buf, sizeof(buf))) LOG_out("%s=%s", "Locale", buf);
if (CompDet.GetValue(CComponentDetection::ccQFEVersion , buf, sizeof(buf))) LOG_out("%s=%s", "QFEVersion", buf);
if (CompDet.GetValue(CComponentDetection::ccCustomData , buf, sizeof(buf))) LOG_out("%s=%s", "CustomData", buf);
*/
//
// now detect the item
//
dwDetectStatus = CompDet.Detect();
switch (dwDetectStatus)
{
case ICI_NOTINSTALLED: // 0 = item not installed(INSTALL)
pItem->ps->state = WU_ITEM_STATE_INSTALL;
LOG_out("puid %d not installed", pItem->GetPuid());
break;
case ICI_INSTALLED: // 1 = this item is curretly installed
pItem->ps->state = WU_ITEM_STATE_CURRENT;
LOG_out("puid %d installed current version", pItem->GetPuid());
break;
case ICI_NEWVERSIONAVAILABLE: // 2 Items is installed but newer available
pItem->ps->state = WU_ITEM_STATE_UPDATE;
{ // we want to save currently installed version
DWORD dwInstalledVer;
DWORD dwInstalledBuild;
CompDet.GetInstalledVersion(&dwInstalledVer, &dwInstalledBuild);
pItem->ps->verInstalled.major = HIWORD(dwInstalledVer);
pItem->ps->verInstalled.minor = LOWORD(dwInstalledVer);
pItem->ps->verInstalled.build = HIWORD(dwInstalledBuild);
pItem->ps->verInstalled.ext = LOWORD(dwInstalledBuild);
LOG_out("puid %d installed version %d.%d.%d.%d and new version available ", pItem->GetPuid(),
pItem->ps->verInstalled.major, pItem->ps->verInstalled.minor, pItem->ps->verInstalled.build, pItem->ps->verInstalled.ext);
}
break;
case ICI_UNKNOWN: // 3 cannot be determined
case ICI_OLDVERSIONAVAILABLE: // 4 Why would anyone want to install the older version?
case ICI_NOTINITIALIZED: // 0xffffffff
default:
pItem->ps->bHidden = TRUE;
pItem->ps->state = WU_ITEM_STATE_PRUNED;
LOG_out("puid %d should be ignored and hidden", pItem->GetPuid());
break;
}
} // each item
LOG_out("%d items were detected", cItemsDetected);
}
void DownloadItem(
LPCTSTR pszLocalDir, //directory to download to. Must be created by caller
CWUDownload* pDownload, //Pointer to internet download class
CDiamond* pDiamond, //Pointer to compression class
PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure.
IWUProgress* pProgress
)
{
USES_CONVERSION;
BYTE itemFlags = 0;
BOOL bCloseConnection = FALSE;
DWORD platformId;
HRESULT hrError;
PWU_VARIABLE_FIELD pvCabs = NULL;
PWU_VARIABLE_FIELD pvCRCs = NULL;
PWU_VARIABLE_FIELD pvServer;
PWU_VARIABLE_FIELD pvTmp;
TCHAR szLocale[64];
BOOL b128Bit;
//Check if the input argument is not NULL
if ( (NULL == pInstallInfo) || (NULL == pInstallInfo->pItem) )
{
return ;
}
//See if the package has a server override defined.
if ((pvServer = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_SERVERROOT)))
{
pDownload = new CWUDownload((LPCTSTR)pvServer->pData);
bCloseConnection = TRUE;
}
try
{
if (pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
{
// if the item is hidden, look for the title in the TopLevel item
if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL))
{
PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
if (pvTopLvl)
{
pvTmp = pvTopLvl;
}
}
pProgress->SetStatusText(W2T((LPWSTR)(pvTmp->pData)));
}
//
// Calculate CIF path
//
pInstallInfo->pItem->GetFixedFieldInfo(WU_ITEM_FLAGS, &itemFlags);
// locale
if (pInstallInfo->dwLocaleID == 0)
{
if (itemFlags & WU_BROWSER_LANGAUGE_FLAG)
{
lstrcpy(szLocale, pInstallInfo->pCatalog->GetBrowserLocaleSZ());
}
else
{
wsprintf(szLocale, _T("0x%8.8x"), GetMachineLangDW());
}
}
else
{
wsprintf(szLocale, _T("0x%8.8x"), pInstallInfo->dwLocaleID);
}
// platform
if (pInstallInfo->dwPlatform == 0)
platformId = pInstallInfo->pCatalog->GetPlatform();
else
platformId = pInstallInfo->dwPlatform;
pInstallInfo->pInfo->iStatus = ITEM_STATUS_DOWNLOAD_COMPLETE;
pInstallInfo->pInfo->hrError = NOERROR;
//
// download files
//
if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD ||
pInstallInfo->pItem->recordType == WU_TYPE_CDM_RECORD ||
pInstallInfo->pItem->recordType == WU_TYPE_RECORD_TYPE_PRINTER)
{
b128Bit = FALSE;
if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD)
{
//download CIF
DownloadCif(pszLocalDir, pDiamond, pInstallInfo);
// check for 128 bit
if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
{
b128Bit = TRUE;
}
}
if (b128Bit)
{
// download 128 bit components
Download128Bit(pszLocalDir, pInstallInfo->pItem, pProgress);
}
else
{
// download install CABs
pvCabs = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_CABFILENAME);
pvCRCs = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CRC_ARRAY);
if (NULL == pvCabs || NULL == pvCRCs)
{
// Active setup items can have no cabs
if( pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD)
throw HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}
else
{
DownloadCabs(pszLocalDir,
pDownload,
pDiamond,
(PBYTE)pvCabs->pData,
(PBYTE)pvCRCs->pData,
pProgress,
pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD);
}
}
}
else
{
throw E_UNEXPECTED;
}
}
catch(HRESULT hr)
{
//
// download failed
//
pInstallInfo->pInfo->hrError = hr;
pInstallInfo->pInfo->iStatus = ITEM_STATUS_FAILED;
if (bCloseConnection)
{
delete pDownload;
}
//
// ping URL to report failure
//
if (pInstallInfo->pTopLevelItem == NULL)
{
// for top level components only
URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ? URLPING_CANCELED : URLPING_FAILED);
}
throw hr;
}
if (bCloseConnection)
{
delete pDownload;
}
//
// ping URL to report success
//
if (pInstallInfo->pTopLevelItem == NULL)
{
URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, URLPING_SUCCESS);
}
}
// this function perform and installation of a catalog item. This function takes care
// of ensuring that the correct installer is called based on the package type.
void InstallItem(
LPCTSTR pszLocalDir, //Local client machine root directory the temp storage
PSELECTITEMINFO pStatusInfo, //Pointer to installation status array
PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure.
IWUProgress* pProgress
)
{
HRESULT hrError;
PWU_VARIABLE_FIELD pvTitle;
PWU_VARIABLE_FIELD pvTmp;
TCHAR szCIFFile[MAX_PATH];
BOOL bWindowsNT;
//check the input arguments
if (NULL == pszLocalDir || NULL == pStatusInfo || NULL == pInstallInfo)
{
return;
}
bWindowsNT = IsWindowsNT();
try
{
if (pvTitle = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
{
// if the item is hidden, look for the title in the TopLevel item
if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL))
{
PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
if (pvTopLvl)
{
pvTitle = pvTopLvl;
}
}
pProgress->SetStatusText(W2T((LPWSTR)(pvTitle->pData)));
}
GetCurTime(&(pStatusInfo->stDateTime));
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS;
pStatusInfo->hrError = NOERROR;
TRACE("InstallItem, puid=%d, recordtype: %d", pInstallInfo->pItem->GetPuid(), (DWORD)pInstallInfo->pItem->recordType);
switch (pInstallInfo->pItem->recordType)
{
case WU_TYPE_ACTIVE_SETUP_RECORD:
BLOCK
{
TCHAR szCifBaseName[16];
wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid());
GetWindowsUpdateDirectory(szCIFFile);
lstrcat(szCIFFile, szCifBaseName);
}
//
// check to see if inseng is up to date (only done once)
//
CheckDllsToJit(pInstallInfo->pCatalog->GetCatalogServer());
//
// install active setup item
//
if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
{
// 128 bit
TCHAR szCmd[MAX_PATH];
long lRet;
lstrcpy(szCmd, pszLocalDir);
AddBackSlash(szCmd);
lstrcat(szCmd, EXENAME_128BIT);
lRet = LaunchProcess(szCmd, NULL, SW_NORMAL, TRUE);
}
else
{
InstallActiveSetupItem(pszLocalDir, szCIFFile, pStatusInfo, pProgress);
}
// delete CIF file
DeleteFile(szCIFFile);
break;
case WU_TYPE_CDM_RECORD:
InstallDriverItem(pszLocalDir, bWindowsNT, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T(""), pInstallInfo->pItem, pStatusInfo);
break;
case WU_TYPE_RECORD_TYPE_PRINTER:
{
PWU_VARIABLE_FIELD pvDriverName = pInstallInfo->pItem->pv->Find(WU_CDM_DRIVER_NAME);
PWU_VARIABLE_FIELD pvArchitecture = pInstallInfo->pItem->pv->Find(WU_CDM_PRINTER_DRIVER_ARCH);
if (NULL == pvDriverName)
throw E_UNEXPECTED; // should never happen
InstallPrinterItem((LPCTSTR)pvDriverName->pData, pszLocalDir,
NULL == pvArchitecture ? NULL : (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:
throw E_UNEXPECTED;
}
if(ITEM_STATUS_FAILED == pStatusInfo->iStatus)
{
URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED);
}
else
{
URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_SUCCESS);
}
}
catch(HRESULT hr)
{
pStatusInfo->hrError = hr;
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED);
}
}
//
// Download128Bit
// this shouldn't get called anymore since the US lifted export restrictions on 128 bit items:
// we don't create items with the 128 bit flag anymore
//
void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress)
{
USES_CONVERSION;
static const TCHAR FAILUREURL[] = _T("about:blank");
static const TCHAR FORMDATA[] = _T("selProdID=%s&Next=Download+Now%%21&failureURL=%s");
CWUDownload* pDL = NULL;
TCHAR szFormData[MAX_PATH];
TCHAR szLocalFile[MAX_PATH];
PWU_VARIABLE_FIELD pvTmp;
DWORD dwErr = ERROR_SUCCESS;
// get product id
if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
// build form data
wsprintf(szFormData, FORMDATA, A2T((LPSTR)pvTmp->pData), FAILUREURL);
// get URL
if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_URL)))
throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
// build local file name
lstrcpy(szLocalFile, pszLocalDir);
AddBackSlash(szLocalFile);
lstrcat(szLocalFile, EXENAME_128BIT);
// create download class
pDL = new CWUDownload(A2T((LPSTR)pvTmp->pData), 8192);
if (!pDL)
{
dwErr = GetLastError();
throw HRESULT_FROM_WIN32(dwErr);
}
if (!pDL->PostCopy(szFormData, szLocalFile, pProgress))
{
dwErr = GetLastError();
}
delete pDL;
if (dwErr != ERROR_SUCCESS)
throw HRESULT_FROM_WIN32(dwErr);
}
void DownloadCabs(
LPCTSTR szLocalDir, //Local client machine directory to use for temp storage
CWUDownload *pDownload, //Pointer to internet download class
CDiamond *pDiamond, //Pointer to compression class
PBYTE pCabList, //Multi SZ list of cabs to be downloaded.
PBYTE pCRCList, //array to CRC hash structures
IWUProgress* pProgress,
BOOL bUnCab
)
{
TCHAR szLocalFile[MAX_PATH];
TCHAR szServerFile[MAX_PATH];
TCHAR szLocalCab[128];
TCHAR szServerCab[128];
int iCabNo = 0;
V3_CreateDirectory(szLocalDir);
for (;;)
{
if (FAILED(GetCRCNameFromList(iCabNo, pCabList, pCRCList, szServerCab, sizeof(szServerCab), szLocalCab)))
break;
// build full paths
lstrcpy(szLocalFile, szLocalDir);
AddBackSlash(szLocalFile);
lstrcat(szLocalFile, szLocalCab);
lstrcpy(szServerFile, _T("CabPool/"));
lstrcat(szServerFile, szServerCab);
TRACE("Downloading %s", szServerFile);
if (!pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, 0, pProgress))
{
TRACE("Download of cab %s failed", szServerFile);
throw HRESULT_FROM_WIN32(GetLastError());
}
//
// check signature of the download CAB file
// Don't show an MS cert
// use VerifyFile (see WU bug # 12251)
//
HRESULT hr = VerifyFile(szLocalFile, TRUE);
TRACE("VerifyFile(%s) Result: %x (%s)", szLocalFile, hr, SUCCEEDED(hr) ? "SUCCESS" : "FAILURE");
if (FAILED(hr))
throw hr;
if (bUnCab)
{
if (pDiamond->IsValidCAB(szLocalFile))
{
TCHAR szUnCompFn[MAX_PATH];
lstrcpy(szUnCompFn, szLocalDir);
AddBackSlash(szUnCompFn);
lstrcat(szUnCompFn, _T("*"));
pDiamond->Decompress(szLocalFile, szUnCompFn);
//
// delete the CAB file after uncompressing
//
DeleteFile(szLocalFile);
}
}
iCabNo++;
}
}
void DownloadCif(
LPCTSTR szLocalDir, // Local client machine directory to use for temp storage
CDiamond *pDiamond, // Pointer to compression class
PINSTALLINFOSTRUCT pInstallInfo
)
{
V3_CreateDirectory(szLocalDir);
PWU_VARIABLE_FIELD pvCif = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CIF_CRC);
if (!pvCif)
{
TRACE("CIF CRC field missing");
throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
TCHAR szCifBaseName[16];
wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid());
TCHAR szCifCRCName[64];
HRESULT hr = MakeCRCName(szCifBaseName, (WUCRC_HASH*)pvCif->pData, szCifCRCName, sizeof(szCifCRCName));
if (FAILED(hr))
throw hr;
// create a temp file name for the .CIF file with .CI$
TCHAR szLocalFile[MAX_PATH];
TCHAR szServerFile[MAX_PATH];
lstrcpy(szLocalFile, szLocalDir);
AddBackSlash(szLocalFile);
lstrcat(szLocalFile, szCifBaseName);
LPTSTR pszDot = _tcschr(szLocalFile, _T('.'));
if (pszDot)
*pszDot = _T('\0');
lstrcat(szLocalFile, _T(".CI$"));
// server file name
wsprintf(szServerFile, _T("CRCCif/%s"), szCifCRCName);
if (!pInstallInfo->pdlRoot->Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL))
{
TRACE("Download of CIF cab %s failed", szServerFile);
throw HRESULT_FROM_WIN32(GetLastError());
}
// copy or uncompress to a .CIF file name
TCHAR szTemp[MAX_PATH];
GetWindowsUpdateDirectory(szTemp);
lstrcat(szTemp, szCifBaseName);
if (pDiamond->IsValidCAB(szLocalFile))
{
pDiamond->Decompress(szLocalFile, szTemp);
}
else
{
CopyFile(szLocalFile, szTemp, FALSE);
}
// NOTE:we don't delete the .CI$ file because all the files in the directory get deleted later
}
// download and save the FileVer.ini file in the cache
//
// NOTE: For 3.1 filever.ini file contains image download information as well
void DownloadFileVerInfo(CWUDownload* pDownload)
{
// if the file is missing, we don't have version information but we do not abort
(void)pDownload->Copy(FILEVERINI_FN, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL);
}
void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath)
{
//
// check our state detection dlls array to see if we downloaded
// this dll in this session already
//
// NOTE: We store the file name of the DLL as it is on the server OSDET.W98, wudetect.bin etc
//
TCHAR szDLLIn[MAX_PATH];
GetWindowsUpdateDirectory(szDLLIn);
lstrcat(szDLLIn, pszDLLName);
TCHAR szDLLOut[MAX_PATH];
lstrcpy(szDLLOut, szDLLIn);
TCHAR* ptr = _tcschr(szDLLOut, _T('.'));
if (ptr)
*ptr = 0;
lstrcat(szDLLOut, _T(".dll"));
if (g_v3state.CacheDLLName(pszDLLName))
{
//added by wei for test
TRACE("%s found in state cache", pszDLLName);
// doublecheck to make sure the DLL hasn't been deleted before we bail
if (FileExists(szDLLOut))
{
return;
}
}
//
// download the file
//
if (pszPath != NULL)
{
if (!pDownload->Copy(pszPath, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL))
throw HRESULT_FROM_WIN32(GetLastError());
}
else
{
if (!pDownload->Copy(pszDLLName, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL))
throw HRESULT_FROM_WIN32(GetLastError());
}
CConnSpeed::Learn(pDownload->GetCopySize(), pDownload->GetCopyTime());
//
// check to see if we download the file or the cached copy was used. If cache was used
// we just check to see if the DLL itself also exists, if yes then we return otherwise we
// will copy the or decompress the compressed file into the DLL
//
if (pDownload->CacheUsed())
{
if (FileExists(szDLLOut))
return;
}
if (pDiamond->IsValidCAB(szDLLIn))
pDiamond->Decompress(szDLLIn, szDLLOut);
else
CopyFile(szDLLIn, szDLLOut, FALSE);
}
void DetectPlatAndLang()
{
TCHAR szOSDETDLL[MAX_PATH];
GetWindowsUpdateDirectory(szOSDETDLL);
lstrcat(szOSDETDLL, _T("osdet.dll"));
//
// do platform and langauge detection using Osdet
//
CallOsDet(szOSDETDLL, &g_v3state.m_pdwPlatformList, &g_v3state.m_iTotalPlatforms);
//If we fail for any reason then use the default platform def_plat.
if ( !g_v3state.m_pdwPlatformList )
{
g_v3state.m_pdwPlatformList = (PULONG)&g_v3state.m_DefPlat;
g_v3state.m_iTotalPlatforms = 1;
}
}
//
// IObjectSafety
//
STDMETHODIMP CCV3::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
{
if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
return E_POINTER;
HRESULT hr = S_OK;
if (riid == IID_IDispatch)
{
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
*pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
}
else
{
*pdwSupportedOptions = 0;
*pdwEnabledOptions = 0;
hr = E_NOINTERFACE;
}
return hr;
}
STDMETHODIMP CCV3::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
{
// If we're being asked to set our safe for scripting option then oblige
if (riid == IID_IDispatch)
{
// Store our current safety level to return in GetInterfaceSafetyOptions
m_dwSafety = dwEnabledOptions & dwOptionSetMask;
return S_OK;
}
return E_NOINTERFACE;
}
//
// IWUpdateCatalog interface
//
STDMETHODIMP CCV3::WUIsCatalogAvailable(long puidCatalog,BSTR bstrServerUrl)
{
return IsCatalogAvailable(puidCatalog, bstrServerUrl);
}
STDMETHODIMP CCV3::WUGetCatalog(long puidCatalog, BSTR bstrServerUrl, long platformId,
BSTR bstrBrowserLanguage, CCatalog** ppCatalogArray)
{
// we don't want to check the launch server from this interface
m_bLaunchServChecked = TRUE;
*ppCatalogArray = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, WU_ALL_ITEMS, WU_NO_PRUNING);
return S_OK;
}
STDMETHODIMP CCV3::WUDownloadItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::WUInstallItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::WURemoveItems(CSelections* pSelections)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::WUCopyInstallHistory(HISTORYARRAY** ppHistoryArray)
{
int iTotalItems;
Varray<HISTORYSTRUCT> History;
PHISTORYARRAY pRetArray;
//Walk though item array for each install item. Each item selected for installation
//is store in a puid array that is part of the g_v3state class. This is a performance
//enhancement. If we did not do this then we would need to walk through the entire
//state structure for each catalog for every item and check it's installation state.
ReadHistory(History, iTotalItems);
//Since we must use the OLE allocator we now need to allocate the correct
//type of return memory and copy the existing history structure to it.
pRetArray = (PHISTORYARRAY)CoTaskMemAlloc(sizeof(HISTORYARRAY)+(iTotalItems * sizeof(HISTORYSTRUCT)));
if (NULL == pRetArray)
{
return HRESULT_FROM_WIN32(GetLastError());
}
pRetArray->iTotalItems = iTotalItems;
memcpy((char *)pRetArray->HistoryItems, &History[0], (iTotalItems * sizeof(HISTORYSTRUCT)));
*ppHistoryArray = pRetArray;
return S_OK;
}
STDMETHODIMP CCV3::WUCopyDependencyList(long puidItem, long** ppDepPui)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::WUProgressDlg(BOOL bOn)
{
return E_NOTIMPL;
}
STDMETHODIMP CCV3::IsWinUpdDisabled(VARIANT_BOOL * pfDisabled)
{
*pfDisabled = FALSE;
if (!m_bValidInstance)
{
return E_ACCESSDENIED;
}
bool fDisabled = false;
HKEY hKey;
DWORD dwDisabled;
DWORD dwSize = sizeof(dwDisabled);
DWORD dwType;
HKEY hkeyRoot = IsWindowsNT() ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
if ( RegOpenKeyEx( hkeyRoot,
REGPATH_EXPLORER,
NULL,
KEY_QUERY_VALUE,
&hKey) == ERROR_SUCCESS )
{
if ( RegQueryValueEx(hKey,
REGKEY_WINUPD_DISABLED,
NULL,
&dwType,
(LPBYTE)&dwDisabled,
&dwSize) == ERROR_SUCCESS )
{
if ( (dwType == REG_DWORD) && (dwDisabled != 0) )
{
*pfDisabled = TRUE;
}
}
RegCloseKey(hKey);
}
return S_OK;
}
STDMETHODIMP CCV3::IsReady(VARIANT_BOOL* pbYes)
{
*pbYes = TRUE;
return S_OK;
}
STDMETHODIMP CCV3::GetContentURL(OUT RETVAL VARIANT* pURL)
{
USES_CONVERSION;
VariantInit(pURL);
V_VT(pURL) = VT_BSTR;
pURL->bstrVal = SysAllocString(T2OLE((LPTSTR)g_v3state.GetContentServer()));
return S_OK;
}
// downloads the readthis first page and images for the puid locally
// script can then navigate to this page
STDMETHODIMP CCV3::GetReadThisPage(IN long puid)
{
CCatalog* pCatalog;
PINVENTORY_ITEM pItem;
if (!m_bValidInstance)
{
// the control is not launched from a trusted location
return E_ACCESSDENIED;
}
if (!g_v3state.GetCatalogAndItem(puid, &pItem, &pCatalog))
{
return E_INVALIDARG;
}
return DownloadReadThis(pItem);
}
STDMETHODIMP CCV3::GetPrintAllPage(OUT RETVAL VARIANT* pURL)
{
USES_CONVERSION;
const char READTHISLIST[] = "%READTHISLIST%"; // a semi-colon separated list of read this pages. For instance "readthis1.htm;readthis2.htm;readthis3.htm"
const char READTHISPATH[] = "%READTHISPATH%"; // the URL to the read this pages. For instance "file://d:\windowsupdate\"
TCHAR szSourceFile[MAX_PATH];
HRESULT hr;
DWORD dwFileSize = 0;
PBYTE pFileBuf = NULL;
HANDLE hFile;
DWORD dwBytes;
LPTSTR pszReadThisList = NULL;
if (!m_bValidInstance)
{
// the control is not launched from a trusted location
return E_ACCESSDENIED;
}
// download the printall page
GetWindowsUpdateDirectory(szSourceFile);
lstrcat(szSourceFile, _T("RTF"));
V3_CreateDirectory(szSourceFile);
hr = DownloadCommonRTFFiles(TRUE, szSourceFile);
if (FAILED(hr))
{
return hr;
}
// build a list of readthis first page names for all selected items
PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems();
int cSel = g_v3state.m_selectedItems.GetTotal();
if (cSel == 0)
{
// no items are selected
return S_OK;
}
// allocate enough memory for names of format puid\puid.htm;
pszReadThisList = (LPTSTR)malloc(cSel * 80);
if(!pszReadThisList)
{
return E_OUTOFMEMORY;
}
pszReadThisList[0] = _T('\0');
for (int iSel = 0; iSel < cSel; iSel++)
{
CCatalog* pCatalog;
PINVENTORY_ITEM pItem;
if (g_v3state.GetCatalogAndItem(pSel[iSel].puid, &pItem, &pCatalog))
{
if SUCCEEDED(DownloadReadThis(pItem))
{
TCHAR szTemp[24];
wsprintf(szTemp, _T("%d\\%d.htm"), pItem->GetPuid(), pItem->GetPuid());
if (pszReadThisList[0] != _T('\0'))
{
lstrcat(pszReadThisList, _T(";"));
}
lstrcat(pszReadThisList, szTemp);
}
}
} //for
if (pszReadThisList[0] == _T('\0'))
{
// no items selected with readthisfirst pages
free(pszReadThisList);
return S_OK;
}
// read the file in memory with a null appended at the end
hFile = CreateFile(szSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize > 0)
{
pFileBuf = (PBYTE)malloc(dwFileSize + 1);
if (pFileBuf != NULL)
{
if (!ReadFile(hFile, pFileBuf, dwFileSize, &dwBytes, NULL))
{
free(pFileBuf);
pFileBuf = NULL;
dwFileSize = 0;
}
pFileBuf[dwFileSize] = 0;
}
}
CloseHandle(hFile);
}
if (pFileBuf != NULL)
{
LPSTR pNewBuf;
TCHAR szDest[MAX_PATH];
GetWindowsUpdateDirectory(szDest);
lstrcat(szDest, _T("RTF\\"));
// replace tokens
if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISLIST, T2A(pszReadThisList)))
{
free(pFileBuf);
pFileBuf = (PBYTE)pNewBuf;
}
if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISPATH, T2A(szDest)))
{
free(pFileBuf);
pFileBuf = (PBYTE)pNewBuf;
}
// create the directory
lstrcat(szDest, _T("0\\"));
V3_CreateDirectory(szDest);
// write out the file
lstrcat(szDest, _T("printall.htm"));
hFile = CreateFile(szDest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
if (!WriteFile(hFile, pFileBuf, strlen((LPSTR)pFileBuf), &dwBytes, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(hFile);
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
free(pFileBuf);
// return the path
TCHAR szRTF[MAX_PATH];
VariantInit(pURL);
wsprintf(szRTF, _T("file://%s"), szDest);
V_VT(pURL) = VT_BSTR;
pURL->bstrVal = SysAllocString(T2OLE(szRTF));
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
HRESULT DownloadReadThis(PINVENTORY_ITEM pItem)
{
LOG_block("DownloadReadThis");
BYTE mszFileNames[512];
TCHAR szBaseName[64];
TCHAR szLocalName[64];
TCHAR szServerName[64];
TCHAR szServerFile[MAX_PATH];
TCHAR szLocalFile[MAX_PATH];
TCHAR szLocalDir[MAX_PATH];
if (NULL == pItem->pd)
{
LOG_error("NULL == pItem->pd");
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
PWU_VARIABLE_FIELD pvRTFCRC = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY);
PWU_VARIABLE_FIELD pvRTFImages = pItem->pd->pv->Find(WU_DESC_RTF_IMAGES);
if (pvRTFCRC == NULL)
{
LOG_error("pvRTFCRC == NULL");
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
// build a multisz string of file names
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);
}
// build local directory
GetWindowsUpdateDirectory(szLocalDir);
wsprintf(szBaseName, _T("RTF\\%d"), pItem->GetPuid());
lstrcat(szLocalDir, szBaseName);
V3_CreateDirectory(szLocalDir);
// download common images and other files
(void)DownloadCommonRTFFiles(FALSE, NULL);
// create a download object
CWUDownload dlRoot(g_v3state.GetRootServer(), 8192);
int iFileNo = 0;
for (;;)
{
if (FAILED(GetCRCNameFromList(iFileNo, mszFileNames, pvRTFCRC->pData, szServerName, sizeof(szServerName), szLocalName)))
{
// end of the list
break;
}
// build full paths
lstrcpy(szLocalFile, szLocalDir);
AddBackSlash(szLocalFile);
lstrcat(szLocalFile, szLocalName);
lstrcpy(szServerFile, _T("CRCRtf/"));
lstrcat(szServerFile, szServerName);
TRACE("Downloading RTF %s", szServerFile);
if (!dlRoot.Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL))
{
LOG_error("Download of RTF %s failed", szServerFile);
return HRESULT_FROM_WIN32(GetLastError());
}
iFileNo++;
} // for
return S_OK;
}
// deletes any cached readthisfirst pages
bool CleanupReadThis()
{
LOG_block("CleanupReadThis");
// build local directory
TCHAR szRtfPath[MAX_PATH];
GetWindowsUpdateDirectory(szRtfPath);
PathAppend(szRtfPath, _T("RTF"));
return_if_false(DeleteNode(szRtfPath));
return true;
}
// download common images for read-this-first pages and the printall page
//
// if bPrintAll=TRUE, only printall.htm page is downloaded, pszPrintAllFN returns locale filename
// if bPrintAll=FALSE, mages are downloaded, pszPrintAllFN is not used and can be null
//
// NOTE: The function downloads images in WinUpdDir/RTF folder and expects it to exist
HRESULT DownloadCommonRTFFiles(BOOL bPrintAll, LPTSTR pszPrintAllFN)
{
const TCHAR SECNAME[] = _T("RTF");
const TCHAR COUNT[] = _T("Count");
const TCHAR IMGENTRY[] = _T("Img%d");
const TCHAR PRINTALL[] = _T("PrintAll");
TCHAR szLocalDir[MAX_PATH];
TCHAR szIniFile[MAX_PATH];
int iCount;
int iNo;
CWUDownload* pDownload = NULL;
TCHAR szBaseName[64];
TCHAR szServerFile[MAX_PATH];
TCHAR szLocalFile[MAX_PATH];
static BOOL bDoneImages = FALSE;
static BOOL bDonePrintAll = FALSE;
// build paths
GetWindowsUpdateDirectory(szLocalDir);
lstrcpy(szIniFile, szLocalDir);
lstrcat(szLocalDir, _T("RTF\\"));
lstrcat(szIniFile, FILEVERINI_FN);
if (GetPrivateProfileString(SECNAME, PRINTALL, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) != 0)
{
lstrcpy(szLocalFile, szLocalDir);
lstrcat(szLocalFile, szBaseName);
}
else
{
szLocalFile[0] = _T('\0');
}
if (bPrintAll && pszPrintAllFN != NULL)
{
lstrcpy(pszPrintAllFN, szLocalFile);
}
// if we are asked to downloaded the printall page and we have not done it in this sesssion
if (bPrintAll && !bDonePrintAll)
{
bDonePrintAll = TRUE;
//
// get the printall page
//
lstrcpy(szServerFile, g_v3state.GetSiteURL());
// find the last slash
int l = lstrlen(szServerFile);
while (l > 0 && szServerFile[l - 1] != _T('\\') && szServerFile[l - 1] != _T('/'))
l--;
if (l == 0)
return E_FAIL;
// put a null following the last slash
szServerFile[l] = _T('\0');
// create the download object using the site URL without the file name
try
{
pDownload = new CWUDownload(szServerFile, 8192);
}
catch(HRESULT hr)
{
return hr;
}
// download the file
(void)pDownload->Copy(szBaseName, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL);
delete pDownload;
}
// if we are asked to download images and we have not yet done them in this session
if (!bPrintAll && !bDoneImages)
{
bDoneImages = FALSE;
//
// download the images
//
iCount = (int)GetPrivateProfileInt(SECNAME, COUNT, 0, szIniFile);
if (iCount == 0)
{
return S_OK;
}
for (iNo = 1; iNo <= iCount; iNo++)
{
TCHAR szKey[32];
wsprintf(szKey, IMGENTRY, iNo);
if (GetPrivateProfileString(SECNAME, szKey, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) == 0)
{
// try next one
continue;
}
if (pDownload == NULL)
{
// we don't have a download object, create one
try
{
pDownload = new CWUDownload(g_v3state.GetContentServer(), 8192);
}
catch(HRESULT hr)
{
return hr;
}
}
// build file names
wsprintf(szServerFile, _T("images/%s"), szBaseName);
lstrcpy(szLocalFile, szLocalDir);
lstrcat(szLocalFile, szBaseName);
// download the file
(void)pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL);
}
if (pDownload != NULL)
{
delete pDownload;
}
}
return S_OK;
}
// this function validates the server the control was instantiated from
void CCV3::CheckLaunchServer()
{
USES_CONVERSION;
BOOL bValid;
HRESULT hr;
BSTR bstrURL;
TCHAR szURL[MAX_PATH];
if (m_bLaunchServChecked)
{
// we only want to do this check once
return;
}
m_bLaunchServChecked = TRUE;
bValid = FALSE;
// check to see we have a client site. This will be NULL if the contrainer has not
// called our IObjectWithSimpleSite interface to set the site.
if (m_spUnkSite != NULL)
{
// NOTE: We are using ATL smart pointers here which call release upon destruction
// QI for IServiceProvider from IUnknown of client site
CComQIPtr<IServiceProvider, &IID_IServiceProvider> spServProv(m_spUnkSite);
if (spServProv)
{
CComPtr<IWebBrowser2> spBrowser;
// QueryService for the IWebBrowser2
hr = spServProv->QueryService(SID_SInternetExplorer, IID_IWebBrowser2, (LPVOID*)&spBrowser);
if (SUCCEEDED(hr))
{
// get the location URL of the page that instantiated us
hr = spBrowser->get_LocationURL(&bstrURL);
if (SUCCEEDED(hr) && bstrURL)
{
lstrcpy(szURL, OLE2T(bstrURL));
SysFreeString(bstrURL);
// copy the entire site URL into the state structure
g_v3state.SetSiteURL(szURL);
// check to see if the host server matches
// any of the site urls specified in ident.cab
// this function will crack the site url and all
// the site server urls to compare the hosts
bValid = g_v3state.ValidateSiteURL();
}
} // queryservice
} // spServProv
} // m_spUnkSite
if (!bValid)
{
TRACE("CheckLauncServer: The control is launced from an untrusted server--aborting");
throw E_ACCESSDENIED;
}
}
//
// CDescriptionmMerger class
//
HRESULT CDescriptionMerger::CheckMerge(PINSTALLINFOSTRUCT pInstallInfo)
{
HRESULT hr = S_OK;
if (!pInstallInfo->pCatalog->LocalesDifferent())
{
// if the browser/machine locales are not different then we don't need to do anything
return hr;
}
if (pInstallInfo->pItem->pd->pv->Find(WU_VARIABLE_MERGEINACTIVE) != NULL)
{
// there is a WU_VARIABLE_MERGEINACTIVE which means we have already merged
return hr;
}
//
// we need merge the descriptions
//
if (m_pMap == NULL || m_pDiamond == NULL)
{
// create CCRCMapFile and CDiamond objects for this and future use for this object
// this method also sets m_pDiamond
hr = ReadMapFile(pInstallInfo->pCatalog);
}
if (SUCCEEDED(hr))
{
hr = pInstallInfo->pCatalog->MergeDescription(pInstallInfo->pdlRoot, m_pDiamond, pInstallInfo->pItem, m_pMap);
}
return hr;
}
HRESULT CDescriptionMerger::ReadMapFile(CCatalog* pCatalog)
{
HRESULT hr = S_OK;
TCHAR szMapFile[MAX_PATH];
BYTE* pMapMem;
DWORD dwMapLen;
// create download object for content server and a diamond object
CWUDownload dl(g_v3state.GetContentServer(), 8192);
m_pDiamond = new CDiamond;
// build path for crc map file for machine language
wsprintf(szMapFile, _T("%d_%s.des"),
pCatalog->GetPlatform(),
pCatalog->GetMachineLocaleSZ());
hr = DownloadFileToMem(&dl, szMapFile, m_pDiamond, &pMapMem, &dwMapLen);
if (SUCCEEDED(hr))
{
// create a crc map object with the memory image of the file
m_pMap = new CCRCMapFile(pMapMem, dwMapLen);
}
return hr;
}
#ifdef _WUV3TEST
// validates the description using diagnosis variable length fields
void CheckDescDiagInfo(CCatalog* pCatalog)
{
PINVENTORY_ITEM pItem;
PWU_VARIABLE_FIELD pvDiag;
DESCDIAGINFO* pDiagInfo;
int cGood = 0;
int cItems = 0;
for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++)
{
if (NULL == (pItem = pCatalog->GetItem(i)))
{
continue;
}
if ((pItem->ps->state != WU_ITEM_STATE_PRUNED))
{
pvDiag = pItem->pd->pv->Find(WU_DESC_DIAGINFO);
if (pvDiag != NULL)
{
pDiagInfo = (DESCDIAGINFO*)pvDiag->pData;
if (pDiagInfo->puid != pItem->GetPuid() ||
pDiagInfo->dwPlat != pCatalog->GetPlatform() ||
pDiagInfo->dwLocale != pCatalog->GetBrowserLocaleDW())
{
TRACE("CheckDescDiagInfo: puid=%d has invalid description", pItem->GetPuid());
}
else
{
cGood++;
}
}
else
{
TRACE("CheckDescDiagInfo: diagnosis information not found in descriptions");
break;
}
}
cItems++;
}
TRACE("CheckDescDiagInfo: %d good found for %d items compared", cGood, cItems);
}
#endif