Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3730 lines
93 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: cv3.cpp
  6. //
  7. // Purpose: V3 control main code
  8. //
  9. //=======================================================================
  10. #include "stdafx.h"
  11. #include "WUV3IS.h"
  12. #include <stdio.h>
  13. #include <initguid.h>
  14. #include <inseng.h>
  15. #include <shlwapi.h>
  16. #define USEWUV3INCLUDES
  17. #include <wuv3.h>
  18. #undef USEWUV3INCLUDES
  19. #include <winspool.h>
  20. #include <cstate.h>
  21. #include <wustl.h>
  22. #include <osdet.h>
  23. #include "printers.h"
  24. #include "progress.h"
  25. #include "newtrust.h"
  26. #include "history.h"
  27. #include "CV3.h"
  28. #include "detect.h"
  29. #include "callback.h"
  30. #include "locstr.h"
  31. #include "safearr.h"
  32. #include "install.h"
  33. #include "log.h"
  34. #include "template.h"
  35. #include "filecrc.h"
  36. #include <shlguid.h>
  37. #include <wininet.h>
  38. #include <servpaus.h>
  39. #include "..\..\inc\wuverp.h"
  40. const TCHAR REGPATH_EXPLORER[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
  41. const TCHAR REGKEY_WINUPD_DISABLED[] = _T("NoWindowsUpdate");
  42. #define EXENAME_128BIT _T("128BIT.EXE")
  43. //
  44. // State management class. All retrieved catalogs are stored here. When the
  45. // control exits then this class cleans up the memory used by each catalog
  46. // stored with the state module. So the application must not delete any catalogs
  47. // that have been added to state storage.
  48. //
  49. CState g_v3state;
  50. TCHAR CCV3::s_szControlVer[20] = _T("\0");
  51. void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath);
  52. void DownloadFileVerInfo(CWUDownload* pDownload);
  53. PBYTE DownloadOemInfo(CWUDownload *pDownload, CDiamond *pDiamond);;
  54. void DownloadCabs(LPCTSTR szLocalDir, CWUDownload* pDownload, CDiamond* pDiamond, PBYTE pCabList, PBYTE pCRCList, IWUProgress* pProgress, BOOL bUnCab);
  55. void DownloadCif(LPCTSTR szLocalDir, CDiamond* pDiamond, PINSTALLINFOSTRUCT pInstallInfo);
  56. void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress);
  57. void DetectPlatAndLang();
  58. void DetectActiveSetupWU(CWUDownload* pDownload, CDiamond* pDiamond, CCatalog* pCatalog);
  59. void DownloadItem(LPCTSTR pszLocalDir, CWUDownload *pDownload, CDiamond *pDiamond, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress);
  60. void InstallItem(LPCTSTR pszLocalDir, PSELECTITEMINFO pStatusInfo, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress);
  61. DWORD WINAPI RebootThreadProc(LPVOID pv);
  62. void CheckDescDiagInfo(CCatalog* pCatalog);
  63. bool IsArabicOrHebrew()
  64. {
  65. WORD wCurPrimeLang = PRIMARYLANGID(LOWORD(g_v3state.GetBrowserLocale()));
  66. return LANG_HEBREW == wCurPrimeLang || LANG_ARABIC == wCurPrimeLang;
  67. }
  68. //
  69. // CDescriptionMerger class
  70. //
  71. // a local class used to merge description files
  72. //
  73. class CDescriptionMerger
  74. {
  75. public:
  76. CDescriptionMerger()
  77. : m_pMap(NULL),
  78. m_pDiamond(NULL)
  79. {
  80. }
  81. ~CDescriptionMerger()
  82. {
  83. if (m_pMap != NULL)
  84. delete m_pMap;
  85. if (m_pDiamond != NULL)
  86. delete m_pDiamond;
  87. }
  88. HRESULT CheckMerge(PINSTALLINFOSTRUCT pInstallInfo);
  89. private:
  90. CCRCMapFile* m_pMap;
  91. CDiamond* m_pDiamond;
  92. HRESULT ReadMapFile(CCatalog* pCatalog);
  93. };
  94. //
  95. // CCV3 class
  96. //
  97. // this function is called when our ref count becomes zero
  98. void CCV3::FinalRelease()
  99. {
  100. LOG_block("CCV3::FinalRelease");
  101. //
  102. // reset state
  103. //
  104. g_v3state.Reset();
  105. //
  106. // make sure we undo registration of MS trust key if we registred it
  107. //
  108. CConnSpeed::WriteToRegistry();
  109. }
  110. // this function is called after our object is created, this is the prefered
  111. // place to do initialization
  112. HRESULT CCV3::FinalConstruct()
  113. {
  114. LOG_block("CCV3::FinalConstruct");
  115. wsprintf(CCV3::s_szControlVer, _T("5,04,%d,%d"), VER_PRODUCTBUILD,VER_PRODUCTBUILD_QFE);
  116. TCHAR szLogFN[MAX_PATH];
  117. TCHAR szDate[50];
  118. TCHAR szTime[50];
  119. GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, sizeof(szDate)/sizeof(szDate[0]));
  120. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER, NULL, NULL, szTime, sizeof(szTime)/sizeof(szTime[0]));
  121. LOG_out("Windows Update V3 Internet Site Control, Version %s",s_szControlVer);
  122. LOG_out("Session starting %s at %s", szDate, szTime);
  123. //
  124. // set up the application log
  125. //
  126. GetWindowsUpdateDirectory(szLogFN);
  127. lstrcat(szLogFN, HISTORY_FILENAME);
  128. g_v3state.AppLog().SetLogFile(szLogFN);
  129. CConnSpeed::ReadFromRegistry();
  130. m_bValidInstance = FALSE;
  131. //
  132. // seed the random number generator
  133. //
  134. srand((int)GetTickCount());
  135. return S_OK;
  136. }
  137. // The get catalog method retrieves a catalog array from the server. The get catalog method only
  138. // accesses the server if the catalog is not already resident on the clients computer system.
  139. // This allows the VB script page call this method to quickly obtain filtered catalog record information.
  140. STDMETHODIMP CCV3::GetCatalog(
  141. IN long puidCatalog,
  142. IN BSTR bstrServerUrl,
  143. IN long platformId,
  144. IN BSTR bstrBrowserLanguage, // BUGBUG - why is browser locale a string and not a long
  145. IN long lFilters,
  146. IN long lFlags,
  147. OUT RETVAL VARIANT *pCatalogArray
  148. )
  149. {
  150. HRESULT hr;
  151. CCatalog* pCatalog;
  152. LOG_block("CCV3::GetCatalog");
  153. try
  154. {
  155. pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags);
  156. //If we are retrieving the sub-catalog list then the return VB script array
  157. //needs to be different.
  158. if (pCatalog->GetCatalogPuid() == WU_CATALOG_LIST_PUID)
  159. {
  160. hr = MakeReturnCatalogListArray(pCatalog, lFilters, lFlags, pCatalogArray);
  161. if (FAILED(hr))
  162. throw hr;
  163. }
  164. else
  165. {
  166. hr = MakeReturnCatalogArray(pCatalog, lFilters, lFlags, pCatalogArray);
  167. if (FAILED(hr))
  168. throw hr;
  169. }
  170. }
  171. catch(HRESULT hr)
  172. {
  173. // create an empty array so that script doesn't throw a UBound error
  174. LPSAFEARRAY psa;
  175. SAFEARRAYBOUND rgsabound[2];
  176. VariantInit(pCatalogArray);
  177. rgsabound[0].lLbound = 0;
  178. rgsabound[0].cElements = 0;
  179. rgsabound[1].lLbound = 0;
  180. rgsabound[1].cElements = 8;
  181. psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
  182. V_VT(pCatalogArray) = VT_ARRAY | VT_VARIANT;
  183. V_ARRAY(pCatalogArray) = psa;
  184. // we can't return a failure code, because that prevents script from
  185. // honoring the return value.
  186. return S_FALSE;
  187. }
  188. return S_OK;
  189. }
  190. STDMETHODIMP CCV3::GetCatalogHTML(
  191. IN long puidCatalog,
  192. IN BSTR bstrServerUrl,
  193. IN long platformId,
  194. IN BSTR bstrBrowserLanguage,
  195. IN long lFilters,
  196. IN long lFlags,
  197. OUT RETVAL VARIANT *pCatalogHTML
  198. )
  199. {
  200. HRESULT hr;
  201. CCatalog* pCatalog;
  202. // we are currently not using the templates feature
  203. // the code for this templates are wrapped in HTML_TEMPLATE define
  204. #ifdef HTML_TEMPLATE
  205. TRACE("GetCatalogHTML: %d", puidCatalog);
  206. try
  207. {
  208. pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags);
  209. hr = MakeCatalogHTML(pCatalog, lFilters, pCatalogHTML);
  210. if (FAILED(hr))
  211. throw hr;
  212. }
  213. catch(HRESULT hr)
  214. {
  215. return hr;
  216. }
  217. return S_OK;
  218. #endif
  219. return E_NOTIMPL;
  220. }
  221. /*
  222. * The process catalog function constructs or retireves the requested
  223. * V3 catalog. A pointer to the retrieved or constructed catalog is
  224. * returned to the caller if successfull or an HRESULT error code is
  225. * thrown if not.
  226. */
  227. CCatalog *CCV3::ProcessCatalog(
  228. IN PUID puidCatalog,
  229. IN BSTR bstrServerUrl,
  230. IN long platformId,
  231. IN BSTR bstrBrowserLanguage,
  232. IN long lFilters,
  233. IN long lFlags
  234. )
  235. {
  236. USES_CONVERSION;
  237. CCdm cdm;
  238. BOOL bCheckInNeeded;
  239. CDiamond dm;
  240. CBitmask bmAS;
  241. CBitmask bmCDM;
  242. CCatalog* pCatalog;
  243. TCHAR szIdentServer[MAX_PATH];
  244. char szBuffer[1024];
  245. PINVENTORY_ITEM pCatalogItem;
  246. int i;
  247. HRESULT hr;
  248. LOG_block("CCV3::ProcessCatalog");
  249. LOG_out("puidCatalog = %d, bstrServerUrl = %s", puidCatalog, OLE2T(bstrServerUrl));
  250. LOG_out("tick count is %d", GetTickCount());
  251. // assume that the catalog is in state storage.
  252. bCheckInNeeded = FALSE;
  253. //
  254. // if catalog is not already in state storage go retrieve and prune it.
  255. //
  256. if ( !(pCatalog = g_v3state.Get(puidCatalog)) )
  257. {
  258. if (NULL == bstrBrowserLanguage) // AutoUpdate
  259. {
  260. // We'll use this flag to determine whether to show UI when we call VerifyFile
  261. g_v3state.m_nClient = WUV3_CLIENT_AUTOUPDATE;
  262. LOG_out("Client Set to AutoUpdate");
  263. LOG_out("Client is currently %s", (CWUDownload::s_fOffline) ? "Offline" : "Online");
  264. }
  265. //
  266. // check if the ident server is trusted as well as read the valid server
  267. // list from ident.cab into memory
  268. //
  269. lstrcpy(szIdentServer, OLE2T(bstrServerUrl));
  270. RemoveLastSlash(szIdentServer);
  271. g_v3state.CheckTrustedServer(szIdentServer, &dm);
  272. //
  273. // check the server the control was launch from. At this point the
  274. // ident cab is already loaded
  275. // this function will do the work only once and it will throw if
  276. // the server is not valid
  277. //
  278. CheckLaunchServer();
  279. //
  280. // create a new catalog object
  281. //
  282. pCatalog = new CCatalog(g_v3state.GetContentServer(), puidCatalog);
  283. if (NULL == pCatalog)
  284. {
  285. LOG_out("ProcessCatalog: Creation of new Catalog failed. GetLastError() = %d", GetLastError());
  286. throw HRESULT_FROM_WIN32(GetLastError());
  287. }
  288. if (NULL != bstrBrowserLanguage) // AutoUpdate whould set it to NULL
  289. {
  290. pCatalog->SetBrowserLocale(OLE2T(bstrBrowserLanguage));
  291. }
  292. //
  293. // Create a download object for the content
  294. //
  295. CWUDownload dl(pCatalog->GetCatalogServer(), 8192);
  296. //
  297. // read the catalog
  298. //
  299. pCatalog->Read(&dl, &dm);
  300. //
  301. // read the bitmask file
  302. //
  303. bmAS.Read(&dl, &dm, puidCatalog, BITMASK_ACTIVESETUP_TYPE, pCatalog->GetBitmaskName());
  304. if (!g_v3state.m_pdwPlatformList)
  305. {
  306. TCHAR szOsdetServer[MAX_PATH];
  307. lstrcpy(szOsdetServer, _T("OSDET."));
  308. AppendExtForOS(szOsdetServer);
  309. DownloadFileVerInfo(&dl);
  310. DownloadDLL(&dm, &dl, szOsdetServer, NULL);
  311. DetectPlatAndLang();
  312. LOG_out("Platform %d", g_v3state.m_pdwPlatformList[0]);
  313. LOG_out("Machine Language 0x%8.8x", GetMachineLangDW());
  314. LOG_out("User UI Language 0x%8.8x", GetUserLangDW());
  315. }
  316. if (NULL == bstrBrowserLanguage) // AutoUpdate
  317. {
  318. // For Windows XP, AU can't use the system language - we need to use the MUI user language
  319. //pCatalog->SetBrowserLocale(pCatalog->GetMachineLocaleSZ());
  320. pCatalog->SetBrowserLocale(pCatalog->GetUserLocaleSZ());
  321. }
  322. if (puidCatalog == WU_CATALOG_LIST_PUID)
  323. {
  324. // inventory.plt is platform 0 by convention
  325. pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]);
  326. }
  327. else
  328. {
  329. // normal inventory item sub catalog.
  330. if (!platformId)
  331. {
  332. // if the caller did not pass in a platformId then we
  333. // need to detect the current platform and use that value
  334. // in the catalog. In this case we luck out since the first
  335. // platform id returned from osdet.dll is the client machines platform.
  336. pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]);
  337. }
  338. else
  339. {
  340. pCatalog->SetPlatform(platformId);
  341. }
  342. }
  343. // inventory.plt catalog only does bitmask pruning
  344. if ( puidCatalog == WU_CATALOG_LIST_PUID )
  345. {
  346. // if puidCatalog is 0 then we are retrieving the inventory.plt list of
  347. // catalogs. We need to handle this catalog differently.
  348. pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pdwPlatformList, g_v3state.m_iTotalPlatforms);
  349. }
  350. else
  351. {
  352. // we are retrieving a normal inventory catalog.
  353. // since we need the OEM table to perform bitmask detection on an inventory catalog
  354. // we first check to see if the oem table has already been read. If it has not we
  355. // download. Note: We use full local caching on the OEM table. This is important for
  356. // maximum performance.
  357. if ( !g_v3state.m_pOemInfoTable ) //Pointer OEM info table that OEM detection needs.
  358. {
  359. byte_buffer bufOemInfo;
  360. if (! DownloadToBuffer( _T("oeminfo.bin"), &dl, &dm, bufOemInfo))
  361. throw HRESULT_FROM_WIN32(GetLastError());
  362. g_v3state.m_pOemInfoTable = bufOemInfo.detach();
  363. }
  364. // perform active setup record bitmask pruning.
  365. pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pOemInfoTable);
  366. // since windows 95 & NT4.0 do not support PnP drivers we cannot add any device driver records.
  367. //
  368. // NOTE: The catalog.Prune() method hides the device driver insertion record. So we do not need
  369. // to do anything if the OS does not allow device driver installations.
  370. if (DoesClientPlatformSupportDrivers())
  371. {
  372. LOG_out("Support drivers on this platform");
  373. // if there are device driver records to be added.
  374. if ( pCatalog->GetRecordIndex(WU_TYPE_CDM_RECORD_PLACE_HOLDER) != -1 )
  375. {
  376. LOG_out("Have drivers on this platform");
  377. // if there are no drivers for this platform
  378. // the bitmask will be missing and the Read()
  379. // method will throw. In this case, we do nothing.
  380. try
  381. {
  382. bmCDM.Read(&dl, &dm, puidCatalog, BITMASK_CDM_TYPE, NULL);
  383. cdm.CreateInventoryList(&bmCDM, &dl, &dm, puidCatalog, g_v3state.m_pOemInfoTable);
  384. pCatalog->AddCDMRecords(&cdm);
  385. }
  386. catch(HRESULT hr)
  387. {
  388. LOG_out("ProcessCatalog: bitmask.cdm or inventory.cdm missing.");
  389. }
  390. }
  391. else
  392. {
  393. LOG_out("Don't have drivers on this platform");
  394. }
  395. }
  396. else
  397. {
  398. LOG_out("Don't support drivers on this platform");
  399. }
  400. pCatalog->ProcessExclusions(&dl);
  401. //
  402. // do active setup detection
  403. //
  404. DetectActiveSetupWU(&dl, &dm, pCatalog);
  405. // perform catalog inventory link processing and use selected registry item hiding.
  406. pCatalog->Prune();
  407. }
  408. if (puidCatalog == WU_CATALOG_LIST_PUID)
  409. {
  410. // description files for catalog list
  411. //
  412. // NOTE: With 3.1 we dropped the description fields for catalog list
  413. // we fill the structure with blank descriptions
  414. for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  415. {
  416. if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
  417. {
  418. continue;
  419. }
  420. if (pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED)
  421. {
  422. (void)pCatalog->BlankDescription(pCatalogItem);
  423. }
  424. }
  425. }
  426. else
  427. {
  428. //
  429. // read descriptions for the catalog items
  430. // 1. read gang description file
  431. // 2. (pass 1) read individual descriptions for items that did not get descriptions by
  432. // by using browser language
  433. // 3. (pass 2) read individual descriptions for itmes that still did not get descriptions
  434. // by using machine language
  435. //
  436. hr = pCatalog->ReadDescriptionGang(&dl, &dm);
  437. // check to see if we need to download any individual descriptions
  438. BOOL bNeedIndividual = FALSE;
  439. if (FAILED(hr))
  440. {
  441. bNeedIndividual = TRUE;
  442. }
  443. else
  444. {
  445. for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  446. {
  447. if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
  448. {
  449. continue;
  450. }
  451. if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL))
  452. {
  453. // need to download it
  454. bNeedIndividual = TRUE;
  455. break;
  456. }
  457. } // for
  458. }
  459. for (int iPass = 1; iPass <= 2; iPass++)
  460. {
  461. if (!bNeedIndividual)
  462. {
  463. break;
  464. }
  465. hr = S_OK;
  466. bNeedIndividual = FALSE;
  467. //
  468. // we need to download individual description files
  469. //
  470. TCHAR szMapFile[MAX_PATH];
  471. TCHAR szMapFileLocal[MAX_PATH];
  472. BYTE* pMapMem;
  473. DWORD dwMapLen;
  474. // build path for crc map file
  475. wsprintf(szMapFile, _T("%d_%s.des"),
  476. pCatalog->GetPlatform(),
  477. (iPass == 1) ? pCatalog->GetBrowserLocaleSZ() : pCatalog->GetMachineLocaleSZ());
  478. //because the map file name isn't a CRC, we can't guarantee that it is the right one - always delete and re-download
  479. GetWindowsUpdateDirectory(szMapFileLocal);
  480. lstrcat(szMapFileLocal, szMapFile);
  481. if(!CWUDownload::s_fOffline)
  482. {
  483. DeleteFile(szMapFileLocal);
  484. }
  485. hr = DownloadFileToMem(&dl, szMapFile, &dm, &pMapMem, &dwMapLen);
  486. if (SUCCEEDED(hr))
  487. {
  488. // create a crc map object with the memory image of the file
  489. CCRCMapFile DescMap(pMapMem, dwMapLen);
  490. CWUDownload dlRoot(g_v3state.GetRootServer(), 8192);
  491. for (i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  492. {
  493. if (NULL == (pCatalogItem = pCatalog->GetItem(i)))
  494. {
  495. continue;
  496. }
  497. if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL))
  498. {
  499. DWORD dwDisp = 0;
  500. hr = pCatalog->ReadDescription(&dlRoot, &dm, pCatalogItem, &DescMap, &dwDisp);
  501. if (FAILED(hr))
  502. {
  503. // description not found
  504. if (iPass == 1)
  505. {
  506. bNeedIndividual = TRUE;
  507. hr = S_OK;
  508. }
  509. else
  510. {
  511. switch(dwDisp)
  512. {
  513. case DISP_PUID_NOT_IN_MAP:
  514. wsprintfA(szBuffer, "Puid #%d not found in map file - removing from catalog", pCatalogItem->GetPuid());
  515. LOG_out(szBuffer);
  516. pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED;
  517. hr = S_OK;
  518. break;
  519. case DISP_DESC_NOT_FOUND:
  520. wsprintfA(szBuffer, "Missing description file for puid #%d - removing from catalog", pCatalogItem->GetPuid());
  521. LOG_out(szBuffer);
  522. pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED;
  523. hr = S_OK;
  524. break;
  525. }
  526. break;
  527. }
  528. }
  529. }
  530. } // for i
  531. V3_free(pMapMem);
  532. }
  533. else
  534. {
  535. if (iPass == 1)
  536. {
  537. bNeedIndividual = TRUE;
  538. hr = S_OK;
  539. }
  540. }
  541. } // for iPass
  542. if (FAILED(hr))
  543. {
  544. throw hr;
  545. }
  546. #ifdef _WUV3TEST
  547. // validate descriptions
  548. CheckDescDiagInfo(pCatalog);
  549. #endif // _WUV3TEST
  550. }
  551. bCheckInNeeded = TRUE;
  552. LOG_out("catalog for %d NOT found in state cache, create it", puidCatalog);//added by wei
  553. }
  554. else //added by wei
  555. {
  556. LOG_out("catalog for %d found in state cache, return it", puidCatalog);
  557. }
  558. // in the case where the catalog is already in state storage we simply make
  559. // the catalog array and return.
  560. // NOTE: if this catalog came from state storage then there is no reason to check it in.
  561. if (bCheckInNeeded)
  562. {
  563. // finally check the pruned catalog into state storage.
  564. g_v3state.Add(puidCatalog, pCatalog);
  565. }
  566. // if we got here that also means that CheckLaunchServer has validated us
  567. // mark this instance as a valid one
  568. m_bValidInstance = TRUE;
  569. return pCatalog;
  570. }
  571. STDMETHODIMP CCV3::ChangeItemState(
  572. IN long puid,
  573. IN long lNewItemState
  574. )
  575. {
  576. HRESULT hrRet = S_OK;
  577. try
  578. {
  579. hrRet = ProcessChangeItemState(puid, lNewItemState);
  580. }
  581. catch (HRESULT hr)
  582. {
  583. hrRet = hr;
  584. }
  585. return hrRet;
  586. }
  587. HRESULT CCV3::ProcessChangeItemState(
  588. IN long puid,
  589. IN long lNewItemState
  590. )
  591. {
  592. HKEY hKey;
  593. BOOL bChanged;
  594. int i;
  595. int iTotalItems;
  596. Varray<PINVENTORY_ITEM> pItemList;
  597. if (!m_bValidInstance)
  598. {
  599. return E_ACCESSDENIED;
  600. }
  601. //if the requested state is SELECT by itself, we default to SELECT | INSTAL
  602. if (lNewItemState == ITEM_STATE_SELECT_ITEM)
  603. {
  604. lNewItemState = ITEM_STATE_SELECT_ITEM | ITEM_STATE_INSTALL_ITEM;
  605. }
  606. if (!(iTotalItems = g_v3state.GetItemList(puid, pItemList)))
  607. {
  608. TRACE("ChangeItemState called with invalid PUID %d", puid);
  609. return E_INVALIDARG;
  610. }
  611. bChanged = FALSE;
  612. for (i = 0; i < iTotalItems; i++)
  613. {
  614. //
  615. // show/hide
  616. //
  617. if (lNewItemState & ITEM_STATE_HIDE_ITEM)
  618. {
  619. if ( !pItemList[i]->ps->bHidden )
  620. {
  621. pItemList[i]->ps->bHidden = TRUE;
  622. bChanged = TRUE;
  623. }
  624. }
  625. else if (lNewItemState & ITEM_STATE_SHOW_ITEM)
  626. {
  627. if ( pItemList[i]->ps->bHidden )
  628. {
  629. pItemList[i]->ps->bHidden = FALSE;
  630. bChanged = TRUE;
  631. }
  632. }
  633. //
  634. // select
  635. //
  636. if (lNewItemState & ITEM_STATE_SELECT_ITEM)
  637. {
  638. // default is to select the item for install.
  639. if (lNewItemState & ITEM_STATE_INSTALL_ITEM)
  640. {
  641. if (!pItemList[i]->ps->bChecked )
  642. {
  643. pItemList[i]->ps->bChecked = TRUE;
  644. bChanged = TRUE;
  645. g_v3state.m_selectedItems.Select(puid, TRUE);
  646. }
  647. }
  648. if ( lNewItemState & ITEM_STATE_REMOVE_ITEM )
  649. {
  650. // remove only removes requested item.
  651. g_v3state.m_selectedItems.Select(puid, FALSE);
  652. bChanged = TRUE;
  653. }
  654. }
  655. //
  656. // unselect
  657. //
  658. if ( lNewItemState & ITEM_STATE_UNSELECT_ITEM )
  659. {
  660. if ( pItemList[i]->ps->bChecked )
  661. {
  662. if (pItemList[i]->ps->bChecked )
  663. {
  664. pItemList[i]->ps->bChecked = FALSE;
  665. bChanged = TRUE;
  666. }
  667. // add item and all of its dependent items to selected items array.
  668. // remove item from selected items array.
  669. //
  670. // NOTE: This will only remove the item
  671. // if the select count is 0.
  672. g_v3state.m_selectedItems.Unselect(puid);
  673. }
  674. }
  675. //
  676. // personalize hide/unhide
  677. //
  678. if (lNewItemState & ITEM_STATE_PERSONALIZE_HIDE)
  679. {
  680. pItemList[i]->ps->bHidden = TRUE;
  681. pItemList[i]->ps->dwReason = WU_STATE_REASON_PERSONALIZE;
  682. bChanged = RegistryHidingUpdate(puid, TRUE);
  683. }
  684. if (lNewItemState & ITEM_STATE_PERSONALIZE_UNHIDE)
  685. {
  686. bChanged = RegistryHidingUpdate(puid, FALSE);
  687. if (bChanged)
  688. {
  689. pItemList[i]->ps->bHidden = FALSE;
  690. pItemList[i]->ps->dwReason = WU_STATE_REASON_NONE;
  691. }
  692. }
  693. }
  694. if (!bChanged)
  695. return E_INVALIDARG;
  696. return S_OK;
  697. }
  698. int __cdecl SortComparePriority(const void* p1, const void* p2)
  699. {
  700. DWORD d1 = ((DEPENDPUID*)p1)->dwPriority;
  701. DWORD d2 = ((DEPENDPUID*)p2)->dwPriority;
  702. // reverse order compare
  703. if (d1 > d2)
  704. return -1;
  705. else if (d1 < d2)
  706. return +1;
  707. else
  708. return 0;
  709. }
  710. // Now sort if by priority
  711. static Varray<PUID> g_vPuidParent;
  712. static int g_cPuidParent;
  713. void ListDependenciesFirst(Varray<DEPENDPUID>& vInitList, int cInitList, Varray<DEPENDPUID>& vFinalList, int& cFinalList)
  714. {
  715. // sort initial list
  716. if (cInitList > 1)
  717. qsort((void *)(&vInitList[0]), cInitList, sizeof(DEPENDPUID), SortComparePriority);
  718. for (int iInitList = 0; iInitList < cInitList; iInitList++)
  719. {
  720. // check if we are in the parent array;
  721. for (int i = 0; i < g_cPuidParent; i++)
  722. {
  723. if (g_vPuidParent[i] == vInitList[iInitList].puid)
  724. break;
  725. }
  726. if (i != g_cPuidParent)
  727. continue; // didn't get to the very end
  728. // Get catalog
  729. CCatalog* pCatalog;
  730. PINVENTORY_ITEM pItem;
  731. if (!g_v3state.GetCatalogAndItem(vInitList[iInitList].puid, &pItem, &pCatalog))
  732. {
  733. continue;
  734. }
  735. // Get dependancies
  736. Varray<DEPENDPUID> vTmpList;
  737. int cTmpList = 0;
  738. pCatalog->GetItemDirectDependencies(pItem, vTmpList, cTmpList);
  739. if (cTmpList)
  740. {
  741. // set vInitList[iList].pTopLevelItem, for them
  742. for(int j = 0; j < cTmpList; j ++)
  743. {
  744. if (NULL == vInitList[iInitList].pTopLevelItem)
  745. vTmpList[j].pTopLevelItem = pItem;
  746. else
  747. vTmpList[j].pTopLevelItem = vInitList[iInitList].pTopLevelItem;
  748. }
  749. // prepend them
  750. g_vPuidParent[g_cPuidParent ++] = vInitList[iInitList].puid;
  751. ListDependenciesFirst(vTmpList, cTmpList, vFinalList, cFinalList);
  752. g_cPuidParent --;
  753. }
  754. // Check if it's included by now
  755. for (i = 0; i < cFinalList; i++)
  756. {
  757. if (vFinalList[i].puid == vInitList[iInitList].puid)
  758. break;
  759. }
  760. if (i != cFinalList)
  761. continue; // didn't get to the very end
  762. // now add the item if it's not there
  763. vFinalList[cFinalList ++] = vInitList[iInitList];
  764. }
  765. }
  766. void ProcessInstallList(Varray<DEPENDPUID>& vFinalList, int& cFinalList)
  767. {
  768. LOG_block("CCV3::ProcessInstallList");
  769. PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems();
  770. int cSel = g_v3state.m_selectedItems.GetTotal();
  771. if (cSel == 0)
  772. return;
  773. // Build selection list
  774. Varray<DEPENDPUID> vSelectList;
  775. int cSelectList = 0;
  776. DEPENDPUID d = {0};
  777. for (int iSel = 0; iSel < cSel; iSel++)
  778. {
  779. d.puid = pSel[iSel].puid;
  780. d.puidParent = 0;
  781. d.pTopLevelItem = NULL; // that is important
  782. CCatalog* pCatalog;
  783. PINVENTORY_ITEM pItem;
  784. if (!g_v3state.GetCatalogAndItem(d.puid, &pItem, &pCatalog))
  785. {
  786. continue;
  787. }
  788. // look up priority and add the item to the array
  789. d.dwPriority = 0;
  790. PWU_VARIABLE_FIELD pvPri = pItem->pd->pv->Find(WU_DESC_INSTALL_PRIORITY);
  791. if (pvPri != NULL)
  792. d.dwPriority = *((DWORD*)(pvPri->pData));
  793. vSelectList[cSelectList ++] = d;
  794. }
  795. // build final list
  796. g_cPuidParent = 0;
  797. ListDependenciesFirst(vSelectList, cSelectList, vFinalList, cFinalList);
  798. //
  799. // now, clear the select and reselect the items (including dependendcies) for installation in order
  800. //
  801. g_v3state.m_selectedItems.Clear();
  802. for (int i = 0; i < cFinalList; i++)
  803. {
  804. LOG_out("Final List %d Pri=%d Parent=%d TopLevel=%s",
  805. vFinalList[i].puid, vFinalList[i].dwPriority,
  806. vFinalList[i].puidParent, (vFinalList[i].pTopLevelItem == NULL ? "NULL" : "Not NULL"));
  807. // select the item
  808. g_v3state.m_selectedItems.Select(vFinalList[i].puid, TRUE);
  809. }
  810. }
  811. STDMETHODIMP CCV3::InstallSelectedItems(
  812. IN BSTR bstrUnused, //Server Directory if blank then the server used with the catalog was retrieved is used.
  813. IN long lFlags, //Flags currently only WU_NOSPECIAL_FLAGS and WU_COPYONLY_NO_INSTALL supported.
  814. IN BSTR bstrNotUsed,
  815. OUT RETVAL VARIANT *pResultsArray
  816. )
  817. {
  818. LOG_block("CCV3::InstallSelectedItems");
  819. int iTotalItems = 0;
  820. TCHAR szTempDir[MAX_PATH];
  821. TCHAR szLocalDir[MAX_PATH];
  822. CDiamond dm;
  823. PSELECTITEMINFO pInfo = NULL;
  824. Varray<INSTALLINFOSTRUCT> InstallArr;
  825. int InstallCnt = 0;
  826. DWORD dwTotalBytes = 0;
  827. Varray<DEPENDPUID> vFinalList;
  828. int cFinalList = 0;
  829. int i;
  830. int t;
  831. if (!m_bValidInstance)
  832. {
  833. return E_ACCESSDENIED;
  834. }
  835. try
  836. {
  837. CWUProgress Progress(_Module.GetModuleInstance());
  838. CServPauser ServPauser;
  839. CDescriptionMerger DescMerger;
  840. g_v3state.m_bRebootNeeded = FALSE;
  841. //
  842. // process depenendencies and priorities of the item
  843. //
  844. ProcessInstallList(vFinalList, cFinalList);
  845. iTotalItems = g_v3state.m_selectedItems.GetTotal();
  846. pInfo = g_v3state.m_selectedItems.GetItems();
  847. // pause task scheduler
  848. ServPauser.PauseTaskScheduler();
  849. //
  850. // go thru all the selected items and build the InstallArr
  851. //
  852. for (i = 0, InstallCnt = 0; i < iTotalItems; i++)
  853. {
  854. if (pInfo[i].bInstall)
  855. {
  856. if (!g_v3state.GetCatalogAndItem(pInfo[i].puid, &InstallArr[InstallCnt].pItem, &InstallArr[InstallCnt].pCatalog))
  857. {
  858. continue;
  859. }
  860. //
  861. // remove the "Checked" status from the item
  862. //
  863. InstallArr[InstallCnt].pItem->ps->bChecked = FALSE;
  864. dwTotalBytes += (InstallArr[InstallCnt].pItem->pd->size * 1024);
  865. //
  866. // create download objects. We use the GetCabPoolServer to get the server.for cabpool
  867. // we create objects for only one element and assign pdl of each install element to this object
  868. //
  869. // NOTE: We are ignoring the szServer passed in and we will eventually remove it from interface
  870. //
  871. if (InstallCnt == 0)
  872. {
  873. TRACE("InstallSelectedItems: creating download objects for %s and %s", g_v3state.GetCabPoolServer(), InstallArr[0].pCatalog->GetCatalogServer());
  874. InstallArr[0].bServerNew = TRUE;
  875. InstallArr[0].pdl = new CWUDownload(g_v3state.GetCabPoolServer(), 8192);
  876. InstallArr[0].pdlRoot = new CWUDownload(g_v3state.GetRootServer(), 8192);
  877. }
  878. else
  879. {
  880. InstallArr[InstallCnt].pdl = InstallArr[0].pdl;
  881. InstallArr[InstallCnt].pdlRoot = InstallArr[0].pdlRoot;
  882. InstallArr[InstallCnt].bServerNew = FALSE;
  883. }
  884. InstallArr[InstallCnt].pInfo = &pInfo[i];
  885. GetCurTime(&(InstallArr[InstallCnt].pInfo->stDateTime));
  886. InstallArr[InstallCnt].pInfo->iStatus = ITEM_STATUS_FAILED; //init to failed
  887. InstallArr[InstallCnt].iSelIndex = i;
  888. InstallArr[InstallCnt].dwLocaleID = 0; // use systems
  889. InstallArr[InstallCnt].dwPlatform = 0; // use systems
  890. InstallArr[InstallCnt].bHistoryWritten = FALSE;
  891. InstallArr[InstallCnt].bDownloaded = FALSE;
  892. InstallArr[InstallCnt].pTopLevelItem = NULL;
  893. //
  894. // if the item is hidden, set the pTopLevelItem using the dependcies list
  895. //
  896. if (InstallArr[InstallCnt].pItem->ps->bHidden)
  897. {
  898. PUID puidDep = InstallArr[InstallCnt].pItem->GetPuid();
  899. //
  900. //check puidDep, i.e. check if the function GetPuid() is returning valid info
  901. //
  902. if (puidDep > 0)
  903. {
  904. for (int iDep = 0; iDep < cFinalList; iDep++)
  905. {
  906. if (vFinalList[iDep].puid == puidDep)
  907. {
  908. InstallArr[InstallCnt].pTopLevelItem = vFinalList[iDep].pTopLevelItem;
  909. break;
  910. }
  911. }
  912. }
  913. }
  914. //
  915. // merge the descriptions if machine/browser languages are different so that
  916. // we have the correct installation information based on machine language
  917. //
  918. BLOCK
  919. {
  920. HRESULT hr = DescMerger.CheckMerge(&InstallArr[InstallCnt]);
  921. if (FAILED(hr))
  922. {
  923. TRACE("Failed while mergeing description");
  924. throw hr;
  925. }
  926. }
  927. InstallCnt++;
  928. }
  929. }
  930. //
  931. // get the directory where we will download CABs
  932. //
  933. GetWindowsUpdateDirectory(szTempDir);
  934. AddBackSlash(szTempDir);
  935. Progress.StartDisplay();
  936. Progress.SetDownloadTotal(dwTotalBytes);
  937. Progress.SetInstallTotal(InstallCnt * 3);
  938. //
  939. // Create directory for and download each item
  940. //
  941. for (i = 0; i < InstallCnt; i++)
  942. {
  943. wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid);
  944. V3_CreateDirectory(szLocalDir);
  945. InstallArr[i].bDownloaded = TRUE; //assume the download will be fine
  946. try
  947. {
  948. DownloadItem(szLocalDir, InstallArr[i].pdl, &dm, &InstallArr[i], &Progress);
  949. }
  950. catch (HRESULT hr)
  951. {
  952. InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED;
  953. InstallArr[i].bDownloaded = FALSE;
  954. //
  955. // check to see if the Cancel button was pressed
  956. //
  957. if (WaitForSingleObject(Progress.GetCancelEvent(), 0) == WAIT_OBJECT_0)
  958. throw hr;
  959. }
  960. // even though the download for this item has succeeded, we reset the status to 'failed'
  961. // until we actually finish the installation
  962. InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED;
  963. }
  964. Progress.SetDownload(); //100%
  965. //
  966. // Install each package and delete its directory
  967. //
  968. for (i = 0; i < InstallCnt; i++)
  969. {
  970. wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid);
  971. Progress.SetInstallAdd(1);
  972. if (InstallArr[i].bDownloaded)
  973. {
  974. // if this is an exclusive component, hide the install progress. We assume
  975. // that, apart from dependencies, this will be the only component being installed
  976. // since it is by definition exclusive. In that case, this will be the last component
  977. // and install progress will be hidden so that the component's own setup UI is displayed
  978. if (InstallArr[i].pItem->pd->flags & DESCRIPTION_EXCLUSIVE)
  979. {
  980. Progress.SetStyle(CWUProgress::ProgStyle::OFF);
  981. }
  982. // install the item
  983. InstallItem(szLocalDir, InstallArr[i].pInfo, &InstallArr[i], &Progress);
  984. }
  985. Progress.SetInstallAdd(1);
  986. DeleteNode(szLocalDir);
  987. UpdateInstallHistory(InstallArr[i].pInfo, 1);
  988. InstallArr[i].bHistoryWritten = TRUE;
  989. if ((InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS) || (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED))
  990. {
  991. //update item status to CURRENT
  992. InstallArr[i].pItem->ps->state = WU_ITEM_STATE_CURRENT;
  993. //indicate that a reboot is required
  994. if (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED)
  995. g_v3state.m_bRebootNeeded = TRUE;
  996. }
  997. //remove the selected flag from the item
  998. InstallArr[i].pItem->ps->bChecked = FALSE;
  999. Progress.SetInstallAdd(1);
  1000. }
  1001. Progress.SetInstall(); //100%
  1002. // create return array
  1003. MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray);
  1004. // remove all items from selected items
  1005. g_v3state.m_selectedItems.Clear();
  1006. // close server connections
  1007. for (i = 0; i < iTotalItems; i++)
  1008. {
  1009. if (InstallArr[i].bServerNew)
  1010. {
  1011. delete InstallArr[i].pdl;
  1012. delete InstallArr[i].pdlRoot;
  1013. }
  1014. }
  1015. Progress.EndDisplay();
  1016. // delete any cached readthisfirst pages
  1017. CleanupReadThis();
  1018. }
  1019. catch (HRESULT hr)
  1020. {
  1021. if (pInfo != NULL)
  1022. {
  1023. // create return array
  1024. MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray);
  1025. }
  1026. else
  1027. {
  1028. return hr;
  1029. }
  1030. //
  1031. // if there was an error, we don't want to reboot
  1032. //
  1033. g_v3state.m_bRebootNeeded = FALSE;
  1034. //
  1035. // remove all items from m_selected
  1036. //
  1037. g_v3state.m_selectedItems.Clear();
  1038. // close server connections
  1039. for (i = 0; i < iTotalItems; i++)
  1040. {
  1041. if (InstallArr[i].bServerNew)
  1042. {
  1043. delete InstallArr[i].pdl;
  1044. delete InstallArr[i].pdlRoot;
  1045. }
  1046. if (!InstallArr[i].bHistoryWritten)
  1047. UpdateInstallHistory(InstallArr[i].pInfo, 1);
  1048. }
  1049. // delete any cached readthisfirst pages
  1050. CleanupReadThis();
  1051. return S_FALSE;
  1052. }
  1053. return S_OK;
  1054. }
  1055. STDMETHODIMP CCV3::GetInstallMetrics(
  1056. OUT RETVAL VARIANT *pMetricsArray
  1057. )
  1058. {
  1059. PSELECTITEMINFO pInfo;
  1060. PINVENTORY_ITEM pItem;
  1061. int iTotalSelectedItems;
  1062. try
  1063. {
  1064. iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal();
  1065. pInfo = g_v3state.m_selectedItems.GetItems();
  1066. MakeInstallMetricArray(pInfo, iTotalSelectedItems, pMetricsArray);
  1067. }
  1068. catch(HRESULT hr)
  1069. {
  1070. return hr;
  1071. }
  1072. return S_OK;
  1073. }
  1074. STDMETHODIMP CCV3::GetEula(
  1075. OUT RETVAL VARIANT *pEulaArray
  1076. )
  1077. {
  1078. PSELECTITEMINFO pInfo;
  1079. PINVENTORY_ITEM pItem;
  1080. int i;
  1081. int iTotalSelectedItems;
  1082. if (!m_bValidInstance)
  1083. {
  1084. return E_ACCESSDENIED;
  1085. }
  1086. try
  1087. {
  1088. //
  1089. // Walk though item array for each install item. Each item selected for installation
  1090. // is store in a puid array that is part of the g_v3state class. This is a performance
  1091. // enhancement. If we did not do this then we would need to walk through the entire
  1092. // state structure for each catalog for every item and check it's installation state.
  1093. //
  1094. iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal();
  1095. pInfo = g_v3state.m_selectedItems.GetItems();
  1096. MakeEulaArray(pInfo, iTotalSelectedItems, pEulaArray);
  1097. }
  1098. catch(HRESULT hr)
  1099. {
  1100. return hr;
  1101. }
  1102. return S_OK;
  1103. }
  1104. STDMETHODIMP CCV3::GetInstallHistory(
  1105. OUT RETVAL VARIANT *pHistoryArray
  1106. )
  1107. {
  1108. int i;
  1109. int iTotalItems;
  1110. Varray<HISTORYSTRUCT> History;
  1111. if (!m_bValidInstance)
  1112. {
  1113. return E_ACCESSDENIED;
  1114. }
  1115. try
  1116. {
  1117. //
  1118. // Walk though item array for each install item. Each item selected for installation
  1119. // is store in a puid array that is part of the g_v3state class. This is a performance
  1120. // enhancement. If we did not do this then we would need to walk through the entire
  1121. // state structure for each catalog for every item and check it's installation state.
  1122. //
  1123. ReadHistory(History, iTotalItems);
  1124. MakeInstallHistoryArray(History, iTotalItems, pHistoryArray);
  1125. }
  1126. catch(HRESULT hr)
  1127. {
  1128. return hr;
  1129. }
  1130. return S_OK;
  1131. }
  1132. STDMETHODIMP CCV3::GetDependencyList(
  1133. IN long puid,
  1134. OUT RETVAL VARIANT *pDependentItemsArray
  1135. )
  1136. {
  1137. return E_NOTIMPL;
  1138. }
  1139. STDMETHODIMP CCV3::GetCatalogItem(
  1140. IN long puid,
  1141. OUT RETVAL VARIANT *pCatalogItem
  1142. )
  1143. {
  1144. PINVENTORY_ITEM pItem;
  1145. HRESULT hrRet = S_OK;
  1146. if (!m_bValidInstance)
  1147. {
  1148. return E_ACCESSDENIED;
  1149. }
  1150. try
  1151. {
  1152. if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL))
  1153. hrRet = E_INVALIDARG;
  1154. else
  1155. hrRet = MakeReturnItemArray(pItem, pCatalogItem);
  1156. }
  1157. catch (HRESULT hr)
  1158. {
  1159. hrRet = hr;
  1160. }
  1161. return hrRet;
  1162. }
  1163. BOOL ConfirmUninstall(PINVENTORY_ITEM pItem)
  1164. {
  1165. USES_CONVERSION;
  1166. PWU_VARIABLE_FIELD pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
  1167. //
  1168. // Prefix bug NTBUG9#114181 warning (25): bounds violation (overflow) using buffer 'szResStr'
  1169. //
  1170. TCHAR szResStr[512];
  1171. if (LoadString(_Module.GetModuleInstance(), IDS_UNINSTALLCHECK, szResStr, sizeof(szResStr)/sizeof(TCHAR)) == 0)
  1172. {
  1173. TRACE("Unable to get resource string for uninstall check");
  1174. return FALSE;
  1175. }
  1176. TCHAR szMsg[1024];
  1177. wsprintf(szMsg, szResStr, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T(""));
  1178. DWORD dwMBFlags = MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_SETFOREGROUND;
  1179. if (IsArabicOrHebrew())
  1180. dwMBFlags |= MB_RTLREADING | MB_RIGHT;
  1181. if (MessageBox(GetActiveWindow(), szMsg, GetLocStr(IDS_APP_TITLE), dwMBFlags) != IDOK)
  1182. {
  1183. return FALSE;
  1184. }
  1185. return TRUE;
  1186. }
  1187. // confirms reboot, cleans up and reboot using a thread
  1188. BOOL CleanupAndReboot()
  1189. {
  1190. TCHAR szBuf[512];
  1191. // NOTE: we assume that GetLocStr will not return strings that will overflow this buffer
  1192. wsprintf(szBuf, _T("%s\n\n%s"), GetLocStr(IDS_REBOOT1), GetLocStr(IDS_REBOOT2));
  1193. // adadi Oct 6, 1999: arabic + hebrew hack
  1194. // we need to add the RTL flag if we're running on loc, but not enabled BIDI systems
  1195. // we don't want the dialog flipped with EN text on an enabled system
  1196. DWORD dwMBFlags = MB_ICONQUESTION | MB_YESNO | MB_TASKMODAL | MB_SETFOREGROUND;
  1197. if (IsArabicOrHebrew())
  1198. dwMBFlags |= MB_RTLREADING | MB_RIGHT;
  1199. UINT id = MessageBox(GetActiveWindow(), szBuf, GetLocStr(IDS_APP_TITLE), dwMBFlags);
  1200. if (id == IDNO)
  1201. return FALSE;
  1202. // cleanup
  1203. g_v3state.Reset();
  1204. CConnSpeed::WriteToRegistry();
  1205. // create a thread to reboot
  1206. DWORD dwThreadID;
  1207. HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RebootThreadProc, NULL, 0, &dwThreadID);
  1208. if (hThread != NULL)
  1209. {
  1210. // we close the handle because we don't need it. The thread will be destroyed after threadproc terminates
  1211. CloseHandle(hThread);
  1212. }
  1213. return TRUE;
  1214. }
  1215. DWORD WINAPI RebootThreadProc(LPVOID pv)
  1216. {
  1217. // Wait for 1 second and reboot the system
  1218. Sleep(1000);
  1219. (void)V3_RebootSystem();
  1220. return 0;
  1221. }
  1222. STDMETHODIMP CCV3::RemoveSelectedItems()
  1223. {
  1224. USES_CONVERSION;
  1225. PSELECTITEMINFO pInfo;
  1226. PINVENTORY_ITEM pItem;
  1227. PWU_VARIABLE_FIELD pvUninstall;
  1228. if (!m_bValidInstance)
  1229. {
  1230. return E_ACCESSDENIED;
  1231. }
  1232. try
  1233. {
  1234. //we need the os type for any device driver installs.
  1235. int iTotalItems = g_v3state.m_selectedItems.GetTotal();
  1236. HRESULT hr = NOERROR;
  1237. g_v3state.m_bRebootNeeded = FALSE;
  1238. pInfo = g_v3state.m_selectedItems.GetItems();
  1239. for (int i=0; i<iTotalItems; i++)
  1240. {
  1241. if (!pInfo[i].bInstall)
  1242. {
  1243. //
  1244. // if item has been selected for removal...
  1245. // confirm that the user wants to install the item. The user will be prompted
  1246. // for each uninstall
  1247. //
  1248. if (!g_v3state.GetCatalogAndItem(pInfo[i].puid, &pItem, NULL))
  1249. {
  1250. continue;
  1251. }
  1252. if (!ConfirmUninstall(pItem))
  1253. {
  1254. // do not uninstall this item
  1255. continue;
  1256. }
  1257. GetCurTime(&(pInfo[i].stDateTime));
  1258. if (pItem->recordType == WU_TYPE_CDM_RECORD)
  1259. {
  1260. hr = UninstallDriverItem(pItem, &pInfo[i]);
  1261. }
  1262. else
  1263. {
  1264. pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY);
  1265. if (pvUninstall != NULL)
  1266. {
  1267. //
  1268. // its possible that uninstall will reboot. We have no way of knowing that
  1269. // so we set the status initially to ITEM_STATUS_UNINSTALL_STARTED which
  1270. // gets translated to "Started" entry in the log
  1271. //
  1272. pInfo[i].iStatus = ITEM_STATUS_UNINSTALL_STARTED;
  1273. UpdateRemoveHistory(&pInfo[i], 1);
  1274. hr = UninstallActiveSetupItem(A2T((LPSTR)pvUninstall->pData));
  1275. }
  1276. else
  1277. {
  1278. hr = E_UNEXPECTED;
  1279. }
  1280. }
  1281. if (SUCCEEDED(hr))
  1282. {
  1283. pInfo[i].iStatus = ITEM_STATUS_SUCCESS;
  1284. pInfo[i].hrError = NOERROR;
  1285. pItem->ps->state = WU_ITEM_STATE_INSTALL;
  1286. }
  1287. else
  1288. {
  1289. pInfo[i].iStatus = ITEM_STATUS_INSTALLED_ERROR;
  1290. pInfo[i].hrError = hr;
  1291. //Fix #736: we leave the item state unchanged if the uninstall fails
  1292. }
  1293. pItem->ps->bChecked = FALSE;
  1294. //
  1295. // write history log for final status. We will write only the error case for active setup
  1296. // items which have already written "Started". For drivers we do not write the "Started"
  1297. // entry so we will write the history now for both success and failure
  1298. //
  1299. if (pItem->recordType == WU_TYPE_CDM_RECORD || pInfo[i].iStatus == ITEM_STATUS_INSTALLED_ERROR)
  1300. {
  1301. UpdateRemoveHistory(&pInfo[i], 1);
  1302. }
  1303. }
  1304. }
  1305. //
  1306. // remove all items from m_selected
  1307. //
  1308. g_v3state.m_selectedItems.Clear();
  1309. //
  1310. // reboot if an uninstall has indicated that we have to reboot
  1311. //
  1312. if (g_v3state.m_bRebootNeeded)
  1313. {
  1314. (void)CleanupAndReboot();
  1315. }
  1316. g_v3state.m_bRebootNeeded = FALSE;
  1317. }
  1318. catch(HRESULT _hr)
  1319. {
  1320. g_v3state.m_bRebootNeeded = FALSE;
  1321. return _hr;
  1322. }
  1323. return S_OK;
  1324. }
  1325. //
  1326. // NOTE: This method is no longer supported. We simply return S_OK for compatibility. We will remove
  1327. // this method
  1328. //
  1329. STDMETHODIMP CCV3::IsCatalogAvailable(
  1330. IN long puidCatalog, //Name of catalog to be read from the server.
  1331. IN BSTR bstrServerUrl //The http://servername/share location for the catalog to be retrieved.
  1332. )
  1333. {
  1334. HRESULT hr = S_OK;
  1335. return hr;
  1336. }
  1337. STDMETHODIMP CCV3::FinalizeInstall(IN long lFlags)
  1338. {
  1339. if (!m_bValidInstance)
  1340. {
  1341. return E_ACCESSDENIED;
  1342. }
  1343. if (lFlags & FINALIZE_DOREBOOT)
  1344. {
  1345. if (g_v3state.m_bRebootNeeded)
  1346. {
  1347. (void)CleanupAndReboot();
  1348. }
  1349. }
  1350. g_v3state.m_bRebootNeeded = FALSE;
  1351. return NOERROR;
  1352. }
  1353. STDMETHODIMP CCV3::SetStrings(IN VARIANT* vStringsArr, IN long lType)
  1354. {
  1355. if (!m_bValidInstance)
  1356. {
  1357. return E_ACCESSDENIED;
  1358. }
  1359. return SetStringsFromSafeArray(vStringsArr, lType);
  1360. }
  1361. STDMETHODIMP CCV3::FixCompatRollbackKey(VARIANT_BOOL *pbRegModified)
  1362. {
  1363. const TCHAR* pszIEVersionRegKey = _T("Software\\Microsoft\\Internet Explorer");
  1364. const TCHAR* pszIEUserAgentCompatKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\User Agent\\Post Platform");
  1365. const TCHAR* pszIEVersionRegValueName = _T("Version");
  1366. const TCHAR* pszIEUserAgentCompatValueName = _T("compat");
  1367. TCHAR szIEVersionValue[40];
  1368. DWORD dwDataType = 0;
  1369. DWORD dwDataLength = sizeof(szIEVersionValue);
  1370. HKEY IEVerKey = NULL;
  1371. HKEY IEUserAgentKey = NULL;
  1372. *pbRegModified = FALSE;
  1373. if (!m_bValidInstance)
  1374. {
  1375. return E_ACCESSDENIED;
  1376. }
  1377. //check the version key first - we don't care what the UA string says unless we have rolled back to IE4
  1378. if(ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszIEVersionRegKey, 0, KEY_QUERY_VALUE, &IEVerKey))
  1379. {
  1380. if(ERROR_SUCCESS == RegQueryValueEx(IEVerKey,pszIEVersionRegValueName,0,&dwDataType, (LPBYTE)szIEVersionValue,&dwDataLength))
  1381. {
  1382. if (szIEVersionValue[0] == '4') //check whether the first character is "4"
  1383. {
  1384. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,pszIEUserAgentCompatKey,0,KEY_SET_VALUE, &IEUserAgentKey))
  1385. {
  1386. if(ERROR_SUCCESS == RegDeleteValue(IEUserAgentKey,pszIEUserAgentCompatValueName))
  1387. {
  1388. *pbRegModified = TRUE;
  1389. }
  1390. RegCloseKey(IEUserAgentKey);
  1391. }
  1392. }
  1393. else // otherwise, this is IE5 - we'll piggyback another reg change onto this function
  1394. {
  1395. UpdateToolsURL();
  1396. }
  1397. }
  1398. RegCloseKey(IEVerKey);
  1399. }
  1400. return S_OK;
  1401. }
  1402. void CCV3::UpdateToolsURL()
  1403. {
  1404. LOG_block("UpdateToolsURL");
  1405. const TCHAR DEFAULT_WU_URL[] = _T("http://windowsupdate.microsoft.com/");
  1406. const TCHAR WU_TOOLMENU_PARAM[] = _T("IE");
  1407. const TCHAR REGKEY_IE_URLS[] = _T("Software\\Microsoft\\Internet Explorer\\Help_Menu_Urls");
  1408. const TCHAR REGVALUENAME_WU_URL[] = _T("3");
  1409. const TCHAR REGKEY_WU_URL[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate");
  1410. const TCHAR REGVALUENAME_WU_Start_URL[] = _T("URL");
  1411. const TCHAR WU_STARTMENU_PARAM[] = _T("Start");
  1412. HKEY hkIEURLKey = 0;
  1413. HKEY hkWUURLKey = 0;
  1414. DWORD dwDisposition = REG_OPENED_EXISTING_KEY;
  1415. TCHAR tszUpdateURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
  1416. TCHAR tszStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
  1417. TCHAR tszNewStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0");
  1418. wsprintf( tszUpdateURL, _T("%s?%s"), DEFAULT_WU_URL, WU_TOOLMENU_PARAM );
  1419. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_IE_URLS, 0, (LPTSTR)NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkIEURLKey, &dwDisposition ) )
  1420. {
  1421. if( ERROR_SUCCESS == RegSetValueEx( hkIEURLKey, REGVALUENAME_WU_URL, 0, REG_SZ, (LPBYTE) tszUpdateURL, lstrlen(tszUpdateURL) * sizeof(TCHAR) ) )
  1422. {
  1423. LOG_out("Updated Tools URL to %s", tszUpdateURL);
  1424. }
  1425. RegCloseKey( hkIEURLKey );
  1426. }
  1427. //take the existing WU regkey and make sure it has "?Start" appended to it
  1428. // this will misbehave in the following two cases:
  1429. // 1) if the URL key exists but is invalid (such as spaces) - can only hapen if a user manually edits the key
  1430. // 2) if the URL contains a fragment (# + parameter)
  1431. // 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)
  1432. 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 ))
  1433. {
  1434. DWORD dwSize = sizeof(tszStartMenuURL);
  1435. (void) RegQueryValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, 0, (LPBYTE)&tszStartMenuURL, &dwSize);
  1436. if(0 != lstrcmp(tszStartMenuURL, _T(""))) // if the reg value isn't blank
  1437. {
  1438. LOG_out("Current Start Menu URL: %s", tszStartMenuURL);
  1439. if( NULL == _tcsstr(tszStartMenuURL, _T("?"))) // if there isn't already a querystring on the URL, make the url currenturl?param
  1440. {
  1441. wsprintf(tszNewStartMenuURL, _T("%s?%s"), tszStartMenuURL, WU_STARTMENU_PARAM);
  1442. RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
  1443. LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL);
  1444. }
  1445. else // if there's already a parameter
  1446. {
  1447. if(NULL != _tcsstr(tszStartMenuURL, WU_STARTMENU_PARAM))//if it already has "Start", bail
  1448. {
  1449. // do nothing
  1450. }
  1451. else//otherwise make the url currenturl?param&newparam
  1452. {
  1453. wsprintf(tszNewStartMenuURL, _T("%s&%s"), tszStartMenuURL, WU_STARTMENU_PARAM);
  1454. RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
  1455. LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL);
  1456. }
  1457. }
  1458. }
  1459. else // if the reg value is blank, use the default WU URL + "?Start"
  1460. {
  1461. wsprintf(tszNewStartMenuURL, _T("%s?%s"), DEFAULT_WU_URL, WU_STARTMENU_PARAM);
  1462. RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR));
  1463. LOG_out("Updated Start Menu URL to %s", tszNewStartMenuURL);
  1464. }
  1465. RegCloseKey(hkWUURLKey);
  1466. }
  1467. }
  1468. // This function converts our internal V3 catalog structure into a safearray of variants
  1469. // that the VBScript web page uses. The format of the safe array will be:
  1470. // array(i,0) = NUMBER puid
  1471. // array(i,1) = STRING TITLE
  1472. // array(i,2) = STRING Description
  1473. // array(i,3) = NUMBER Item Status
  1474. // array(i,4) = NUMBER Download Size in Bytes
  1475. // array(i,5) = NUMBER Download Time in seconds
  1476. // array(i,6) = STRING Uninstall Key
  1477. // array(i,7) = STRING Read This Url
  1478. HRESULT CCV3::MakeReturnCatalogArray(
  1479. CCatalog *pCatalog, //Pointer to catalog structure to be converted.
  1480. long lFilters, //Filters to apply, see GetCatalog for the actual descriptions.
  1481. long lFlags, //Flags that control the amount of information returned in each array record.
  1482. VARIANT *pvaVariant //pointer to returned safearray.
  1483. )
  1484. {
  1485. USES_CONVERSION;
  1486. PUID puid;
  1487. PWSTR pTitle;
  1488. PWSTR pDescription;
  1489. PSTR pUninstall;
  1490. PWSTR pReadThisUrl;
  1491. HRESULT hr;
  1492. LPVARIANT rgElems;
  1493. LPSAFEARRAY psa;
  1494. SAFEARRAYBOUND rgsabound[2];
  1495. PINVENTORY_ITEM pItem;
  1496. PWU_VARIABLE_FIELD pv;
  1497. PWU_VARIABLE_FIELD pvTitle;
  1498. PWU_VARIABLE_FIELD pvDescription;
  1499. PWU_VARIABLE_FIELD pvUninstall;
  1500. PWU_VARIABLE_FIELD pvRTF;
  1501. PWU_VARIABLE_FIELD pvAltName;
  1502. int i;
  1503. int t;
  1504. int size;
  1505. int downloadTime;
  1506. TCHAR szRTF[MAX_PATH];
  1507. if ( !pvaVariant )
  1508. return E_INVALIDARG;
  1509. VariantInit(pvaVariant);
  1510. hr = NOERROR;
  1511. rgsabound[0].lLbound = 0;
  1512. rgsabound[0].cElements = 0;
  1513. rgsabound[1].lLbound = 0;
  1514. rgsabound[1].cElements = 8;
  1515. // count number records to return
  1516. for(i=0; i<pCatalog->GetHeader()->totalItems; i++)
  1517. {
  1518. pItem = pCatalog->GetItem(i);
  1519. if (NULL == pItem)
  1520. {
  1521. continue;
  1522. }
  1523. if ( !FilterCatalogItem(pItem, lFilters) )
  1524. continue;
  1525. rgsabound[0].cElements++;
  1526. }
  1527. psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
  1528. if (!psa)
  1529. return E_OUTOFMEMORY;
  1530. // plug references to the data into the SAFEARRAY
  1531. if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems)))
  1532. return hr;
  1533. for(i = 0, t = 0; i < pCatalog->GetHeader()->totalItems; i++)
  1534. {
  1535. pItem = pCatalog->GetItem(i);
  1536. if (NULL == pItem)
  1537. {
  1538. continue;
  1539. }
  1540. if (!FilterCatalogItem(pItem, lFilters))
  1541. {
  1542. TRACE("Filtering (%d) skipped PUID %d while building SaveArray", lFilters, pItem->GetPuid());
  1543. continue;
  1544. }
  1545. if (!pItem->pd)
  1546. {
  1547. TRACE("PUID %d skipped while building SaveArray - no description", pItem->GetPuid());
  1548. continue;
  1549. }
  1550. size = pItem->pd->size;
  1551. downloadTime = CalcDownloadTime(size, pItem->pd->downloadTime);
  1552. pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid);
  1553. if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) )
  1554. pTitle = (PWSTR)pvTitle->pData;
  1555. else
  1556. pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR
  1557. if (pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION))
  1558. pDescription = (PWSTR)pvDescription->pData;
  1559. else
  1560. pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR
  1561. // uninstall/altname field
  1562. pUninstall = ""; // SafeArray should return empty string, not NULL BSTR
  1563. if (pItem->recordType == WU_TYPE_CDM_RECORD)
  1564. {
  1565. //NOTE: we are simply returning a key that says script should put the uninstall button
  1566. // currently we will always display this button but we will change this to only
  1567. // display it when the driver can be uninstalled
  1568. pUninstall = "DriverUninstall";
  1569. }
  1570. else if (pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD)
  1571. {
  1572. if ((pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY)))
  1573. {
  1574. pUninstall = (char *)pvUninstall->pData;
  1575. }
  1576. }
  1577. else
  1578. {
  1579. // for everything else, we pass the AltName field if provided
  1580. if ((pvAltName = pItem->pd->pv->Find(WU_DESC_ALTNAME)))
  1581. {
  1582. pUninstall = (char *)pvAltName->pData;
  1583. }
  1584. }
  1585. // read this first page
  1586. if ((pvRTF = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY)))
  1587. {
  1588. TCHAR szTemp[MAX_PATH];
  1589. GetWindowsUpdateDirectory(szTemp);
  1590. wsprintf(szRTF, _T("file://%sRTF\\%d\\%d.htm"), szTemp, pItem->GetPuid(), pItem->GetPuid());
  1591. pReadThisUrl = szRTF;
  1592. }
  1593. else
  1594. {
  1595. pReadThisUrl = _T(""); // SafeArray should return empty string, not NULL BSTR
  1596. }
  1597. try
  1598. {
  1599. TRACE("PUID %d added to SaveArray with ReturnStatus %d", pItem->GetPuid(), GetItemReturnStatus(pItem));
  1600. /*
  1601. // Noisy Debug Only
  1602. TRACE("\t%S",pTitle);
  1603. TRACE("\t%S", pDescription);
  1604. TRACE("\t%d", GetItemReturnStatus(pItem));
  1605. TRACE("\t%d", size);
  1606. TRACE("\t%d", downloadTime);
  1607. TRACE("\t%s", pUninstall);
  1608. TRACE("\t%s", pReadThisUrl);
  1609. */
  1610. AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements,
  1611. "%d%s%s%d%d%d%s%s",
  1612. puid,
  1613. pTitle,
  1614. pDescription,
  1615. GetItemReturnStatus(pItem),
  1616. size,
  1617. downloadTime,
  1618. A2W(pUninstall),
  1619. pReadThisUrl);
  1620. t++;
  1621. }
  1622. catch(HRESULT hr)
  1623. {
  1624. TRACE("Exception thrown calling AddSafeArrayRecord");
  1625. for (; t; t--)
  1626. DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d%d%d%s%s");
  1627. SafeArrayUnaccessData(psa);
  1628. VariantInit(pvaVariant);
  1629. throw hr;
  1630. }
  1631. }
  1632. SafeArrayUnaccessData(psa);
  1633. V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT;
  1634. V_ARRAY(pvaVariant) = psa;
  1635. return NOERROR;
  1636. }
  1637. // This function converts our internal V3 catalog structure for inventory.plt catalogs into a
  1638. // safearray of variants that the VBScript web page uses. The format of the safe array will be:
  1639. // array(i,0) = NUMBER puid
  1640. // array(i,1) = STRING TITLE
  1641. // array(i,2) = STRING Description
  1642. // array(i,3) = NUMBER Item Status
  1643. HRESULT CCV3::MakeReturnCatalogListArray(
  1644. CCatalog *pCatalog, //Pointer to catalog structure to be converted.
  1645. long lFilters, //Filters to apply, see GetCatalog for the actual descriptions.
  1646. long lFlags, //Flags that control the amount of information returned in each array record.
  1647. VARIANT *pvaVariant //pointer to returned safearray.
  1648. )
  1649. {
  1650. PUID puid;
  1651. PWSTR pTitle;
  1652. PWSTR pDescription;
  1653. HRESULT hr;
  1654. LPVARIANT rgElems;
  1655. LPSAFEARRAY psa;
  1656. SAFEARRAYBOUND rgsabound[2];
  1657. PINVENTORY_ITEM pItem;
  1658. PWU_VARIABLE_FIELD pv;
  1659. PWU_VARIABLE_FIELD pvTitle;
  1660. PWU_VARIABLE_FIELD pvDescription;
  1661. PWU_VARIABLE_FIELD pvUninstall;
  1662. int i;
  1663. int t;
  1664. int size;
  1665. int downloadTime;
  1666. if ( !pvaVariant )
  1667. return E_INVALIDARG;
  1668. VariantInit(pvaVariant);
  1669. hr = NOERROR;
  1670. rgsabound[0].lLbound = 0;
  1671. rgsabound[0].cElements = 0;
  1672. rgsabound[1].lLbound = 0;
  1673. rgsabound[1].cElements = 4;
  1674. // count number records to return
  1675. for(i=0; i<pCatalog->GetHeader()->totalItems; i++)
  1676. {
  1677. if (NULL == (pItem = pCatalog->GetItem(i)))
  1678. {
  1679. continue;
  1680. }
  1681. if ( !FilterCatalogItem(pItem, lFilters) )
  1682. continue;
  1683. rgsabound[0].cElements++;
  1684. }
  1685. psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
  1686. if ( !psa )
  1687. return E_OUTOFMEMORY;
  1688. // plug references to the data into the SAFEARRAY
  1689. if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems)))
  1690. return hr;
  1691. for(i=0,t=0; i<pCatalog->GetHeader()->totalItems; i++)
  1692. {
  1693. if (NULL == (pItem = pCatalog->GetItem(i)))
  1694. {
  1695. continue;
  1696. }
  1697. if ( !FilterCatalogItem(pItem, lFilters) )
  1698. continue;
  1699. //array(i,0) = NUMBER puid
  1700. //array(i,1) = STRING TITLE
  1701. //array(i,2) = STRING Description
  1702. //array(i,3) = NUMBER Item Status
  1703. pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid);
  1704. if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) )
  1705. pTitle = (PWSTR)pvTitle->pData;
  1706. else
  1707. pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR
  1708. if ( pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION) )
  1709. pDescription = (PWSTR)pvDescription->pData;
  1710. else
  1711. pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR
  1712. try
  1713. {
  1714. AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d",
  1715. puid, pTitle, pDescription, GetItemReturnStatus(pItem));
  1716. t++;
  1717. }
  1718. catch(HRESULT hr)
  1719. {
  1720. for (; t; t--)
  1721. DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d");
  1722. SafeArrayUnaccessData(psa);
  1723. VariantInit(pvaVariant);
  1724. throw hr;
  1725. }
  1726. }
  1727. SafeArrayUnaccessData(psa);
  1728. V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT;
  1729. V_ARRAY(pvaVariant) = psa;
  1730. return NOERROR;
  1731. }
  1732. void DetectActiveSetupWU(
  1733. CWUDownload* pDownload, // CWUDLOAD download class to be used to download detection DLLs.
  1734. CDiamond* pDiamond, // Diamond Expansion class.
  1735. CCatalog* pCatalog // catalog that detection CIF is to be created from.
  1736. )
  1737. {
  1738. USES_CONVERSION;
  1739. int cItemsDetected = 0;
  1740. PWU_VARIABLE_FIELD pVar;
  1741. DWORD dwDetectStatus;
  1742. CComponentDetection CompDet;
  1743. LOG_block("DetectActiveSetupWU");
  1744. //check input argument if valid
  1745. if (NULL == pCatalog)
  1746. {
  1747. return ;
  1748. }
  1749. for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  1750. {
  1751. PINVENTORY_ITEM pItem = pCatalog->GetItem(i);
  1752. //check if the function GetItem has returned valid value
  1753. if (NULL == pItem)
  1754. {
  1755. continue;
  1756. }
  1757. if (pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD || (pItem->ps->state == WU_ITEM_STATE_PRUNED))
  1758. continue;
  1759. if (!IsValidGuid(&pItem->pf->a.g))
  1760. continue;
  1761. WCHAR wszGuid[64];
  1762. if (StringFromGUID2(pItem->pf->a.g, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0])) == 0)
  1763. continue;
  1764. PUID puid = pItem->GetPuid();
  1765. LOG_out("puid %d", puid);
  1766. if (puid <= 0)
  1767. {
  1768. continue;
  1769. }
  1770. //
  1771. // we have a valid component to detect
  1772. //
  1773. cItemsDetected++;
  1774. // guid
  1775. CompDet.SetValue(CComponentDetection::ccGUID, W2A(wszGuid));
  1776. // version
  1777. char szVersion[64];
  1778. VersionToString(&pItem->pf->a.version, szVersion);
  1779. CompDet.SetValue(CComponentDetection::ccVersion, szVersion);
  1780. //
  1781. // detection dll variable fields
  1782. //
  1783. char szDllName[128];
  1784. szDllName[0] = '\0';
  1785. if (pItem->pv->Find(WU_DETECT_DLL_REG_KEY_EXISTS))
  1786. {
  1787. // WUDETECT.DLL,RegKeyExists special case
  1788. CompDet.SetValue(CComponentDetection::ccDetectVersion, "wudetect.dll,RegKeyExists");
  1789. strcpy(szDllName, "wudetect.bin");
  1790. }
  1791. if ((pVar = pItem->pv->Find(WU_DETECT_DLL_GENERIC)))
  1792. {
  1793. LPSTR ptr;
  1794. // generic detection DLL including WUDETECT.DLL,RegKeyVersion case
  1795. CompDet.SetValue(CComponentDetection::ccDetectVersion, (LPCSTR)pVar->pData);
  1796. // parse out detection dll name from DetectVersion= value
  1797. if ((ptr = (PSTR)_memccpy(szDllName, (char *)pVar->pData, '.', sizeof(szDllName))))
  1798. {
  1799. *(ptr - 1) = 0;
  1800. }
  1801. strcat(szDllName, ".bin");
  1802. }
  1803. //
  1804. // download the dll. Download DLL takes care of caching
  1805. //
  1806. if (szDllName[0] != '\0')
  1807. {
  1808. TCHAR szPath[MAX_PATH];
  1809. // construct full path for the detection dll
  1810. wsprintf(szPath, _T("Detect/%d/%s"), pCatalog->GetPlatform(), A2T(szDllName));
  1811. DownloadDLL(pDiamond, pDownload, A2T(szDllName), szPath);
  1812. }
  1813. //
  1814. // other variable length fields
  1815. //
  1816. if ((pVar = pItem->pv->Find(WU_KEY_CUSTOMDETECT)))
  1817. {
  1818. // custom data
  1819. CompDet.SetValue(CComponentDetection::ccCustomData, (LPCSTR)pVar->pData);
  1820. }
  1821. if ((pVar = pItem->pv->Find(WU_KEY_UNINSTALLKEY)))
  1822. {
  1823. // UninstallKey, remove quotes first
  1824. char szKeyVal[MAX_PATH];
  1825. LPCSTR pszKeyDat = (LPCSTR)pVar->pData;
  1826. if (pszKeyDat[0] == '"')
  1827. {
  1828. strcpy(szKeyVal, (pszKeyDat + 1));
  1829. int iKenLen = strlen(szKeyVal);
  1830. if (iKenLen > 0)
  1831. szKeyVal[iKenLen - 1] = '\0';
  1832. }
  1833. else
  1834. {
  1835. strcpy(szKeyVal, pszKeyDat);
  1836. }
  1837. CompDet.SetValue(CComponentDetection::ccUninstallKey, szKeyVal);
  1838. }
  1839. // locale
  1840. if (!(pVar = pItem->pv->Find(WU_DET_CIF_LOCALE)))
  1841. {
  1842. CompDet.SetValue(CComponentDetection::ccLocale, "*");
  1843. }
  1844. else
  1845. {
  1846. CompDet.SetValue(CComponentDetection::ccLocale, (LPCSTR)pVar->pData);
  1847. }
  1848. /*
  1849. DEBUG CODE ONLY
  1850. LOG_out("[%d]", pItem->GetPuid());
  1851. char buf[512];
  1852. if (CompDet.GetValue(CComponentDetection::ccGUID, buf, sizeof(buf))) LOG_out("%s=%s", "GUID", buf);
  1853. if (CompDet.GetValue(CComponentDetection::ccVersion, buf, sizeof(buf))) LOG_out("%s=%s", "Version", buf);
  1854. if (CompDet.GetValue(CComponentDetection::ccUninstallKey , buf, sizeof(buf))) LOG_out("%s=%s", "UninstallKey", buf);
  1855. if (CompDet.GetValue(CComponentDetection::ccDetectVersion, buf, sizeof(buf))) LOG_out("%s=%s", "DetectVersion", buf);
  1856. if (CompDet.GetValue(CComponentDetection::ccRegKeyVersion , buf, sizeof(buf))) LOG_out("%s=%s", "RegKeyVersion", buf);
  1857. if (CompDet.GetValue(CComponentDetection::ccLocale , buf, sizeof(buf))) LOG_out("%s=%s", "Locale", buf);
  1858. if (CompDet.GetValue(CComponentDetection::ccQFEVersion , buf, sizeof(buf))) LOG_out("%s=%s", "QFEVersion", buf);
  1859. if (CompDet.GetValue(CComponentDetection::ccCustomData , buf, sizeof(buf))) LOG_out("%s=%s", "CustomData", buf);
  1860. */
  1861. //
  1862. // now detect the item
  1863. //
  1864. dwDetectStatus = CompDet.Detect();
  1865. switch (dwDetectStatus)
  1866. {
  1867. case ICI_NOTINSTALLED: // 0 = item not installed(INSTALL)
  1868. pItem->ps->state = WU_ITEM_STATE_INSTALL;
  1869. LOG_out("puid %d not installed", pItem->GetPuid());
  1870. break;
  1871. case ICI_INSTALLED: // 1 = this item is curretly installed
  1872. pItem->ps->state = WU_ITEM_STATE_CURRENT;
  1873. LOG_out("puid %d installed current version", pItem->GetPuid());
  1874. break;
  1875. case ICI_NEWVERSIONAVAILABLE: // 2 Items is installed but newer available
  1876. pItem->ps->state = WU_ITEM_STATE_UPDATE;
  1877. { // we want to save currently installed version
  1878. DWORD dwInstalledVer;
  1879. DWORD dwInstalledBuild;
  1880. CompDet.GetInstalledVersion(&dwInstalledVer, &dwInstalledBuild);
  1881. pItem->ps->verInstalled.major = HIWORD(dwInstalledVer);
  1882. pItem->ps->verInstalled.minor = LOWORD(dwInstalledVer);
  1883. pItem->ps->verInstalled.build = HIWORD(dwInstalledBuild);
  1884. pItem->ps->verInstalled.ext = LOWORD(dwInstalledBuild);
  1885. LOG_out("puid %d installed version %d.%d.%d.%d and new version available ", pItem->GetPuid(),
  1886. pItem->ps->verInstalled.major, pItem->ps->verInstalled.minor, pItem->ps->verInstalled.build, pItem->ps->verInstalled.ext);
  1887. }
  1888. break;
  1889. case ICI_UNKNOWN: // 3 cannot be determined
  1890. case ICI_OLDVERSIONAVAILABLE: // 4 Why would anyone want to install the older version?
  1891. case ICI_NOTINITIALIZED: // 0xffffffff
  1892. default:
  1893. pItem->ps->bHidden = TRUE;
  1894. pItem->ps->state = WU_ITEM_STATE_PRUNED;
  1895. LOG_out("puid %d should be ignored and hidden", pItem->GetPuid());
  1896. break;
  1897. }
  1898. } // each item
  1899. LOG_out("%d items were detected", cItemsDetected);
  1900. }
  1901. void DownloadItem(
  1902. LPCTSTR pszLocalDir, //directory to download to. Must be created by caller
  1903. CWUDownload* pDownload, //Pointer to internet download class
  1904. CDiamond* pDiamond, //Pointer to compression class
  1905. PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure.
  1906. IWUProgress* pProgress
  1907. )
  1908. {
  1909. USES_CONVERSION;
  1910. BYTE itemFlags = 0;
  1911. BOOL bCloseConnection = FALSE;
  1912. DWORD platformId;
  1913. HRESULT hrError;
  1914. PWU_VARIABLE_FIELD pvCabs = NULL;
  1915. PWU_VARIABLE_FIELD pvCRCs = NULL;
  1916. PWU_VARIABLE_FIELD pvServer;
  1917. PWU_VARIABLE_FIELD pvTmp;
  1918. TCHAR szLocale[64];
  1919. BOOL b128Bit;
  1920. //Check if the input argument is not NULL
  1921. if ( (NULL == pInstallInfo) || (NULL == pInstallInfo->pItem) )
  1922. {
  1923. return ;
  1924. }
  1925. //See if the package has a server override defined.
  1926. if ((pvServer = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_SERVERROOT)))
  1927. {
  1928. pDownload = new CWUDownload((LPCTSTR)pvServer->pData);
  1929. bCloseConnection = TRUE;
  1930. }
  1931. try
  1932. {
  1933. if (pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
  1934. {
  1935. // if the item is hidden, look for the title in the TopLevel item
  1936. if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL))
  1937. {
  1938. PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
  1939. if (pvTopLvl)
  1940. {
  1941. pvTmp = pvTopLvl;
  1942. }
  1943. }
  1944. pProgress->SetStatusText(W2T((LPWSTR)(pvTmp->pData)));
  1945. }
  1946. //
  1947. // Calculate CIF path
  1948. //
  1949. pInstallInfo->pItem->GetFixedFieldInfo(WU_ITEM_FLAGS, &itemFlags);
  1950. // locale
  1951. if (pInstallInfo->dwLocaleID == 0)
  1952. {
  1953. if (itemFlags & WU_BROWSER_LANGAUGE_FLAG)
  1954. {
  1955. lstrcpy(szLocale, pInstallInfo->pCatalog->GetBrowserLocaleSZ());
  1956. }
  1957. else
  1958. {
  1959. wsprintf(szLocale, _T("0x%8.8x"), GetMachineLangDW());
  1960. }
  1961. }
  1962. else
  1963. {
  1964. wsprintf(szLocale, _T("0x%8.8x"), pInstallInfo->dwLocaleID);
  1965. }
  1966. // platform
  1967. if (pInstallInfo->dwPlatform == 0)
  1968. platformId = pInstallInfo->pCatalog->GetPlatform();
  1969. else
  1970. platformId = pInstallInfo->dwPlatform;
  1971. pInstallInfo->pInfo->iStatus = ITEM_STATUS_DOWNLOAD_COMPLETE;
  1972. pInstallInfo->pInfo->hrError = NOERROR;
  1973. //
  1974. // download files
  1975. //
  1976. if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD ||
  1977. pInstallInfo->pItem->recordType == WU_TYPE_CDM_RECORD ||
  1978. pInstallInfo->pItem->recordType == WU_TYPE_RECORD_TYPE_PRINTER)
  1979. {
  1980. b128Bit = FALSE;
  1981. if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD)
  1982. {
  1983. //download CIF
  1984. DownloadCif(pszLocalDir, pDiamond, pInstallInfo);
  1985. // check for 128 bit
  1986. if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
  1987. {
  1988. b128Bit = TRUE;
  1989. }
  1990. }
  1991. if (b128Bit)
  1992. {
  1993. // download 128 bit components
  1994. Download128Bit(pszLocalDir, pInstallInfo->pItem, pProgress);
  1995. }
  1996. else
  1997. {
  1998. // download install CABs
  1999. pvCabs = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_CABFILENAME);
  2000. pvCRCs = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CRC_ARRAY);
  2001. if (NULL == pvCabs || NULL == pvCRCs)
  2002. {
  2003. // Active setup items can have no cabs
  2004. if( pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD)
  2005. throw HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2006. }
  2007. else
  2008. {
  2009. DownloadCabs(pszLocalDir,
  2010. pDownload,
  2011. pDiamond,
  2012. (PBYTE)pvCabs->pData,
  2013. (PBYTE)pvCRCs->pData,
  2014. pProgress,
  2015. pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD);
  2016. }
  2017. }
  2018. }
  2019. else
  2020. {
  2021. throw E_UNEXPECTED;
  2022. }
  2023. }
  2024. catch(HRESULT hr)
  2025. {
  2026. //
  2027. // download failed
  2028. //
  2029. pInstallInfo->pInfo->hrError = hr;
  2030. pInstallInfo->pInfo->iStatus = ITEM_STATUS_FAILED;
  2031. if (bCloseConnection)
  2032. {
  2033. delete pDownload;
  2034. }
  2035. //
  2036. // ping URL to report failure
  2037. //
  2038. if (pInstallInfo->pTopLevelItem == NULL)
  2039. {
  2040. // for top level components only
  2041. URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ? URLPING_CANCELED : URLPING_FAILED);
  2042. }
  2043. throw hr;
  2044. }
  2045. if (bCloseConnection)
  2046. {
  2047. delete pDownload;
  2048. }
  2049. //
  2050. // ping URL to report success
  2051. //
  2052. if (pInstallInfo->pTopLevelItem == NULL)
  2053. {
  2054. URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, URLPING_SUCCESS);
  2055. }
  2056. }
  2057. // this function perform and installation of a catalog item. This function takes care
  2058. // of ensuring that the correct installer is called based on the package type.
  2059. void InstallItem(
  2060. LPCTSTR pszLocalDir, //Local client machine root directory the temp storage
  2061. PSELECTITEMINFO pStatusInfo, //Pointer to installation status array
  2062. PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure.
  2063. IWUProgress* pProgress
  2064. )
  2065. {
  2066. HRESULT hrError;
  2067. PWU_VARIABLE_FIELD pvTitle;
  2068. PWU_VARIABLE_FIELD pvTmp;
  2069. TCHAR szCIFFile[MAX_PATH];
  2070. BOOL bWindowsNT;
  2071. //check the input arguments
  2072. if (NULL == pszLocalDir || NULL == pStatusInfo || NULL == pInstallInfo)
  2073. {
  2074. return;
  2075. }
  2076. bWindowsNT = IsWindowsNT();
  2077. try
  2078. {
  2079. if (pvTitle = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
  2080. {
  2081. // if the item is hidden, look for the title in the TopLevel item
  2082. if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL))
  2083. {
  2084. PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE);
  2085. if (pvTopLvl)
  2086. {
  2087. pvTitle = pvTopLvl;
  2088. }
  2089. }
  2090. pProgress->SetStatusText(W2T((LPWSTR)(pvTitle->pData)));
  2091. }
  2092. GetCurTime(&(pStatusInfo->stDateTime));
  2093. pStatusInfo->iStatus = ITEM_STATUS_SUCCESS;
  2094. pStatusInfo->hrError = NOERROR;
  2095. TRACE("InstallItem, puid=%d, recordtype: %d", pInstallInfo->pItem->GetPuid(), (DWORD)pInstallInfo->pItem->recordType);
  2096. switch (pInstallInfo->pItem->recordType)
  2097. {
  2098. case WU_TYPE_ACTIVE_SETUP_RECORD:
  2099. BLOCK
  2100. {
  2101. TCHAR szCifBaseName[16];
  2102. wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid());
  2103. GetWindowsUpdateDirectory(szCIFFile);
  2104. lstrcat(szCIFFile, szCifBaseName);
  2105. }
  2106. //
  2107. // check to see if inseng is up to date (only done once)
  2108. //
  2109. CheckDllsToJit(pInstallInfo->pCatalog->GetCatalogServer());
  2110. //
  2111. // install active setup item
  2112. //
  2113. if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
  2114. {
  2115. // 128 bit
  2116. TCHAR szCmd[MAX_PATH];
  2117. long lRet;
  2118. lstrcpy(szCmd, pszLocalDir);
  2119. AddBackSlash(szCmd);
  2120. lstrcat(szCmd, EXENAME_128BIT);
  2121. lRet = LaunchProcess(szCmd, NULL, SW_NORMAL, TRUE);
  2122. }
  2123. else
  2124. {
  2125. InstallActiveSetupItem(pszLocalDir, szCIFFile, pStatusInfo, pProgress);
  2126. }
  2127. // delete CIF file
  2128. DeleteFile(szCIFFile);
  2129. break;
  2130. case WU_TYPE_CDM_RECORD:
  2131. InstallDriverItem(pszLocalDir, bWindowsNT, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T(""), pInstallInfo->pItem, pStatusInfo);
  2132. break;
  2133. case WU_TYPE_RECORD_TYPE_PRINTER:
  2134. {
  2135. PWU_VARIABLE_FIELD pvDriverName = pInstallInfo->pItem->pv->Find(WU_CDM_DRIVER_NAME);
  2136. PWU_VARIABLE_FIELD pvArchitecture = pInstallInfo->pItem->pv->Find(WU_CDM_PRINTER_DRIVER_ARCH);
  2137. if (NULL == pvDriverName)
  2138. throw E_UNEXPECTED; // should never happen
  2139. InstallPrinterItem((LPCTSTR)pvDriverName->pData, pszLocalDir,
  2140. NULL == pvArchitecture ? NULL : (LPCTSTR)pvArchitecture->pData);
  2141. }
  2142. break;
  2143. case WU_TYPE_CDM_RECORD_PLACE_HOLDER:
  2144. case WU_TYPE_SECTION_RECORD:
  2145. case WU_TYPE_SUBSECTION_RECORD:
  2146. case WU_TYPE_SUBSUBSECTION_RECORD:
  2147. default:
  2148. throw E_UNEXPECTED;
  2149. }
  2150. if(ITEM_STATUS_FAILED == pStatusInfo->iStatus)
  2151. {
  2152. URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED);
  2153. }
  2154. else
  2155. {
  2156. URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_SUCCESS);
  2157. }
  2158. }
  2159. catch(HRESULT hr)
  2160. {
  2161. pStatusInfo->hrError = hr;
  2162. pStatusInfo->iStatus = ITEM_STATUS_FAILED;
  2163. URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED);
  2164. }
  2165. }
  2166. //
  2167. // Download128Bit
  2168. // this shouldn't get called anymore since the US lifted export restrictions on 128 bit items:
  2169. // we don't create items with the 128 bit flag anymore
  2170. //
  2171. void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress)
  2172. {
  2173. USES_CONVERSION;
  2174. static const TCHAR FAILUREURL[] = _T("about:blank");
  2175. static const TCHAR FORMDATA[] = _T("selProdID=%s&Next=Download+Now%%21&failureURL=%s");
  2176. CWUDownload* pDL = NULL;
  2177. TCHAR szFormData[MAX_PATH];
  2178. TCHAR szLocalFile[MAX_PATH];
  2179. PWU_VARIABLE_FIELD pvTmp;
  2180. DWORD dwErr = ERROR_SUCCESS;
  2181. // get product id
  2182. if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_PRODID)))
  2183. throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2184. // build form data
  2185. wsprintf(szFormData, FORMDATA, A2T((LPSTR)pvTmp->pData), FAILUREURL);
  2186. // get URL
  2187. if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_URL)))
  2188. throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2189. // build local file name
  2190. lstrcpy(szLocalFile, pszLocalDir);
  2191. AddBackSlash(szLocalFile);
  2192. lstrcat(szLocalFile, EXENAME_128BIT);
  2193. // create download class
  2194. pDL = new CWUDownload(A2T((LPSTR)pvTmp->pData), 8192);
  2195. if (!pDL)
  2196. {
  2197. dwErr = GetLastError();
  2198. throw HRESULT_FROM_WIN32(dwErr);
  2199. }
  2200. if (!pDL->PostCopy(szFormData, szLocalFile, pProgress))
  2201. {
  2202. dwErr = GetLastError();
  2203. }
  2204. delete pDL;
  2205. if (dwErr != ERROR_SUCCESS)
  2206. throw HRESULT_FROM_WIN32(dwErr);
  2207. }
  2208. void DownloadCabs(
  2209. LPCTSTR szLocalDir, //Local client machine directory to use for temp storage
  2210. CWUDownload *pDownload, //Pointer to internet download class
  2211. CDiamond *pDiamond, //Pointer to compression class
  2212. PBYTE pCabList, //Multi SZ list of cabs to be downloaded.
  2213. PBYTE pCRCList, //array to CRC hash structures
  2214. IWUProgress* pProgress,
  2215. BOOL bUnCab
  2216. )
  2217. {
  2218. TCHAR szLocalFile[MAX_PATH];
  2219. TCHAR szServerFile[MAX_PATH];
  2220. TCHAR szLocalCab[128];
  2221. TCHAR szServerCab[128];
  2222. int iCabNo = 0;
  2223. V3_CreateDirectory(szLocalDir);
  2224. for (;;)
  2225. {
  2226. if (FAILED(GetCRCNameFromList(iCabNo, pCabList, pCRCList, szServerCab, sizeof(szServerCab), szLocalCab)))
  2227. break;
  2228. // build full paths
  2229. lstrcpy(szLocalFile, szLocalDir);
  2230. AddBackSlash(szLocalFile);
  2231. lstrcat(szLocalFile, szLocalCab);
  2232. lstrcpy(szServerFile, _T("CabPool/"));
  2233. lstrcat(szServerFile, szServerCab);
  2234. TRACE("Downloading %s", szServerFile);
  2235. if (!pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, 0, pProgress))
  2236. {
  2237. TRACE("Download of cab %s failed", szServerFile);
  2238. throw HRESULT_FROM_WIN32(GetLastError());
  2239. }
  2240. //
  2241. // check signature of the download CAB file
  2242. // Don't show an MS cert
  2243. // use VerifyFile (see WU bug # 12251)
  2244. //
  2245. HRESULT hr = VerifyFile(szLocalFile, TRUE);
  2246. TRACE("VerifyFile(%s) Result: %x (%s)", szLocalFile, hr, SUCCEEDED(hr) ? "SUCCESS" : "FAILURE");
  2247. if (FAILED(hr))
  2248. throw hr;
  2249. if (bUnCab)
  2250. {
  2251. if (pDiamond->IsValidCAB(szLocalFile))
  2252. {
  2253. TCHAR szUnCompFn[MAX_PATH];
  2254. lstrcpy(szUnCompFn, szLocalDir);
  2255. AddBackSlash(szUnCompFn);
  2256. lstrcat(szUnCompFn, _T("*"));
  2257. pDiamond->Decompress(szLocalFile, szUnCompFn);
  2258. //
  2259. // delete the CAB file after uncompressing
  2260. //
  2261. DeleteFile(szLocalFile);
  2262. }
  2263. }
  2264. iCabNo++;
  2265. }
  2266. }
  2267. void DownloadCif(
  2268. LPCTSTR szLocalDir, // Local client machine directory to use for temp storage
  2269. CDiamond *pDiamond, // Pointer to compression class
  2270. PINSTALLINFOSTRUCT pInstallInfo
  2271. )
  2272. {
  2273. V3_CreateDirectory(szLocalDir);
  2274. PWU_VARIABLE_FIELD pvCif = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CIF_CRC);
  2275. if (!pvCif)
  2276. {
  2277. TRACE("CIF CRC field missing");
  2278. throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2279. }
  2280. TCHAR szCifBaseName[16];
  2281. wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid());
  2282. TCHAR szCifCRCName[64];
  2283. HRESULT hr = MakeCRCName(szCifBaseName, (WUCRC_HASH*)pvCif->pData, szCifCRCName, sizeof(szCifCRCName));
  2284. if (FAILED(hr))
  2285. throw hr;
  2286. // create a temp file name for the .CIF file with .CI$
  2287. TCHAR szLocalFile[MAX_PATH];
  2288. TCHAR szServerFile[MAX_PATH];
  2289. lstrcpy(szLocalFile, szLocalDir);
  2290. AddBackSlash(szLocalFile);
  2291. lstrcat(szLocalFile, szCifBaseName);
  2292. LPTSTR pszDot = _tcschr(szLocalFile, _T('.'));
  2293. if (pszDot)
  2294. *pszDot = _T('\0');
  2295. lstrcat(szLocalFile, _T(".CI$"));
  2296. // server file name
  2297. wsprintf(szServerFile, _T("CRCCif/%s"), szCifCRCName);
  2298. if (!pInstallInfo->pdlRoot->Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL))
  2299. {
  2300. TRACE("Download of CIF cab %s failed", szServerFile);
  2301. throw HRESULT_FROM_WIN32(GetLastError());
  2302. }
  2303. // copy or uncompress to a .CIF file name
  2304. TCHAR szTemp[MAX_PATH];
  2305. GetWindowsUpdateDirectory(szTemp);
  2306. lstrcat(szTemp, szCifBaseName);
  2307. if (pDiamond->IsValidCAB(szLocalFile))
  2308. {
  2309. pDiamond->Decompress(szLocalFile, szTemp);
  2310. }
  2311. else
  2312. {
  2313. CopyFile(szLocalFile, szTemp, FALSE);
  2314. }
  2315. // NOTE:we don't delete the .CI$ file because all the files in the directory get deleted later
  2316. }
  2317. // download and save the FileVer.ini file in the cache
  2318. //
  2319. // NOTE: For 3.1 filever.ini file contains image download information as well
  2320. void DownloadFileVerInfo(CWUDownload* pDownload)
  2321. {
  2322. // if the file is missing, we don't have version information but we do not abort
  2323. (void)pDownload->Copy(FILEVERINI_FN, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL);
  2324. }
  2325. void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath)
  2326. {
  2327. //
  2328. // check our state detection dlls array to see if we downloaded
  2329. // this dll in this session already
  2330. //
  2331. // NOTE: We store the file name of the DLL as it is on the server OSDET.W98, wudetect.bin etc
  2332. //
  2333. TCHAR szDLLIn[MAX_PATH];
  2334. GetWindowsUpdateDirectory(szDLLIn);
  2335. lstrcat(szDLLIn, pszDLLName);
  2336. TCHAR szDLLOut[MAX_PATH];
  2337. lstrcpy(szDLLOut, szDLLIn);
  2338. TCHAR* ptr = _tcschr(szDLLOut, _T('.'));
  2339. if (ptr)
  2340. *ptr = 0;
  2341. lstrcat(szDLLOut, _T(".dll"));
  2342. if (g_v3state.CacheDLLName(pszDLLName))
  2343. {
  2344. //added by wei for test
  2345. TRACE("%s found in state cache", pszDLLName);
  2346. // doublecheck to make sure the DLL hasn't been deleted before we bail
  2347. if (FileExists(szDLLOut))
  2348. {
  2349. return;
  2350. }
  2351. }
  2352. //
  2353. // download the file
  2354. //
  2355. if (pszPath != NULL)
  2356. {
  2357. if (!pDownload->Copy(pszPath, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL))
  2358. throw HRESULT_FROM_WIN32(GetLastError());
  2359. }
  2360. else
  2361. {
  2362. if (!pDownload->Copy(pszDLLName, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL))
  2363. throw HRESULT_FROM_WIN32(GetLastError());
  2364. }
  2365. CConnSpeed::Learn(pDownload->GetCopySize(), pDownload->GetCopyTime());
  2366. //
  2367. // check to see if we download the file or the cached copy was used. If cache was used
  2368. // we just check to see if the DLL itself also exists, if yes then we return otherwise we
  2369. // will copy the or decompress the compressed file into the DLL
  2370. //
  2371. if (pDownload->CacheUsed())
  2372. {
  2373. if (FileExists(szDLLOut))
  2374. return;
  2375. }
  2376. if (pDiamond->IsValidCAB(szDLLIn))
  2377. pDiamond->Decompress(szDLLIn, szDLLOut);
  2378. else
  2379. CopyFile(szDLLIn, szDLLOut, FALSE);
  2380. }
  2381. void DetectPlatAndLang()
  2382. {
  2383. TCHAR szOSDETDLL[MAX_PATH];
  2384. GetWindowsUpdateDirectory(szOSDETDLL);
  2385. lstrcat(szOSDETDLL, _T("osdet.dll"));
  2386. //
  2387. // do platform and langauge detection using Osdet
  2388. //
  2389. CallOsDet(szOSDETDLL, &g_v3state.m_pdwPlatformList, &g_v3state.m_iTotalPlatforms);
  2390. //If we fail for any reason then use the default platform def_plat.
  2391. if ( !g_v3state.m_pdwPlatformList )
  2392. {
  2393. g_v3state.m_pdwPlatformList = (PULONG)&g_v3state.m_DefPlat;
  2394. g_v3state.m_iTotalPlatforms = 1;
  2395. }
  2396. }
  2397. //
  2398. // IObjectSafety
  2399. //
  2400. STDMETHODIMP CCV3::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
  2401. {
  2402. if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
  2403. return E_POINTER;
  2404. HRESULT hr = S_OK;
  2405. if (riid == IID_IDispatch)
  2406. {
  2407. *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
  2408. *pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
  2409. }
  2410. else
  2411. {
  2412. *pdwSupportedOptions = 0;
  2413. *pdwEnabledOptions = 0;
  2414. hr = E_NOINTERFACE;
  2415. }
  2416. return hr;
  2417. }
  2418. STDMETHODIMP CCV3::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
  2419. {
  2420. // If we're being asked to set our safe for scripting option then oblige
  2421. if (riid == IID_IDispatch)
  2422. {
  2423. // Store our current safety level to return in GetInterfaceSafetyOptions
  2424. m_dwSafety = dwEnabledOptions & dwOptionSetMask;
  2425. return S_OK;
  2426. }
  2427. return E_NOINTERFACE;
  2428. }
  2429. //
  2430. // IWUpdateCatalog interface
  2431. //
  2432. STDMETHODIMP CCV3::WUIsCatalogAvailable(long puidCatalog,BSTR bstrServerUrl)
  2433. {
  2434. return IsCatalogAvailable(puidCatalog, bstrServerUrl);
  2435. }
  2436. STDMETHODIMP CCV3::WUGetCatalog(long puidCatalog, BSTR bstrServerUrl, long platformId,
  2437. BSTR bstrBrowserLanguage, CCatalog** ppCatalogArray)
  2438. {
  2439. // we don't want to check the launch server from this interface
  2440. m_bLaunchServChecked = TRUE;
  2441. *ppCatalogArray = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, WU_ALL_ITEMS, WU_NO_PRUNING);
  2442. return S_OK;
  2443. }
  2444. STDMETHODIMP CCV3::WUDownloadItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir)
  2445. {
  2446. return E_NOTIMPL;
  2447. }
  2448. STDMETHODIMP CCV3::WUInstallItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir)
  2449. {
  2450. return E_NOTIMPL;
  2451. }
  2452. STDMETHODIMP CCV3::WURemoveItems(CSelections* pSelections)
  2453. {
  2454. return E_NOTIMPL;
  2455. }
  2456. STDMETHODIMP CCV3::WUCopyInstallHistory(HISTORYARRAY** ppHistoryArray)
  2457. {
  2458. int iTotalItems;
  2459. Varray<HISTORYSTRUCT> History;
  2460. PHISTORYARRAY pRetArray;
  2461. //Walk though item array for each install item. Each item selected for installation
  2462. //is store in a puid array that is part of the g_v3state class. This is a performance
  2463. //enhancement. If we did not do this then we would need to walk through the entire
  2464. //state structure for each catalog for every item and check it's installation state.
  2465. ReadHistory(History, iTotalItems);
  2466. //Since we must use the OLE allocator we now need to allocate the correct
  2467. //type of return memory and copy the existing history structure to it.
  2468. pRetArray = (PHISTORYARRAY)CoTaskMemAlloc(sizeof(HISTORYARRAY)+(iTotalItems * sizeof(HISTORYSTRUCT)));
  2469. if (NULL == pRetArray)
  2470. {
  2471. return HRESULT_FROM_WIN32(GetLastError());
  2472. }
  2473. pRetArray->iTotalItems = iTotalItems;
  2474. memcpy((char *)pRetArray->HistoryItems, &History[0], (iTotalItems * sizeof(HISTORYSTRUCT)));
  2475. *ppHistoryArray = pRetArray;
  2476. return S_OK;
  2477. }
  2478. STDMETHODIMP CCV3::WUCopyDependencyList(long puidItem, long** ppDepPui)
  2479. {
  2480. return E_NOTIMPL;
  2481. }
  2482. STDMETHODIMP CCV3::WUProgressDlg(BOOL bOn)
  2483. {
  2484. return E_NOTIMPL;
  2485. }
  2486. STDMETHODIMP CCV3::IsWinUpdDisabled(VARIANT_BOOL * pfDisabled)
  2487. {
  2488. *pfDisabled = FALSE;
  2489. if (!m_bValidInstance)
  2490. {
  2491. return E_ACCESSDENIED;
  2492. }
  2493. bool fDisabled = false;
  2494. HKEY hKey;
  2495. DWORD dwDisabled;
  2496. DWORD dwSize = sizeof(dwDisabled);
  2497. DWORD dwType;
  2498. HKEY hkeyRoot = IsWindowsNT() ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  2499. if ( RegOpenKeyEx( hkeyRoot,
  2500. REGPATH_EXPLORER,
  2501. NULL,
  2502. KEY_QUERY_VALUE,
  2503. &hKey) == ERROR_SUCCESS )
  2504. {
  2505. if ( RegQueryValueEx(hKey,
  2506. REGKEY_WINUPD_DISABLED,
  2507. NULL,
  2508. &dwType,
  2509. (LPBYTE)&dwDisabled,
  2510. &dwSize) == ERROR_SUCCESS )
  2511. {
  2512. if ( (dwType == REG_DWORD) && (dwDisabled != 0) )
  2513. {
  2514. *pfDisabled = TRUE;
  2515. }
  2516. }
  2517. RegCloseKey(hKey);
  2518. }
  2519. return S_OK;
  2520. }
  2521. STDMETHODIMP CCV3::IsReady(VARIANT_BOOL* pbYes)
  2522. {
  2523. *pbYes = TRUE;
  2524. return S_OK;
  2525. }
  2526. STDMETHODIMP CCV3::GetContentURL(OUT RETVAL VARIANT* pURL)
  2527. {
  2528. USES_CONVERSION;
  2529. VariantInit(pURL);
  2530. V_VT(pURL) = VT_BSTR;
  2531. pURL->bstrVal = SysAllocString(T2OLE((LPTSTR)g_v3state.GetContentServer()));
  2532. return S_OK;
  2533. }
  2534. // downloads the readthis first page and images for the puid locally
  2535. // script can then navigate to this page
  2536. STDMETHODIMP CCV3::GetReadThisPage(IN long puid)
  2537. {
  2538. CCatalog* pCatalog;
  2539. PINVENTORY_ITEM pItem;
  2540. if (!m_bValidInstance)
  2541. {
  2542. // the control is not launched from a trusted location
  2543. return E_ACCESSDENIED;
  2544. }
  2545. if (!g_v3state.GetCatalogAndItem(puid, &pItem, &pCatalog))
  2546. {
  2547. return E_INVALIDARG;
  2548. }
  2549. return DownloadReadThis(pItem);
  2550. }
  2551. STDMETHODIMP CCV3::GetPrintAllPage(OUT RETVAL VARIANT* pURL)
  2552. {
  2553. USES_CONVERSION;
  2554. const char READTHISLIST[] = "%READTHISLIST%"; // a semi-colon separated list of read this pages. For instance "readthis1.htm;readthis2.htm;readthis3.htm"
  2555. const char READTHISPATH[] = "%READTHISPATH%"; // the URL to the read this pages. For instance "file://d:\windowsupdate\"
  2556. TCHAR szSourceFile[MAX_PATH];
  2557. HRESULT hr;
  2558. DWORD dwFileSize = 0;
  2559. PBYTE pFileBuf = NULL;
  2560. HANDLE hFile;
  2561. DWORD dwBytes;
  2562. LPTSTR pszReadThisList = NULL;
  2563. if (!m_bValidInstance)
  2564. {
  2565. // the control is not launched from a trusted location
  2566. return E_ACCESSDENIED;
  2567. }
  2568. // download the printall page
  2569. GetWindowsUpdateDirectory(szSourceFile);
  2570. lstrcat(szSourceFile, _T("RTF"));
  2571. V3_CreateDirectory(szSourceFile);
  2572. hr = DownloadCommonRTFFiles(TRUE, szSourceFile);
  2573. if (FAILED(hr))
  2574. {
  2575. return hr;
  2576. }
  2577. // build a list of readthis first page names for all selected items
  2578. PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems();
  2579. int cSel = g_v3state.m_selectedItems.GetTotal();
  2580. if (cSel == 0)
  2581. {
  2582. // no items are selected
  2583. return S_OK;
  2584. }
  2585. // allocate enough memory for names of format puid\puid.htm;
  2586. pszReadThisList = (LPTSTR)malloc(cSel * 80);
  2587. if(!pszReadThisList)
  2588. {
  2589. return E_OUTOFMEMORY;
  2590. }
  2591. pszReadThisList[0] = _T('\0');
  2592. for (int iSel = 0; iSel < cSel; iSel++)
  2593. {
  2594. CCatalog* pCatalog;
  2595. PINVENTORY_ITEM pItem;
  2596. if (g_v3state.GetCatalogAndItem(pSel[iSel].puid, &pItem, &pCatalog))
  2597. {
  2598. if SUCCEEDED(DownloadReadThis(pItem))
  2599. {
  2600. TCHAR szTemp[24];
  2601. wsprintf(szTemp, _T("%d\\%d.htm"), pItem->GetPuid(), pItem->GetPuid());
  2602. if (pszReadThisList[0] != _T('\0'))
  2603. {
  2604. lstrcat(pszReadThisList, _T(";"));
  2605. }
  2606. lstrcat(pszReadThisList, szTemp);
  2607. }
  2608. }
  2609. } //for
  2610. if (pszReadThisList[0] == _T('\0'))
  2611. {
  2612. // no items selected with readthisfirst pages
  2613. free(pszReadThisList);
  2614. return S_OK;
  2615. }
  2616. // read the file in memory with a null appended at the end
  2617. hFile = CreateFile(szSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  2618. if (hFile != INVALID_HANDLE_VALUE)
  2619. {
  2620. dwFileSize = GetFileSize(hFile, NULL);
  2621. if (dwFileSize > 0)
  2622. {
  2623. pFileBuf = (PBYTE)malloc(dwFileSize + 1);
  2624. if (pFileBuf != NULL)
  2625. {
  2626. if (!ReadFile(hFile, pFileBuf, dwFileSize, &dwBytes, NULL))
  2627. {
  2628. free(pFileBuf);
  2629. pFileBuf = NULL;
  2630. dwFileSize = 0;
  2631. }
  2632. pFileBuf[dwFileSize] = 0;
  2633. }
  2634. }
  2635. CloseHandle(hFile);
  2636. }
  2637. if (pFileBuf != NULL)
  2638. {
  2639. LPSTR pNewBuf;
  2640. TCHAR szDest[MAX_PATH];
  2641. GetWindowsUpdateDirectory(szDest);
  2642. lstrcat(szDest, _T("RTF\\"));
  2643. // replace tokens
  2644. if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISLIST, T2A(pszReadThisList)))
  2645. {
  2646. free(pFileBuf);
  2647. pFileBuf = (PBYTE)pNewBuf;
  2648. }
  2649. if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISPATH, T2A(szDest)))
  2650. {
  2651. free(pFileBuf);
  2652. pFileBuf = (PBYTE)pNewBuf;
  2653. }
  2654. // create the directory
  2655. lstrcat(szDest, _T("0\\"));
  2656. V3_CreateDirectory(szDest);
  2657. // write out the file
  2658. lstrcat(szDest, _T("printall.htm"));
  2659. hFile = CreateFile(szDest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
  2660. if (hFile != INVALID_HANDLE_VALUE)
  2661. {
  2662. if (!WriteFile(hFile, pFileBuf, strlen((LPSTR)pFileBuf), &dwBytes, NULL))
  2663. {
  2664. hr = HRESULT_FROM_WIN32(GetLastError());
  2665. }
  2666. CloseHandle(hFile);
  2667. }
  2668. else
  2669. {
  2670. hr = HRESULT_FROM_WIN32(GetLastError());
  2671. }
  2672. free(pFileBuf);
  2673. // return the path
  2674. TCHAR szRTF[MAX_PATH];
  2675. VariantInit(pURL);
  2676. wsprintf(szRTF, _T("file://%s"), szDest);
  2677. V_VT(pURL) = VT_BSTR;
  2678. pURL->bstrVal = SysAllocString(T2OLE(szRTF));
  2679. }
  2680. else
  2681. {
  2682. hr = HRESULT_FROM_WIN32(GetLastError());
  2683. }
  2684. return hr;
  2685. }
  2686. HRESULT DownloadReadThis(PINVENTORY_ITEM pItem)
  2687. {
  2688. LOG_block("DownloadReadThis");
  2689. BYTE mszFileNames[512];
  2690. TCHAR szBaseName[64];
  2691. TCHAR szLocalName[64];
  2692. TCHAR szServerName[64];
  2693. TCHAR szServerFile[MAX_PATH];
  2694. TCHAR szLocalFile[MAX_PATH];
  2695. TCHAR szLocalDir[MAX_PATH];
  2696. if (NULL == pItem->pd)
  2697. {
  2698. LOG_error("NULL == pItem->pd");
  2699. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2700. }
  2701. PWU_VARIABLE_FIELD pvRTFCRC = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY);
  2702. PWU_VARIABLE_FIELD pvRTFImages = pItem->pd->pv->Find(WU_DESC_RTF_IMAGES);
  2703. if (pvRTFCRC == NULL)
  2704. {
  2705. LOG_error("pvRTFCRC == NULL");
  2706. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2707. }
  2708. // build a multisz string of file names
  2709. int iLen = sprintf((char*)mszFileNames, "%d.htm", pItem->GetPuid());
  2710. mszFileNames[++iLen] = '\0';
  2711. if (pvRTFImages != NULL)
  2712. {
  2713. // we have images
  2714. memcpy(mszFileNames + iLen, pvRTFImages->pData, pvRTFImages->len - 4);
  2715. }
  2716. // build local directory
  2717. GetWindowsUpdateDirectory(szLocalDir);
  2718. wsprintf(szBaseName, _T("RTF\\%d"), pItem->GetPuid());
  2719. lstrcat(szLocalDir, szBaseName);
  2720. V3_CreateDirectory(szLocalDir);
  2721. // download common images and other files
  2722. (void)DownloadCommonRTFFiles(FALSE, NULL);
  2723. // create a download object
  2724. CWUDownload dlRoot(g_v3state.GetRootServer(), 8192);
  2725. int iFileNo = 0;
  2726. for (;;)
  2727. {
  2728. if (FAILED(GetCRCNameFromList(iFileNo, mszFileNames, pvRTFCRC->pData, szServerName, sizeof(szServerName), szLocalName)))
  2729. {
  2730. // end of the list
  2731. break;
  2732. }
  2733. // build full paths
  2734. lstrcpy(szLocalFile, szLocalDir);
  2735. AddBackSlash(szLocalFile);
  2736. lstrcat(szLocalFile, szLocalName);
  2737. lstrcpy(szServerFile, _T("CRCRtf/"));
  2738. lstrcat(szServerFile, szServerName);
  2739. TRACE("Downloading RTF %s", szServerFile);
  2740. if (!dlRoot.Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL))
  2741. {
  2742. LOG_error("Download of RTF %s failed", szServerFile);
  2743. return HRESULT_FROM_WIN32(GetLastError());
  2744. }
  2745. iFileNo++;
  2746. } // for
  2747. return S_OK;
  2748. }
  2749. // deletes any cached readthisfirst pages
  2750. bool CleanupReadThis()
  2751. {
  2752. LOG_block("CleanupReadThis");
  2753. // build local directory
  2754. TCHAR szRtfPath[MAX_PATH];
  2755. GetWindowsUpdateDirectory(szRtfPath);
  2756. PathAppend(szRtfPath, _T("RTF"));
  2757. return_if_false(DeleteNode(szRtfPath));
  2758. return true;
  2759. }
  2760. // download common images for read-this-first pages and the printall page
  2761. //
  2762. // if bPrintAll=TRUE, only printall.htm page is downloaded, pszPrintAllFN returns locale filename
  2763. // if bPrintAll=FALSE, mages are downloaded, pszPrintAllFN is not used and can be null
  2764. //
  2765. // NOTE: The function downloads images in WinUpdDir/RTF folder and expects it to exist
  2766. HRESULT DownloadCommonRTFFiles(BOOL bPrintAll, LPTSTR pszPrintAllFN)
  2767. {
  2768. const TCHAR SECNAME[] = _T("RTF");
  2769. const TCHAR COUNT[] = _T("Count");
  2770. const TCHAR IMGENTRY[] = _T("Img%d");
  2771. const TCHAR PRINTALL[] = _T("PrintAll");
  2772. TCHAR szLocalDir[MAX_PATH];
  2773. TCHAR szIniFile[MAX_PATH];
  2774. int iCount;
  2775. int iNo;
  2776. CWUDownload* pDownload = NULL;
  2777. TCHAR szBaseName[64];
  2778. TCHAR szServerFile[MAX_PATH];
  2779. TCHAR szLocalFile[MAX_PATH];
  2780. static BOOL bDoneImages = FALSE;
  2781. static BOOL bDonePrintAll = FALSE;
  2782. // build paths
  2783. GetWindowsUpdateDirectory(szLocalDir);
  2784. lstrcpy(szIniFile, szLocalDir);
  2785. lstrcat(szLocalDir, _T("RTF\\"));
  2786. lstrcat(szIniFile, FILEVERINI_FN);
  2787. if (GetPrivateProfileString(SECNAME, PRINTALL, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) != 0)
  2788. {
  2789. lstrcpy(szLocalFile, szLocalDir);
  2790. lstrcat(szLocalFile, szBaseName);
  2791. }
  2792. else
  2793. {
  2794. szLocalFile[0] = _T('\0');
  2795. }
  2796. if (bPrintAll && pszPrintAllFN != NULL)
  2797. {
  2798. lstrcpy(pszPrintAllFN, szLocalFile);
  2799. }
  2800. // if we are asked to downloaded the printall page and we have not done it in this sesssion
  2801. if (bPrintAll && !bDonePrintAll)
  2802. {
  2803. bDonePrintAll = TRUE;
  2804. //
  2805. // get the printall page
  2806. //
  2807. lstrcpy(szServerFile, g_v3state.GetSiteURL());
  2808. // find the last slash
  2809. int l = lstrlen(szServerFile);
  2810. while (l > 0 && szServerFile[l - 1] != _T('\\') && szServerFile[l - 1] != _T('/'))
  2811. l--;
  2812. if (l == 0)
  2813. return E_FAIL;
  2814. // put a null following the last slash
  2815. szServerFile[l] = _T('\0');
  2816. // create the download object using the site URL without the file name
  2817. try
  2818. {
  2819. pDownload = new CWUDownload(szServerFile, 8192);
  2820. }
  2821. catch(HRESULT hr)
  2822. {
  2823. return hr;
  2824. }
  2825. // download the file
  2826. (void)pDownload->Copy(szBaseName, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL);
  2827. delete pDownload;
  2828. }
  2829. // if we are asked to download images and we have not yet done them in this session
  2830. if (!bPrintAll && !bDoneImages)
  2831. {
  2832. bDoneImages = FALSE;
  2833. //
  2834. // download the images
  2835. //
  2836. iCount = (int)GetPrivateProfileInt(SECNAME, COUNT, 0, szIniFile);
  2837. if (iCount == 0)
  2838. {
  2839. return S_OK;
  2840. }
  2841. for (iNo = 1; iNo <= iCount; iNo++)
  2842. {
  2843. TCHAR szKey[32];
  2844. wsprintf(szKey, IMGENTRY, iNo);
  2845. if (GetPrivateProfileString(SECNAME, szKey, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) == 0)
  2846. {
  2847. // try next one
  2848. continue;
  2849. }
  2850. if (pDownload == NULL)
  2851. {
  2852. // we don't have a download object, create one
  2853. try
  2854. {
  2855. pDownload = new CWUDownload(g_v3state.GetContentServer(), 8192);
  2856. }
  2857. catch(HRESULT hr)
  2858. {
  2859. return hr;
  2860. }
  2861. }
  2862. // build file names
  2863. wsprintf(szServerFile, _T("images/%s"), szBaseName);
  2864. lstrcpy(szLocalFile, szLocalDir);
  2865. lstrcat(szLocalFile, szBaseName);
  2866. // download the file
  2867. (void)pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL);
  2868. }
  2869. if (pDownload != NULL)
  2870. {
  2871. delete pDownload;
  2872. }
  2873. }
  2874. return S_OK;
  2875. }
  2876. // this function validates the server the control was instantiated from
  2877. void CCV3::CheckLaunchServer()
  2878. {
  2879. USES_CONVERSION;
  2880. BOOL bValid;
  2881. HRESULT hr;
  2882. BSTR bstrURL;
  2883. TCHAR szURL[MAX_PATH];
  2884. if (m_bLaunchServChecked)
  2885. {
  2886. // we only want to do this check once
  2887. return;
  2888. }
  2889. m_bLaunchServChecked = TRUE;
  2890. bValid = FALSE;
  2891. // check to see we have a client site. This will be NULL if the contrainer has not
  2892. // called our IObjectWithSimpleSite interface to set the site.
  2893. if (m_spUnkSite != NULL)
  2894. {
  2895. // NOTE: We are using ATL smart pointers here which call release upon destruction
  2896. // QI for IServiceProvider from IUnknown of client site
  2897. CComQIPtr<IServiceProvider, &IID_IServiceProvider> spServProv(m_spUnkSite);
  2898. if (spServProv)
  2899. {
  2900. CComPtr<IWebBrowser2> spBrowser;
  2901. // QueryService for the IWebBrowser2
  2902. hr = spServProv->QueryService(SID_SInternetExplorer, IID_IWebBrowser2, (LPVOID*)&spBrowser);
  2903. if (SUCCEEDED(hr))
  2904. {
  2905. // get the location URL of the page that instantiated us
  2906. hr = spBrowser->get_LocationURL(&bstrURL);
  2907. if (SUCCEEDED(hr) && bstrURL)
  2908. {
  2909. lstrcpy(szURL, OLE2T(bstrURL));
  2910. SysFreeString(bstrURL);
  2911. // copy the entire site URL into the state structure
  2912. g_v3state.SetSiteURL(szURL);
  2913. // check to see if the host server matches
  2914. // any of the site urls specified in ident.cab
  2915. // this function will crack the site url and all
  2916. // the site server urls to compare the hosts
  2917. bValid = g_v3state.ValidateSiteURL();
  2918. }
  2919. } // queryservice
  2920. } // spServProv
  2921. } // m_spUnkSite
  2922. if (!bValid)
  2923. {
  2924. TRACE("CheckLauncServer: The control is launced from an untrusted server--aborting");
  2925. throw E_ACCESSDENIED;
  2926. }
  2927. }
  2928. //
  2929. // CDescriptionmMerger class
  2930. //
  2931. HRESULT CDescriptionMerger::CheckMerge(PINSTALLINFOSTRUCT pInstallInfo)
  2932. {
  2933. HRESULT hr = S_OK;
  2934. if (!pInstallInfo->pCatalog->LocalesDifferent())
  2935. {
  2936. // if the browser/machine locales are not different then we don't need to do anything
  2937. return hr;
  2938. }
  2939. if (pInstallInfo->pItem->pd->pv->Find(WU_VARIABLE_MERGEINACTIVE) != NULL)
  2940. {
  2941. // there is a WU_VARIABLE_MERGEINACTIVE which means we have already merged
  2942. return hr;
  2943. }
  2944. //
  2945. // we need merge the descriptions
  2946. //
  2947. if (m_pMap == NULL || m_pDiamond == NULL)
  2948. {
  2949. // create CCRCMapFile and CDiamond objects for this and future use for this object
  2950. // this method also sets m_pDiamond
  2951. hr = ReadMapFile(pInstallInfo->pCatalog);
  2952. }
  2953. if (SUCCEEDED(hr))
  2954. {
  2955. hr = pInstallInfo->pCatalog->MergeDescription(pInstallInfo->pdlRoot, m_pDiamond, pInstallInfo->pItem, m_pMap);
  2956. }
  2957. return hr;
  2958. }
  2959. HRESULT CDescriptionMerger::ReadMapFile(CCatalog* pCatalog)
  2960. {
  2961. HRESULT hr = S_OK;
  2962. TCHAR szMapFile[MAX_PATH];
  2963. BYTE* pMapMem;
  2964. DWORD dwMapLen;
  2965. // create download object for content server and a diamond object
  2966. CWUDownload dl(g_v3state.GetContentServer(), 8192);
  2967. m_pDiamond = new CDiamond;
  2968. // build path for crc map file for machine language
  2969. wsprintf(szMapFile, _T("%d_%s.des"),
  2970. pCatalog->GetPlatform(),
  2971. pCatalog->GetMachineLocaleSZ());
  2972. hr = DownloadFileToMem(&dl, szMapFile, m_pDiamond, &pMapMem, &dwMapLen);
  2973. if (SUCCEEDED(hr))
  2974. {
  2975. // create a crc map object with the memory image of the file
  2976. m_pMap = new CCRCMapFile(pMapMem, dwMapLen);
  2977. }
  2978. return hr;
  2979. }
  2980. #ifdef _WUV3TEST
  2981. // validates the description using diagnosis variable length fields
  2982. void CheckDescDiagInfo(CCatalog* pCatalog)
  2983. {
  2984. PINVENTORY_ITEM pItem;
  2985. PWU_VARIABLE_FIELD pvDiag;
  2986. DESCDIAGINFO* pDiagInfo;
  2987. int cGood = 0;
  2988. int cItems = 0;
  2989. for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++)
  2990. {
  2991. if (NULL == (pItem = pCatalog->GetItem(i)))
  2992. {
  2993. continue;
  2994. }
  2995. if ((pItem->ps->state != WU_ITEM_STATE_PRUNED))
  2996. {
  2997. pvDiag = pItem->pd->pv->Find(WU_DESC_DIAGINFO);
  2998. if (pvDiag != NULL)
  2999. {
  3000. pDiagInfo = (DESCDIAGINFO*)pvDiag->pData;
  3001. if (pDiagInfo->puid != pItem->GetPuid() ||
  3002. pDiagInfo->dwPlat != pCatalog->GetPlatform() ||
  3003. pDiagInfo->dwLocale != pCatalog->GetBrowserLocaleDW())
  3004. {
  3005. TRACE("CheckDescDiagInfo: puid=%d has invalid description", pItem->GetPuid());
  3006. }
  3007. else
  3008. {
  3009. cGood++;
  3010. }
  3011. }
  3012. else
  3013. {
  3014. TRACE("CheckDescDiagInfo: diagnosis information not found in descriptions");
  3015. break;
  3016. }
  3017. }
  3018. cItems++;
  3019. }
  3020. TRACE("CheckDescDiagInfo: %d good found for %d items compared", cGood, cItems);
  3021. }
  3022. #endif