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.

2826 lines
100 KiB

  1. //***************************************************************************
  2. //* Copyright (c) Microsoft Corporation 1995-1996. All rights reserved. *
  3. //***************************************************************************
  4. //* *
  5. //* ADVPACK.C - Advanced INF Installer. *
  6. //* *
  7. //***************************************************************************
  8. //***************************************************************************
  9. //* INCLUDE FILES *
  10. //***************************************************************************
  11. #include <io.h>
  12. #include <windows.h>
  13. #include <winerror.h>
  14. #include <ole2.h>
  15. #include "resource.h"
  16. #include "cpldebug.h"
  17. #include "ntapi.h"
  18. #include "advpub.h"
  19. #include "w95pub32.h"
  20. #include "advpack.h"
  21. #include "regstr.h"
  22. #include "globals.h"
  23. #include "cfgmgr32.h"
  24. #include "sfp.h"
  25. //***************************************************************************
  26. //* global defines *
  27. //***************************************************************************
  28. #define YES "1"
  29. #define NO "0"
  30. #define FILELIST_SIZE 10*BUF_1K
  31. //***************************************************************************
  32. //* globals *
  33. //***************************************************************************
  34. INFOPT RegInfOpt[] = { ADVINF_ADDREG, ADVINF_DELREG, ADVINF_BKREG }; // code below depending on this orders
  35. static PSTR gst_pszFiles;
  36. static PSTR gst_pszEndLastFile = NULL;
  37. static HRESULT gst_hNeedReboot;
  38. static PSTR gst_pszSmartReboot = NULL;
  39. const char c_szActiveSetupKey[] = "software\\microsoft\\Active Setup\\Installed Components";
  40. // globals for reg backup key and file names
  41. const char c_szRegUninstPath[] = "BackupRegPathName";
  42. const char c_szRegUninstSize[] = "BackupRegSize";
  43. const char c_szHiveKey_FMT[] = "AINF%04d";
  44. // NoBackupPlatform string table
  45. LPCSTR c_pszPlatform[] = { "win9x", "NT3.5", "NT4", "NT5", "NT5.1" };
  46. //-----------------------------------------------------------------------------------------
  47. //
  48. // PerUser section defines
  49. //
  50. //-----------------------------------------------------------------------------------------
  51. const CHAR REGVAL_OLDDISPN[]= "OldDisplayName";
  52. const CHAR REGVAL_OLDVER[]= "OldVersion";
  53. const CHAR REGVAL_OLDSTUB[]= "OldStubPath";
  54. const CHAR REGVAL_OLDLANG[]= "OldLocale";
  55. const CHAR REGVAL_OLDREALSTUBPATH[]= "OldRealStubPath";
  56. const CHAR REGVAL_REALSTUBPATH[]= "RealStubPath";
  57. const CHAR ADV_UNINSTSTUBWRAPPER[]= "rundll32.exe advpack.dll,UserUnInstStubWrapper %s";
  58. const CHAR ADV_INSTSTUBWRAPPER[]= "rundll32.exe advpack.dll,UserInstStubWrapper %s";
  59. const CHAR c_szRegDontAskValue[] = "DontAsk";
  60. /* Check the "Don't Ask" value. If it's present, its value
  61. * is interpreted as follows:
  62. *
  63. * 0 --> ask the user
  64. * 1 --> do not run the stub
  65. * 2 --> always run the stub
  66. */
  67. HRESULT ProcessOneRegSec( HWND hw, PCSTR pszTitle, PCSTR pszInf, PCSTR pszSec, HKEY hKey, HKEY hCUKey, DWORD dwFlags, BOOL *lpbOneRegSave );
  68. UINT WINAPI MyFileQueueCallback( PVOID Context,UINT Notification,UINT_PTR parm1,UINT_PTR parm2 );
  69. UINT WINAPI MyFileQueueCallback2( PVOID Context,UINT Notification,UINT_PTR parm1,UINT_PTR parm2 );
  70. void CleanRegLogFile( PCSTR pcszLogFileSecName );
  71. BOOL VerifyBackupInfo( HKEY hKey, HKEY hCUKey );
  72. void DeleteOldBackupData( HKEY hKey );
  73. //int DeleteSubKey(HKEY root, char *keyname);
  74. BOOL NeedBackupData(LPCSTR pszInf, LPCSTR pszSec);
  75. BOOL GetUniBackupName( HKEY hKey, LPSTR pszBackupBase, DWORD dwInSize, LPCSTR pszBackupPath, LPCSTR pszModule );
  76. //***************************************************************************
  77. extern PFSetupDefaultQueueCallback pfSetupDefaultQueueCallback;
  78. extern PFSetupInstallFromInfSection pfSetupInstallFromInfSection;
  79. extern PFSetupInitDefaultQueueCallbackEx pfSetupInitDefaultQueueCallbackEx;
  80. extern PFSetupTermDefaultQueueCallback pfSetupTermDefaultQueueCallback;
  81. //***************************************************************************
  82. //* *
  83. //* NAME: LaunchINFSectionEx *
  84. //* *
  85. //* SYNOPSIS: Detect which shell mode you are in and flip it over to *
  86. //* the other mode *
  87. //* *
  88. //* REQUIRES: *
  89. //* *
  90. //* RETURNS: *
  91. //* *
  92. //***************************************************************************
  93. HRESULT WINAPI LaunchINFSectionEx( HWND hwnd, HINSTANCE hInstance, PSTR pszParms, INT nShow )
  94. {
  95. LPSTR pszFlags;
  96. PCABINFO pcabInfo = NULL;
  97. HRESULT hRet = S_OK;
  98. AdvWriteToLog("LaunchINFSectionEx: Param= %1\r\n", pszParms);
  99. pcabInfo = (PCABINFO)LocalAlloc( LPTR, sizeof(CABINFO) );
  100. if ( !pcabInfo )
  101. {
  102. ErrorMsg( hwnd, IDS_ERR_NO_MEMORY );
  103. goto done;
  104. }
  105. // Parse the arguments, SETUP engine is not called. So we only need to check on \".
  106. pcabInfo->pszInf = GetStringField( &pszParms, ",", '\"', TRUE );
  107. pcabInfo->pszSection = GetStringField( &pszParms, ",", '\"', TRUE );
  108. pcabInfo->pszCab = GetStringField( &pszParms, ",", '\"', TRUE );
  109. pszFlags = GetStringField( &pszParms, ",", '\"', TRUE );
  110. gst_pszSmartReboot = GetStringField( &pszParms, ",", '\"', TRUE );
  111. if ( pszFlags != NULL )
  112. pcabInfo->dwFlags = My_atol(pszFlags);
  113. if ( pcabInfo->pszCab != NULL && *pcabInfo->pszCab )
  114. {
  115. if ( IsFullPath( pcabInfo->pszCab ) )
  116. {
  117. lstrcpy( pcabInfo->szSrcPath, pcabInfo->pszCab );
  118. GetParentDir( pcabInfo->szSrcPath );
  119. }
  120. else
  121. {
  122. ErrorMsg1Param( hwnd, IDS_ERR_CABPATH, pcabInfo->pszCab );
  123. goto done;
  124. }
  125. }
  126. // if we need to switch the mode. call ExecuteCab()
  127. hRet = ExecuteCab( hwnd, pcabInfo, NULL );
  128. done:
  129. if ( pcabInfo )
  130. LocalFree( pcabInfo );
  131. AdvWriteToLog("LaunchINFSectionEx: End hr=0x%1!x!\r\n",hRet);
  132. return hRet;
  133. }
  134. //***************************************************************************
  135. //* *
  136. //* NAME: ExecuteCab *
  137. //* *
  138. //* SYNOPSIS: Get INF from the cab and install it based on the flag. *
  139. //* *
  140. //* REQUIRES: hWnd: Handle to parent window. *
  141. //* *
  142. //* RETURNS: HRESULT: See advpub.h *
  143. //* *
  144. //***************************************************************************
  145. HRESULT WINAPI ExecuteCab( HWND hWnd, PCABINFO pcabInfo, PVOID pvReserved )
  146. {
  147. HRESULT hRet = S_OK, hRet1 = S_OK;
  148. DWORD dwFlags;
  149. char szFullPathInf[MAX_PATH];
  150. HKEY hKey = NULL;
  151. char szSec[MAX_PATH] = { 0 };
  152. DWORD dwSecSize = sizeof(szSec);
  153. BOOL bExtracF = FALSE;
  154. BOOL bExtractCatalog = FALSE;
  155. BOOL fSavedContext = FALSE;
  156. BOOL fTmpInf = FALSE;
  157. char szModule[MAX_PATH];
  158. char szCatalogName[MAX_PATH];
  159. AdvWriteToLog("ExecuteCab:");
  160. if (!SaveGlobalContext())
  161. {
  162. hRet1 = E_OUTOFMEMORY;
  163. goto done;
  164. }
  165. fSavedContext = TRUE;
  166. // Validate parameters:
  167. // if INF filename info is missing, invalid.
  168. if ( !pcabInfo || !(pcabInfo->pszInf) || !*(pcabInfo->pszInf) )
  169. return E_INVALIDARG;
  170. AdvWriteToLog("Inf = %1\r\n", pcabInfo->pszInf);
  171. ctx.hWnd = hWnd;
  172. // the flag ALINF_ROLLBACKDOALL includes meaning ALINF_ROLLBACK
  173. // TO avoid check both flag everywhere, we set both on if DOALL
  174. if ( pcabInfo->dwFlags & ALINF_ROLLBKDOALL )
  175. {
  176. pcabInfo->dwFlags |= ALINF_ROLLBACK;
  177. }
  178. // if INF is 8.3 format and the Cab file is given, extract INF out of the cab. Oterwise use it as it is.
  179. if ( pcabInfo->pszCab && *pcabInfo->pszCab )
  180. {
  181. if ( !IsFullPath( pcabInfo->pszInf ) )
  182. {
  183. if ( SUCCEEDED(hRet = ExtractFiles( pcabInfo->pszCab, pcabInfo->szSrcPath, 0, pcabInfo->pszInf, 0, 0) ) )
  184. bExtracF = TRUE;
  185. }
  186. }
  187. else
  188. {
  189. if ( pcabInfo->dwFlags & ALINF_ROLLBACK )
  190. {
  191. pcabInfo->dwFlags |= ALINF_ROLLBKDOALL;
  192. }
  193. }
  194. if ( !GetFullInfNameAndSrcDir( pcabInfo->pszInf, szFullPathInf, pcabInfo->szSrcPath ) )
  195. {
  196. hRet1 = E_INVALIDARG;
  197. goto done;
  198. }
  199. // if rollback case, we want to make the tmp INF file to use in case the rollback will delete the real file.
  200. if ( (pcabInfo->dwFlags & ALINF_ROLLBACK) && !bExtracF )
  201. {
  202. PSTR pszFile;
  203. char szPath[MAX_PATH];
  204. char ch;
  205. pszFile = ANSIStrRChr( szFullPathInf, '\\' );
  206. if ( pszFile )
  207. {
  208. ch = *pszFile;
  209. *pszFile = '\0';
  210. if ( GetTempFileName( szFullPathInf, "INF", 0, szPath ) )
  211. {
  212. DeleteFile( szPath );
  213. *pszFile = ch;
  214. if ( CopyFile( szFullPathInf, szPath, FALSE ) )
  215. {
  216. AdvWriteToLog("InfFile Rename: %1 becomes %2\r\n", szFullPathInf, szPath);
  217. fTmpInf = TRUE;
  218. lstrcpy( szFullPathInf, szPath );
  219. }
  220. }
  221. }
  222. }
  223. if ( pcabInfo->pszSection )
  224. lstrcpy( szSec, pcabInfo->pszSection );
  225. GetInfInstallSectionName( szFullPathInf, szSec, dwSecSize );
  226. // GetComponent Name
  227. if ( FAILED(GetTranslatedString( szFullPathInf, szSec, ADVINF_MODNAME,
  228. szModule, sizeof(szModule), NULL)) && szModule[0])
  229. {
  230. *szModule = '\0'; // Or should we exit if we don't find a module name????
  231. }
  232. // extract the catalog, if specified
  233. if (pcabInfo->pszCab && *pcabInfo->pszCab)
  234. {
  235. *szCatalogName = '\0';
  236. GetTranslatedString(szFullPathInf, szSec, ADVINF_CATALOG_NAME, szCatalogName, sizeof(szCatalogName), NULL);
  237. if (*szCatalogName)
  238. {
  239. if (SUCCEEDED(ExtractFiles(pcabInfo->pszCab, pcabInfo->szSrcPath, 0, szCatalogName, 0, 0)))
  240. bExtractCatalog = TRUE;
  241. }
  242. }
  243. // start Pre-rollback
  244. //
  245. dwFlags = COREINSTALL_PROMPT;
  246. dwFlags |= (pcabInfo->dwFlags & ALINF_NGCONV ) ? 0 : COREINSTALL_GRPCONV;
  247. if ( pcabInfo->dwFlags & ALINF_QUIET )
  248. ctx.wQuietMode = QUIETMODE_ALL;
  249. if ( pcabInfo->dwFlags & ALINF_CHECKBKDATA || pcabInfo->dwFlags & ALINF_ROLLBACK )
  250. {
  251. char szUninstall[MAX_PATH];
  252. CHAR szBuf[MAX_PATH];
  253. HKEY hCUKey = NULL;
  254. if ( pcabInfo->dwFlags & ALINF_ROLLBACK )
  255. {
  256. szUninstall[0] = 0;
  257. if ( SUCCEEDED(GetTranslatedString( szFullPathInf, szSec, ADVINF_PREROLBK,
  258. szUninstall, sizeof(szUninstall), NULL)) && szUninstall[0])
  259. {
  260. hRet = CoreInstall( szFullPathInf, szUninstall, pcabInfo->szSrcPath, 0, dwFlags, NULL );
  261. if ( FAILED( hRet ) )
  262. {
  263. hRet1 = hRet;
  264. goto done;
  265. }
  266. }
  267. }
  268. // if just want to checking backup data, process here and return
  269. //
  270. hRet1 = E_UNEXPECTED; //if HKLM does not have the \Advance INF setup\Module, it is unexpected.s
  271. if (*szModule)
  272. {
  273. // backup/restore the reg info referred by AddReg, DelReg, BackupReg lines inside the INF install section
  274. //
  275. lstrcpy( szBuf, REGKEY_SAVERESTORE );
  276. AddPath( szBuf, szModule );
  277. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szBuf, 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS)
  278. {
  279. RegOpenKeyEx( HKEY_CURRENT_USER, szBuf, 0, KEY_READ, &hCUKey);
  280. if ( VerifyBackupInfo( hKey, hCUKey ) )
  281. hRet1 = S_OK;
  282. else
  283. hRet1 = E_FAIL;
  284. }
  285. if ( hKey )
  286. RegCloseKey( hKey );
  287. if ( hCUKey )
  288. RegCloseKey( hCUKey );
  289. }
  290. if ( FAILED(hRet1) || (pcabInfo->dwFlags == ALINF_CHECKBKDATA) )
  291. {
  292. goto done;
  293. }
  294. }
  295. dwFlags |= (pcabInfo->dwFlags & ALINF_DELAYREGISTEROCX) ? COREINSTALL_DELAYREGISTEROCX : 0;
  296. dwFlags |= (pcabInfo->dwFlags & ALINF_BKINSTALL) ? COREINSTALL_BKINSTALL : 0;
  297. dwFlags |= (pcabInfo->dwFlags & ALINF_ROLLBACK) ? COREINSTALL_ROLLBACK : 0;
  298. dwFlags |= (pcabInfo->dwFlags & ALINF_ROLLBKDOALL) ? COREINSTALL_ROLLBKDOALL : 0;
  299. dwFlags |= COREINSTALL_SMARTREBOOT;
  300. hRet1 = CoreInstall( szFullPathInf, szSec, pcabInfo->szSrcPath, 0, dwFlags, gst_pszSmartReboot );
  301. // save the cab file info
  302. if ( SUCCEEDED( hRet1 ) && pcabInfo->pszCab && *pcabInfo->pszCab && (pcabInfo->dwFlags & ALINF_BKINSTALL) )
  303. {
  304. if ( hRet == ERROR_SUCCESS_REBOOT_REQUIRED )
  305. hRet1 = hRet;
  306. if (*szModule)
  307. {
  308. // reuse the buf so name is not acurate!!
  309. lstrcpy( szSec, REGKEY_SAVERESTORE );
  310. AddPath( szSec, szModule );
  311. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, szSec, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
  312. NULL, &hKey, &dwFlags ) == ERROR_SUCCESS )
  313. {
  314. RegSetValueEx( hKey, REGVAL_BKINSTCAB, 0, REG_SZ, pcabInfo->pszCab, lstrlen(pcabInfo->pszCab)+1 );
  315. RegCloseKey( hKey );
  316. }
  317. }
  318. }
  319. done:
  320. if ( bExtracF || fTmpInf )
  321. {
  322. // need to delete the INF file
  323. DeleteFile( szFullPathInf );
  324. }
  325. if (bExtractCatalog)
  326. {
  327. char szFullCatalogName[MAX_PATH];
  328. lstrcpy(szFullCatalogName, pcabInfo->szSrcPath);
  329. AddPath(szFullCatalogName, szCatalogName);
  330. DeleteFile(szFullCatalogName);
  331. }
  332. if (fSavedContext)
  333. {
  334. RestoreGlobalContext();
  335. }
  336. if (pcabInfo->pszInf)
  337. AdvWriteToLog("ExecuteCab: End hr=0x%1!x! Inf=%2\r\n", hRet1,pcabInfo->pszInf);
  338. else
  339. AdvWriteToLog("ExecuteCab: End hr=0x%1!x!\r\n", hRet1);
  340. return hRet1;
  341. }
  342. //-----------------------------------------------------------------------------------------
  343. //
  344. //-----------------------------------------------------------------------------------------
  345. HRESULT SaveRestoreInfo( PCSTR pszInf, PCSTR pszSection, PCSTR pszSrcDir, PCSTR pszCatalogs, DWORD dwFlags )
  346. {
  347. char szBuf[MAX_PATH];
  348. char szModule[MAX_PATH];
  349. char szBackupPath[MAX_PATH];
  350. char szBackupBase[MAX_PATH];
  351. UINT uErrid = 0;
  352. DWORD dwTmp;
  353. PSTR pszFileList = NULL;
  354. BOOL bDeleteKey = FALSE;
  355. HKEY hKey = NULL, hSubKey = NULL, hCUSubKey = NULL;
  356. HRESULT hRet = S_OK;
  357. BOOL bAtleastOneReg = FALSE;
  358. DWORD adwAttr[8];
  359. // check if we need to backup the data
  360. if ( !NeedBackupData(pszInf, pszSection) )
  361. goto done;
  362. AdvWriteToLog("SaveRestoreInfo: ");
  363. // GetComponent Name
  364. if ( FAILED(GetTranslatedString( pszInf, pszSection, ADVINF_MODNAME,
  365. szModule, sizeof(szModule), NULL)))
  366. {
  367. // error out if no component name
  368. goto done;
  369. }
  370. AdvWriteToLog("CompName=%1 pszInf=%2 Sec=%3\r\n", szModule, pszInf, pszSection);
  371. // backup/restore the reg info referred by AddReg, DelReg, BackupReg lines inside the INF install section
  372. //
  373. lstrcpy( szBuf, REGKEY_SAVERESTORE );
  374. if ( dwFlags & COREINSTALL_BKINSTALL )
  375. {
  376. CleanRegLogFile( REG_SAVE_LOG_KEY );
  377. CleanRegLogFile( REG_RESTORE_LOG_KEY );
  378. }
  379. AddPath( szBuf, szModule );
  380. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  381. NULL, &hKey, &dwTmp ) != ERROR_SUCCESS )
  382. {
  383. // If client does not have the access to this key, we may not want to fault out the rest setup process.
  384. // For some reason with Read only access set, this call return error code 2 instead of 5 access denied
  385. // so we just skip save rollback if this can not be opened/created
  386. goto done;
  387. }
  388. // create HKCU branch
  389. AddPath( szBuf, REGSUBK_REGBK );
  390. if ( RegCreateKeyEx( HKEY_CURRENT_USER, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE,
  391. NULL, &hCUSubKey, NULL ) != ERROR_SUCCESS )
  392. {
  393. hRet = HRESULT_FROM_WIN32(GetLastError());
  394. goto done;
  395. }
  396. // get the bacup info folder
  397. dwTmp = sizeof( szBackupPath );
  398. szBackupPath[0] = 0;
  399. RegQueryValueEx( hKey, REGVAL_BKDIR, NULL, NULL, szBackupPath, &dwTmp );
  400. if ( szBackupPath[0] == 0 )
  401. {
  402. DWORD dwSize;
  403. // use user specified: either the same as cab location #S or default location #D
  404. if ( FAILED( GetTranslatedString( pszInf, pszSection, ADVINF_BACKUPPATH, szBackupPath,
  405. sizeof(szBackupPath), &dwSize) ) || !IsFullPath( szBackupPath ) )
  406. {
  407. // use default dir
  408. GetProgramFilesDir( szBackupPath, sizeof( szBackupPath ) );
  409. AddPath( szBackupPath, DEF_BACKUPPATH );
  410. CreateFullPath(szBackupPath, TRUE);
  411. //CreateDirectory( szBackupPath, NULL );
  412. //if ( dwFlags & COREINSTALL_BKINSTALL )
  413. //SetFileAttributes( szBackupPath, FILE_ATTRIBUTE_HIDDEN );
  414. AddPath( szBackupPath, szModule );
  415. }
  416. }
  417. // set the flags and Process the AddReg/DelReg lines
  418. dwTmp = (dwFlags & COREINSTALL_ROLLBACK) ? IE4_RESTORE : 0;
  419. dwTmp |= (dwFlags & COREINSTALL_ROLLBKDOALL) ? IE4_FRDOALL : 0;
  420. dwTmp |= IE4_NOPROGRESS;
  421. // process files first ...
  422. GetUniBackupName( hKey, szBackupBase, sizeof(szBackupBase), szBackupPath, szModule );
  423. hRet = ProcessAllFiles( ctx.hWnd, pszSection, pszSrcDir, szBackupPath, szBackupBase, pszCatalogs, szModule, dwTmp );
  424. // process regs second ...
  425. // create/open the subkey where the registry backup info stored
  426. if ( FAILED(hRet) )
  427. goto done;
  428. // On win95 and save/rollback client and hive not loaded, proce
  429. if ( (ctx.wOSVer == _OSVER_WIN95) && !ctx.bHiveLoaded )
  430. {
  431. GetUniHiveKeyName( hKey, ctx.szRegHiveKey, sizeof(ctx.szRegHiveKey), szBackupPath );
  432. lstrcpy( szBuf, szBackupPath );
  433. // make sure the path folders are not hiden and not LFN
  434. // flag TRUE: Set the path folders to NORMAL, save the old once in adwAttr
  435. // BUGBUG: assume no deep than 8 levels here
  436. //
  437. SetPathForRegHiveUse( szBuf, adwAttr, 8, TRUE );
  438. GetShortPathName( szBuf, szBuf, sizeof(szBuf) );
  439. AddPath( szBuf, ctx.szRegHiveKey );
  440. // 4 possibilities exist:
  441. // Case 1: Reg uinstall file exists but IE4RegBackup doesn't exist
  442. // - user is upgrading over IE4, load the file as a hive
  443. // Case 2: Reg uinstall file doesn't exist and IE4RegBackup doesn't exist
  444. // - clean install, create a hive under HKEY_LOCAL_MACHINE
  445. // Case 3: Reg uninstall file doesn't exist but IE4RegBackup exists
  446. // - user is upgrading over an older IE4 build which saved
  447. // the reg backup info into the registry itself, call RegSaveKey
  448. // to export the backup key to a file, then delete the backup key
  449. // and load the file as a hive
  450. // Case 4: Reg uninstall file exists and IE4RegBackup exists
  451. // - THIS CASE SHOULDN'T HAPPEN AT ALL! If somehow happens,
  452. // we will default to Case 1.
  453. // to be safe, unload any previously loaded hive and delete the key
  454. RegUnLoadKey(HKEY_LOCAL_MACHINE, ctx.szRegHiveKey);
  455. RegDeleteKeyRecursively(HKEY_LOCAL_MACHINE, (char *) ctx.szRegHiveKey);
  456. // Case 1 (or Case 4)
  457. if (RegLoadKey(HKEY_LOCAL_MACHINE, ctx.szRegHiveKey, szBuf) == ERROR_SUCCESS)
  458. {
  459. ctx.bHiveLoaded = TRUE;
  460. }
  461. else
  462. {
  463. // To create a hive do the following steps:
  464. // Step 1: Create a subkey under HKEY_LOCAL_MACHINE
  465. // Step 2: Call RegSaveKey on the subkey to save it to a file
  466. // Step 3: Delete the subkey
  467. // Step 4: Load the file as a hive
  468. // Step 1
  469. if ( RegCreateKeyEx( hKey, REGSUBK_REGBK, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  470. NULL, &hSubKey, NULL ) == ERROR_SUCCESS )
  471. {
  472. LONG lErr;
  473. // to be safe, delete any old reg unisntall file
  474. SetFileAttributes(szBuf, FILE_ATTRIBUTE_NORMAL);
  475. DeleteFile(szBuf);
  476. lErr = RegSaveKey( hSubKey, szBuf, NULL);
  477. RegCloseKey(hSubKey);
  478. hSubKey = NULL;
  479. if (lErr == ERROR_SUCCESS)
  480. {
  481. // Step 3
  482. RegDeleteKeyRecursively(hKey, REGSUBK_REGBK);
  483. // Step 4
  484. if (RegLoadKey(HKEY_LOCAL_MACHINE, ctx.szRegHiveKey, szBuf) == ERROR_SUCCESS)
  485. {
  486. ctx.bHiveLoaded = TRUE;
  487. }
  488. }
  489. }
  490. else
  491. {
  492. hRet = HRESULT_FROM_WIN32(GetLastError());
  493. goto done;
  494. }
  495. }
  496. }
  497. // create/open the backup reg key
  498. if (RegCreateKeyEx( ctx.bHiveLoaded ? HKEY_LOCAL_MACHINE : hKey,
  499. ctx.bHiveLoaded ? ctx.szRegHiveKey : REGSUBK_REGBK,
  500. 0, NULL, REG_OPTION_NON_VOLATILE,
  501. KEY_READ|KEY_WRITE, NULL, &hSubKey, NULL ) != ERROR_SUCCESS)
  502. {
  503. hRet = HRESULT_FROM_WIN32(GetLastError());
  504. goto done;
  505. }
  506. // set the flags and Process the AddReg/DelReg lines
  507. dwTmp = (dwFlags & COREINSTALL_ROLLBACK) ? IE4_RESTORE : 0;
  508. dwTmp |= (dwFlags & COREINSTALL_ROLLBKDOALL) ? IE4_FRDOALL : 0;
  509. if ( dwFlags & COREINSTALL_ROLLBACK )
  510. {
  511. HRESULT hret1;
  512. // RegRestoreAllEx will restore all the backed-up reg entries in one shot
  513. hRet = RegRestoreAllEx( hSubKey );
  514. hret1 = RegRestoreAllEx( hCUSubKey );
  515. if ( FAILED(hret1) )
  516. hRet = hret1;
  517. }
  518. else
  519. {
  520. // Save all reg sections
  521. hRet = ProcessAllRegSec( ctx.hWnd, NULL, pszInf, pszSection, hSubKey, hCUSubKey, dwTmp, &bAtleastOneReg );
  522. }
  523. // after all the reg work, unload the hive to reg backup file and record where those
  524. // reg backup data are in registry.
  525. if ( (ctx.wOSVer == _OSVER_WIN95) && ctx.bHiveLoaded )
  526. {
  527. // flush the key and unload the hive
  528. ctx.bHiveLoaded = FALSE;
  529. RegFlushKey(hSubKey);
  530. RegCloseKey(hSubKey);
  531. hSubKey = NULL;
  532. RegUnLoadKey(HKEY_LOCAL_MACHINE, ctx.szRegHiveKey);
  533. // Flag: FALSE; reset the path folders to its orignal attributes
  534. SetPathForRegHiveUse( szBackupPath, adwAttr, 8, FALSE );
  535. if ( dwFlags & COREINSTALL_BKINSTALL )
  536. {
  537. // write the file<key>, path and size of the reg uninstall file to the registry
  538. RegSetValueEx( hKey, c_szRegUninstPath, 0, REG_SZ, (LPBYTE)szBuf, lstrlen(szBuf) + 1 );
  539. // the size can be used to validate the file during RegRestore; currently NOT USED
  540. dwTmp = MyFileSize( szBuf );
  541. RegSetValueEx( hKey, c_szRegUninstSize, 0, REG_DWORD, (LPBYTE)&dwTmp, sizeof(dwTmp) );
  542. }
  543. else if ( SUCCEEDED( hRet ) )
  544. {
  545. // delete reg data backup file
  546. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  547. DeleteFile( szBuf );
  548. RegDeleteValue(hKey, c_szRegUninstPath);
  549. RegDeleteValue(hKey, c_szRegUninstSize);
  550. }
  551. }
  552. // store & cleanup the backup information
  553. if ( SUCCEEDED( hRet ) )
  554. {
  555. PSTR ptmp;
  556. PCSTR pszCatalogName;
  557. lstrcpy( szBuf, szBackupPath );
  558. AddPath( szBuf, szBackupBase );
  559. ptmp = szBuf + lstrlen(szBuf);
  560. lstrcpy( ptmp, ".DAT" );
  561. if ( dwFlags & COREINSTALL_BKINSTALL )
  562. {
  563. dwTmp = MyFileSize( szBuf );
  564. RegSetValueEx( hKey, REGVAL_BKFILE, 0, REG_SZ, szBuf, lstrlen(szBuf)+1 );
  565. RegSetValueEx( hKey, REGVAL_BKSIZE, 0, REG_DWORD, (LPBYTE)&dwTmp, sizeof(DWORD) );
  566. RegSetValueEx( hKey, REGVAL_BKDIR, 0, REG_SZ, szBackupPath, lstrlen(szBackupPath)+1 );
  567. RegSetValueEx( hKey, REGVAL_BKINSTINF, 0, REG_SZ, pszInf, lstrlen(pszInf)+1 );
  568. RegSetValueEx( hKey, REGVAL_BKINSTSEC, 0, REG_SZ, pszSection, lstrlen(pszSection)+1 );
  569. RegSetValueEx( hKey, REGVAL_BKREGDATA, 0, REG_SZ, bAtleastOneReg ? "y" : "n", 2 );
  570. if ( SUCCEEDED(GetTranslatedString( pszInf, pszSection, ADVINF_MODVER,
  571. szBuf, sizeof(szBuf), NULL)) && szBuf[0])
  572. {
  573. RegSetValueEx( hKey, REGVAL_BKMODVER, 0, REG_SZ, szBuf, lstrlen(szBuf)+1 );
  574. }
  575. for (pszCatalogName = pszCatalogs; *pszCatalogName; pszCatalogName += lstrlen(pszCatalogName) + 1)
  576. {
  577. HKEY hkCatalogKey;
  578. CHAR szFullCatalogName[MAX_PATH];
  579. if (RegCreateKeyEx(hKey, REGSUBK_CATALOGS, 0, NULL, REG_OPTION_NON_VOLATILE,
  580. KEY_SET_VALUE, NULL, &hkCatalogKey, NULL) == ERROR_SUCCESS)
  581. {
  582. DWORD dwVal = 1;
  583. RegSetValueEx(hkCatalogKey, pszCatalogName, 0, REG_DWORD, (CONST BYTE *) &dwVal, sizeof(dwVal));
  584. RegCloseKey(hkCatalogKey);
  585. }
  586. lstrcpy(szFullCatalogName, szBackupPath);
  587. AddPath(szFullCatalogName, pszCatalogName);
  588. if (FileExists(szFullCatalogName))
  589. SetFileAttributes(szFullCatalogName, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
  590. }
  591. }
  592. else if ( dwFlags & COREINSTALL_ROLLBACK )
  593. {
  594. // delete the catalogs
  595. for (pszCatalogName = pszCatalogs; *pszCatalogName; pszCatalogName += lstrlen(pszCatalogName) + 1)
  596. {
  597. HKEY hkCatalogKey;
  598. CHAR szFullCatalogName[MAX_PATH];
  599. if (RegOpenKeyEx(hKey, REGSUBK_CATALOGS, 0, KEY_WRITE, &hkCatalogKey) == ERROR_SUCCESS)
  600. {
  601. RegDeleteValue(hkCatalogKey, pszCatalogName);
  602. RegCloseKey(hkCatalogKey);
  603. }
  604. lstrcpy(szFullCatalogName, szBackupPath);
  605. AddPath(szFullCatalogName, pszCatalogName);
  606. if (FileExists(szFullCatalogName))
  607. {
  608. SetFileAttributes(szFullCatalogName, FILE_ATTRIBUTE_NORMAL);
  609. DeleteFile(szFullCatalogName);
  610. }
  611. }
  612. // delete backup .dat .ini files
  613. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  614. DeleteFile( szBuf );
  615. lstrcpy( ptmp, ".INI" );
  616. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  617. DeleteFile( szBuf );
  618. MyRemoveDirectory( szBackupPath );
  619. // since we have rollback all the files and delete the backup .dat .ini files, we
  620. // should re-set the backup file size to ZERO to allow reg restore continue for whatever
  621. // following users.
  622. dwTmp = 0;
  623. RegSetValueEx( hKey, REGVAL_BKSIZE, 0, REG_DWORD, (LPBYTE)&dwTmp, sizeof(DWORD) );
  624. RegSetValueEx( hKey, REGVAL_BKREGDATA, 0, REG_SZ, "n", 2 );
  625. RegDeleteValue( hKey, REGVAL_BKMODVER );
  626. }
  627. }
  628. done:
  629. if ( hSubKey )
  630. {
  631. RegCloseKey( hSubKey );
  632. }
  633. if ( hKey )
  634. {
  635. RegCloseKey( hKey );
  636. }
  637. if ( hCUSubKey )
  638. {
  639. BOOL bEmpty = TRUE;
  640. DWORD dwKeys, dwValues;
  641. if ( (RegQueryInfoKey(hCUSubKey, NULL, NULL, NULL, &dwKeys, NULL, NULL,
  642. &dwValues, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
  643. (dwKeys || dwValues) )
  644. {
  645. // not empty key
  646. bEmpty = FALSE;
  647. }
  648. RegCloseKey( hCUSubKey );
  649. if ( bEmpty )
  650. {
  651. // delete the empty key
  652. if ( RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_SAVERESTORE, 0, KEY_READ|KEY_WRITE, &hCUSubKey) == ERROR_SUCCESS)
  653. {
  654. RegDeleteKeyRecursively( hCUSubKey, szModule );
  655. RegCloseKey( hCUSubKey );
  656. }
  657. }
  658. }
  659. if ( gst_pszFiles )
  660. {
  661. LocalFree( gst_pszFiles );
  662. gst_pszFiles = NULL;
  663. gst_pszEndLastFile = NULL;
  664. }
  665. AdvWriteToLog("SaveRestoreInfo: End hr=0x%1!x! %2\r\n", hRet, szModule);
  666. return hRet;
  667. }
  668. //-----------------------------------------------------------------------------------------
  669. //
  670. //-----------------------------------------------------------------------------------------
  671. HRESULT ProcessAllRegSec( HWND hw, PCSTR pszTitle, PCSTR pszInf, PCSTR pszSection, HKEY hKey, HKEY hCUKey, DWORD dwFlags, BOOL *lpbOneReg )
  672. {
  673. int i, arraysize;
  674. PSTR pszOneSec;
  675. PSTR pszStr;
  676. HRESULT hRet = S_OK;
  677. char szBuf[MAX_PATH];
  678. AdvWriteToLog("ProcessAllRegSec: \r\n");
  679. arraysize = ARRAYSIZE( RegInfOpt );
  680. for ( i=0; i<arraysize; i++ )
  681. {
  682. szBuf[0] = 0;
  683. pszStr = szBuf;
  684. GetTranslatedString( pszInf, pszSection, RegInfOpt[i].pszInfKey,
  685. szBuf, sizeof(szBuf), NULL);
  686. // Parse the arguments, SETUP engine is not called to process this line. So we check on \".
  687. pszOneSec = GetStringField( &pszStr, ",", '\"', TRUE );
  688. while ( (hRet == S_OK) && pszOneSec && *pszOneSec )
  689. {
  690. if ( i == 0 ) // AddReg section only
  691. dwFlags |= IE4_NOENUMKEY;
  692. else
  693. dwFlags &= ~IE4_NOENUMKEY;
  694. if (*pszOneSec != '!')
  695. hRet = ProcessOneRegSec( hw, pszTitle, pszInf, pszOneSec, hKey, hCUKey, dwFlags, lpbOneReg );
  696. pszOneSec = GetStringField( &pszStr, ",", '\"', TRUE );
  697. }
  698. }
  699. AdvWriteToLog("ProcessAllRegSec: End hr=0x%1!x!\r\n", hRet);
  700. return hRet;
  701. }
  702. //-----------------------------------------------------------------------------------------
  703. //
  704. //-----------------------------------------------------------------------------------------
  705. HRESULT ProcessOneRegSec( HWND hw, PCSTR pszTitle, PCSTR pszInf, PCSTR pszSec, HKEY hLMKey, HKEY hCUKey, DWORD dwFlags, BOOL *lpbOneReg )
  706. {
  707. int j;
  708. PSTR pszInfLine = NULL;
  709. HRESULT hResult = S_OK;
  710. PSTR pszRootKey, pszSubKey, pszValueName, pszTmp1, pszTmp2;
  711. HKEY hKey;
  712. AdvWriteToLog("ProcessOneRegSec: Section=%1\r\n", pszSec);
  713. for ( j=0; (hResult==S_OK); j++ )
  714. {
  715. if ( FAILED(hResult = GetTranslatedLine( pszInf, pszSec, j, &pszInfLine, NULL )) ||
  716. !pszInfLine )
  717. {
  718. // if the failure due to no more items, set to normal return
  719. if ( hResult == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) )
  720. hResult = S_OK;
  721. break;
  722. }
  723. // at least, there is one reg data to be saved
  724. if ( lpbOneReg && !*lpbOneReg )
  725. *lpbOneReg = TRUE;
  726. // Parse out the fields Registry op-line.
  727. ParseCustomLine( pszInfLine, &pszRootKey, &pszSubKey, &pszValueName, &pszTmp1, &pszTmp2, FALSE, TRUE );
  728. if ( !lstrcmpi( pszRootKey, "HKCU") || !lstrcmpi( pszRootKey, "HKEY_CURRENT_USER" ) )
  729. hKey = hCUKey;
  730. else
  731. hKey = hLMKey;
  732. // Check the specified registry branch and grab the contents.
  733. hResult = RegSaveRestore( hw, pszTitle, hKey, pszRootKey, pszSubKey, pszValueName, dwFlags );
  734. LocalFree( pszInfLine );
  735. pszInfLine = NULL;
  736. }
  737. AdvWriteToLog("ProcessOneRegSec: End hr=0x%1!x! %2\r\n", hResult, pszSec);
  738. return hResult;
  739. }
  740. //-----------------------------------------------------------------------------------------
  741. //
  742. //-----------------------------------------------------------------------------------------
  743. HRESULT ProcessAllFiles( HWND hw, PCSTR pszSection, PCSTR pszSrcDir, PCSTR pszBackupPath,
  744. PCSTR pszBaseName, PCSTR pszCatalogs, PCSTR pszModule, DWORD dwFlags )
  745. {
  746. HRESULT hRet = S_OK;
  747. PCSTR pszCatalogName;
  748. AdvWriteToLog("ProcessAllFiles: Sec=%1, SrcDir=%2, BackupPath=%3\r\n", pszSection, pszSrcDir, pszBackupPath);
  749. // if CORESINSTALL_ROLLBKDOALL is on, no need to build the filelist. FileRestore will
  750. // rollback everything based on its .INI backup data index file. Otherwise, build
  751. // file list gst_pszFiles inside
  752. gst_pszFiles = NULL;
  753. if ( !(dwFlags & IE4_FRDOALL) )
  754. {
  755. // backup/restore the files referred by CopyFiles, DelFiles, RenFiles
  756. //
  757. gst_pszFiles = (PSTR)LocalAlloc( LPTR, FILELIST_SIZE ); // allocat 10k
  758. gst_pszEndLastFile = gst_pszFiles; // already will have 2 zeros
  759. if ( !gst_pszFiles )
  760. {
  761. ErrorMsg( hw, IDS_ERR_NO_MEMORY );
  762. hRet = E_OUTOFMEMORY;
  763. return hRet;
  764. }
  765. hRet = ProcessFileSections( pszSection, pszSrcDir, MyFileQueueCallback );
  766. }
  767. // if a catalog is specified, backup/restore it
  768. for (pszCatalogName = pszCatalogs; SUCCEEDED(hRet) && *pszCatalogName; pszCatalogName += lstrlen(pszCatalogName) + 1)
  769. {
  770. DWORD dwRet;
  771. CHAR szPrevCatalog[MAX_PATH];
  772. AdvWriteToLog("ProcessAllFiles: Processing catalog=%1\r\n", pszCatalogName);
  773. lstrcpy(szPrevCatalog, pszBackupPath);
  774. AddPath(szPrevCatalog, pszCatalogName);
  775. if ((dwFlags & IE4_RESTORE) || (dwFlags & IE4_FRDOALL))
  776. {
  777. // first delete the current catalog and then install the previous one
  778. dwRet = g_pfSfpDeleteCatalog(pszCatalogName);
  779. AdvWriteToLog("\tProcessAllFiles: SfpDeleteCatalog returned=%1!lu!\r\n", dwRet);
  780. if (dwRet != ERROR_SUCCESS)
  781. hRet = E_FAIL;
  782. if (SUCCEEDED(hRet) && FileExists(szPrevCatalog))
  783. {
  784. dwRet = g_pfSfpInstallCatalog(szPrevCatalog, NULL);
  785. AdvWriteToLog("\tProcessAllFiles: SfpInstallCatalog returned=%1!lu!\r\n", dwRet);
  786. if (dwRet != ERROR_SUCCESS)
  787. hRet = E_FAIL;
  788. }
  789. }
  790. else
  791. {
  792. BOOL bBackupCatalog = FALSE;
  793. CHAR szBuf[MAX_PATH];
  794. if (pszModule != NULL)
  795. {
  796. HKEY hkCatalogKey;
  797. lstrcpy(szBuf, REGKEY_SAVERESTORE);
  798. AddPath(szBuf, pszModule);
  799. AddPath(szBuf, REGSUBK_CATALOGS);
  800. // back-up the catalog if it hasn't been already backed up
  801. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_QUERY_VALUE, &hkCatalogKey) == ERROR_SUCCESS)
  802. {
  803. if (RegQueryValueEx(hkCatalogKey, pszCatalogName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
  804. bBackupCatalog = TRUE;
  805. RegCloseKey(hkCatalogKey);
  806. }
  807. else
  808. bBackupCatalog = TRUE;
  809. }
  810. else
  811. {
  812. // back-up the catalog if the file back-up .dat doesn't exist
  813. lstrcpy(szBuf, pszBackupPath);
  814. AddPath(szBuf, pszBaseName);
  815. lstrcat(szBuf, ".dat");
  816. if (!FileExists(szBuf))
  817. bBackupCatalog = TRUE;
  818. }
  819. if (bBackupCatalog)
  820. {
  821. dwRet = g_pfSfpDuplicateCatalog(pszCatalogName, pszBackupPath);
  822. AdvWriteToLog("\tProcessAllFiles: SfpDuplicateCatalog returned=%1!lu!\r\n", dwRet);
  823. if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND)
  824. hRet = E_FAIL;
  825. }
  826. }
  827. }
  828. if ( SUCCEEDED(hRet) )
  829. {
  830. hRet = FileSaveRestore( hw, gst_pszFiles, (PSTR)pszBackupPath, (PSTR)pszBaseName, dwFlags );
  831. }
  832. AdvWriteToLog("ProcessAllFiles: End hr=0x%1!x!\r\n", hRet);
  833. return hRet;
  834. }
  835. //-----------------------------------------------------------------------------------------
  836. //
  837. //-----------------------------------------------------------------------------------------
  838. HRESULT ProcessFileSections( PCSTR pszSection, PCSTR pszSrcDir, MYFILEQUEUECALLBACK pMyFileQueueCallback )
  839. {
  840. PVOID pContext = NULL;
  841. HRESULT hResult = S_OK;
  842. AdvWriteToLog("ProcessFileSections: Sec=%1\r\n", pszSection);
  843. // Build File list include all the files in CopyFiles/DelFiles/renFiles
  844. //
  845. // Setup Context data structure initialized for us for default UI provided by Setup API.
  846. pContext = pfSetupInitDefaultQueueCallbackEx( NULL,
  847. INVALID_HANDLE_VALUE,
  848. 0, 0, NULL );
  849. if ( pContext == INVALID_HANDLE_VALUE )
  850. {
  851. hResult = HRESULT_FROM_SETUPAPI(GetLastError());
  852. goto done;
  853. }
  854. if ( !pfSetupInstallFromInfSection( NULL, ctx.hInf, pszSection, SPINST_FILES, NULL,
  855. pszSrcDir, SP_COPY_NEWER,
  856. pMyFileQueueCallback,
  857. pContext, NULL, NULL ) )
  858. {
  859. hResult = HRESULT_FROM_SETUPAPI(GetLastError());
  860. pfSetupTermDefaultQueueCallback( pContext );
  861. goto done;
  862. }
  863. // Free Context Data structure
  864. pfSetupTermDefaultQueueCallback( pContext );
  865. done:
  866. AdvWriteToLog("ProcessFileSections: End hr=0x%1!x!\r\n",hResult);
  867. return hResult;
  868. }
  869. //-----------------------------------------------------------------------------------------
  870. //
  871. //-----------------------------------------------------------------------------------------
  872. UINT WINAPI MyFileQueueCallback( PVOID Context,UINT Notification,UINT_PTR parm1,UINT_PTR parm2 )
  873. {
  874. UINT retVal = FILEOP_SKIP;
  875. switch(Notification)
  876. {
  877. case SPFILENOTIFY_STARTDELETE:
  878. case SPFILENOTIFY_STARTRENAME:
  879. case SPFILENOTIFY_STARTCOPY:
  880. {
  881. FILEPATHS *pFilePath;
  882. int len;
  883. PCSTR pTmp;
  884. pFilePath = (FILEPATHS *)parm1;
  885. if ( !gst_pszFiles )
  886. {
  887. retVal = FILEOP_ABORT;
  888. SetLastError( ERROR_OUTOFMEMORY );
  889. break;
  890. }
  891. if ( Notification == SPFILENOTIFY_STARTRENAME )
  892. {
  893. len = lstrlen( pFilePath->Source ) + 1;
  894. pTmp = pFilePath->Source;
  895. }
  896. else
  897. {
  898. len = lstrlen( pFilePath->Target ) + 1;
  899. pTmp = pFilePath->Target;
  900. }
  901. if ( (FILELIST_SIZE - (gst_pszEndLastFile - gst_pszFiles )) <= (len + 8) )
  902. {
  903. retVal = FILEOP_ABORT;
  904. SetLastError( ERROR_OUTOFMEMORY );
  905. break;
  906. }
  907. lstrcpy( gst_pszEndLastFile, pTmp );
  908. gst_pszEndLastFile += len;
  909. *gst_pszEndLastFile = 0; // the second '\0' to end the list
  910. }
  911. break;
  912. case SPFILENOTIFY_NEEDMEDIA:
  913. return ( MyFileQueueCallback2( Context, Notification, parm1, parm2 ) );
  914. default:
  915. return ( pfSetupDefaultQueueCallback( Context, Notification, parm1, parm2 ) );
  916. }
  917. return( retVal );
  918. }
  919. //-----------------------------------------------------------------------------------------
  920. //
  921. //-----------------------------------------------------------------------------------------
  922. BOOL GetFullInfNameAndSrcDir( PCSTR pszInfFilename, PSTR pszFilename, PSTR pszSrcDir )
  923. {
  924. BOOL bRet = FALSE;
  925. UINT uiErrid = 0;
  926. PCSTR pszErrParm1 = NULL;
  927. char szBuf[MAX_PATH];
  928. if ( !pszInfFilename || !pszFilename || !(*pszInfFilename) )
  929. goto done;
  930. if ( !IsFullPath( pszInfFilename ) && pszSrcDir && *pszSrcDir )
  931. {
  932. lstrcpy( szBuf, pszSrcDir );
  933. AddPath( szBuf, pszInfFilename );
  934. }
  935. else
  936. lstrcpy( szBuf, pszInfFilename );
  937. if ( GetFileAttributes( szBuf ) == 0xFFFFFFFF )
  938. {
  939. if ( IsFullPath( szBuf ) )
  940. {
  941. uiErrid = IDS_ERR_CANT_FIND_FILE;
  942. pszErrParm1 = pszInfFilename;
  943. goto done;
  944. }
  945. // If the file doesn't exist in the current directory, check the
  946. // Windows\inf directory
  947. if ( !GetWindowsDirectory( szBuf, sizeof(szBuf) ) )
  948. {
  949. uiErrid = IDS_ERR_GET_WIN_DIR;
  950. goto done;
  951. }
  952. AddPath( szBuf, "inf" );
  953. AddPath( szBuf, pszInfFilename );
  954. if ( GetFileAttributes( szBuf) == 0xFFFFFFFF )
  955. {
  956. uiErrid = IDS_ERR_CANT_FIND_FILE;
  957. pszErrParm1 = pszInfFilename;
  958. goto done;
  959. }
  960. }
  961. // Generate the source directory from the inf path.
  962. lstrcpy( pszFilename, szBuf );
  963. GetParentDir( szBuf );
  964. lstrcpy( pszSrcDir, szBuf );
  965. bRet = TRUE;
  966. done:
  967. if ( uiErrid )
  968. ErrorMsg1Param( ctx.hWnd, uiErrid, pszErrParm1 );
  969. return bRet;
  970. }
  971. //-----------------------------------------------------------------------------------------
  972. //
  973. //-----------------------------------------------------------------------------------------
  974. void CleanRegLogFile( PCSTR pcszLogFileSecName )
  975. {
  976. char szLogFileName[MAX_PATH];
  977. char szBuf[MAX_PATH];
  978. HKEY hkSubKey;
  979. if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SAVERESTORE, 0, KEY_READ, &hkSubKey) == ERROR_SUCCESS)
  980. {
  981. DWORD dwDataLen = sizeof(szLogFileName);
  982. if (RegQueryValueEx(hkSubKey, pcszLogFileSecName, NULL, NULL, szLogFileName, &dwDataLen) != ERROR_SUCCESS)
  983. *szLogFileName = '\0';
  984. RegCloseKey(hkSubKey);
  985. }
  986. if (*szLogFileName)
  987. {
  988. if (szLogFileName[1] != ':') // crude way of determining if fully qualified path is specified or not
  989. {
  990. GetWindowsDirectory(szBuf, sizeof(szBuf)); // default to windows dir
  991. AddPath(szBuf, szLogFileName);
  992. }
  993. else
  994. lstrcpy(szBuf, szLogFileName);
  995. DeleteFile( szBuf );
  996. }
  997. }
  998. //-----------------------------------------------------------------------------------------
  999. //
  1000. //-----------------------------------------------------------------------------------------
  1001. BOOL VerifyBackupRegData( HKEY hKey )
  1002. {
  1003. HKEY hSubKey;
  1004. char szBackData[MAX_PATH];
  1005. DWORD dwSize = 0, dwBkSize;
  1006. BOOL bRet = FALSE;
  1007. if ( ctx.wOSVer == _OSVER_WIN95 )
  1008. {
  1009. dwSize = sizeof( szBackData );
  1010. if ( RegQueryValueEx( hKey, c_szRegUninstPath, NULL, NULL, szBackData, &dwSize ) == ERROR_SUCCESS )
  1011. {
  1012. dwSize = sizeof( DWORD );
  1013. if ( RegQueryValueEx( hKey, c_szRegUninstSize, NULL, NULL, (LPBYTE)&dwBkSize, &dwSize ) == ERROR_SUCCESS )
  1014. {
  1015. if ( MyFileSize(szBackData) == dwBkSize )
  1016. {
  1017. bRet = TRUE;
  1018. return bRet;
  1019. }
  1020. }
  1021. }
  1022. }
  1023. // if you are here, the file backup info is OK. We check on reg backup info
  1024. if ( RegOpenKeyEx( hKey, REGSUBK_REGBK, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
  1025. {
  1026. HKEY hsubsubKey;
  1027. if ( RegOpenKeyEx( hSubKey, "0", 0, KEY_READ, &hsubsubKey) == ERROR_SUCCESS)
  1028. {
  1029. if ( (RegQueryInfoKey( hsubsubKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize,
  1030. NULL, NULL, NULL, NULL ) == ERROR_SUCCESS) && dwSize )
  1031. {
  1032. bRet = TRUE;
  1033. }
  1034. RegCloseKey( hsubsubKey );
  1035. }
  1036. RegCloseKey(hSubKey);
  1037. }
  1038. return bRet;
  1039. }
  1040. //-----------------------------------------------------------------------------------------
  1041. //
  1042. //-----------------------------------------------------------------------------------------
  1043. BOOL VerifyBackupInfo( HKEY hKey, HKEY hCUKey )
  1044. {
  1045. char szBackData[MAX_PATH];
  1046. DWORD dwSize, dwBkSize = 0;
  1047. BOOL bRet = FALSE;
  1048. HKEY hSubKey = NULL;
  1049. if ( hKey )
  1050. {
  1051. // verify the backup file first
  1052. dwSize = sizeof( szBackData );
  1053. if ( RegQueryValueEx( hKey, REGVAL_BKFILE, NULL, NULL, szBackData, &dwSize ) == ERROR_SUCCESS )
  1054. {
  1055. dwSize = sizeof( DWORD );
  1056. if ( RegQueryValueEx( hKey, REGVAL_BKSIZE, NULL, NULL, (LPBYTE)&dwBkSize, &dwSize ) == ERROR_SUCCESS )
  1057. {
  1058. if ( MyFileSize(szBackData) == dwBkSize )
  1059. {
  1060. // if you are here, the file backup info is OK. We check on reg backup info
  1061. dwSize = sizeof( szBackData );
  1062. if ( (RegQueryValueEx( hKey, REGVAL_BKREGDATA, NULL, NULL, (LPBYTE)szBackData, &dwSize ) == ERROR_SUCCESS ) &&
  1063. ( szBackData[0] == 'n' ) )
  1064. {
  1065. // no registry data backed up, so no need to verify further
  1066. bRet = TRUE;
  1067. }
  1068. else
  1069. {
  1070. if ( VerifyBackupRegData( hKey ) || (hCUKey && VerifyBackupRegData( hCUKey )) )
  1071. {
  1072. bRet = TRUE;
  1073. }
  1074. }
  1075. }
  1076. }
  1077. }
  1078. }
  1079. return bRet;
  1080. }
  1081. typedef HRESULT (*CHECKTOKENMEMBERSHIP)(HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember);
  1082. BOOL CheckToken(BOOL *pfIsAdmin)
  1083. {
  1084. BOOL bNewNT5check = FALSE;
  1085. HINSTANCE hAdvapi32 = NULL;
  1086. CHECKTOKENMEMBERSHIP pf;
  1087. PSID AdministratorsGroup;
  1088. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1089. hAdvapi32 = LoadLibrary("advapi32.dll");
  1090. if (hAdvapi32)
  1091. {
  1092. pf = (CHECKTOKENMEMBERSHIP)GetProcAddress(hAdvapi32, "CheckTokenMembership");
  1093. if (pf)
  1094. {
  1095. bNewNT5check = TRUE;
  1096. *pfIsAdmin = FALSE;
  1097. if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  1098. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) )
  1099. {
  1100. pf(NULL, AdministratorsGroup, pfIsAdmin);
  1101. FreeSid(AdministratorsGroup);
  1102. }
  1103. }
  1104. FreeLibrary(hAdvapi32);
  1105. }
  1106. return bNewNT5check;
  1107. }
  1108. //***************************************************************************
  1109. //* Functions: IsNTAdmin() *
  1110. //* *
  1111. //* Returns TRUE if our process has admin priviliges. *
  1112. //* FALSE otherwise. *
  1113. //***************************************************************************
  1114. BOOL WINAPI IsNTAdmin( DWORD dwReserved, DWORD *lpdwReserved )
  1115. {
  1116. static int fIsAdmin = 2;
  1117. HANDLE hAccessToken;
  1118. PTOKEN_GROUPS ptgGroups;
  1119. DWORD dwReqSize;
  1120. UINT i;
  1121. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1122. PSID AdministratorsGroup;
  1123. BOOL bRet;
  1124. //
  1125. // If we have cached a value, return the cached value. Note I never
  1126. // set the cached value to false as I want to retry each time in
  1127. // case a previous failure was just a temp. problem (ie net access down)
  1128. //
  1129. bRet = FALSE;
  1130. ptgGroups = NULL;
  1131. if( fIsAdmin != 2 )
  1132. return (BOOL)fIsAdmin;
  1133. if (!CheckToken(&bRet))
  1134. {
  1135. if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hAccessToken ) )
  1136. return FALSE;
  1137. // See how big of a buffer we need for the token information
  1138. if(!GetTokenInformation( hAccessToken, TokenGroups, NULL, 0, &dwReqSize))
  1139. {
  1140. // GetTokenInfo should the buffer size we need - Alloc a buffer
  1141. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  1142. ptgGroups = (PTOKEN_GROUPS) LocalAlloc(LMEM_FIXED, dwReqSize);
  1143. }
  1144. // ptgGroups could be NULL for a coupla reasons here:
  1145. // 1. The alloc above failed
  1146. // 2. GetTokenInformation actually managed to succeed the first time (possible?)
  1147. // 3. GetTokenInfo failed for a reason other than insufficient buffer
  1148. // Any of these seem justification for bailing.
  1149. // So, make sure it isn't null, then get the token info
  1150. if(ptgGroups && GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, dwReqSize, &dwReqSize))
  1151. {
  1152. if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  1153. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) )
  1154. {
  1155. // Search thru all the groups this process belongs to looking for the
  1156. // Admistrators Group.
  1157. for( i=0; i < ptgGroups->GroupCount; i++ )
  1158. {
  1159. if( EqualSid(ptgGroups->Groups[i].Sid, AdministratorsGroup) )
  1160. {
  1161. // Yea! This guy looks like an admin
  1162. fIsAdmin = TRUE;
  1163. bRet = TRUE;
  1164. break;
  1165. }
  1166. }
  1167. FreeSid(AdministratorsGroup);
  1168. }
  1169. }
  1170. if(ptgGroups)
  1171. LocalFree(ptgGroups);
  1172. // BUGBUG: Close handle here? doc's aren't clear whether this is needed.
  1173. CloseHandle(hAccessToken);
  1174. }
  1175. else if (bRet)
  1176. fIsAdmin = TRUE;
  1177. return bRet;
  1178. }
  1179. //-----------------------------------------------------------------------------------------
  1180. //
  1181. // MyFileCheckCallback()
  1182. //
  1183. //-----------------------------------------------------------------------------------------
  1184. UINT WINAPI MyFileCheckCallback( PVOID Context,UINT Notification,UINT_PTR parm1,UINT_PTR parm2 )
  1185. {
  1186. UINT retVal = FILEOP_SKIP;
  1187. switch(Notification)
  1188. {
  1189. case SPFILENOTIFY_STARTDELETE:
  1190. case SPFILENOTIFY_STARTRENAME:
  1191. case SPFILENOTIFY_STARTCOPY:
  1192. {
  1193. FILEPATHS *pFilePath;
  1194. PCSTR pTmp;
  1195. HANDLE hFile;
  1196. pFilePath = (FILEPATHS *)parm1;
  1197. if ( Notification == SPFILENOTIFY_STARTRENAME )
  1198. {
  1199. pTmp = pFilePath->Source;
  1200. }
  1201. else
  1202. {
  1203. pTmp = pFilePath->Target;
  1204. }
  1205. if ( FileExists(pTmp) ) // original file exists
  1206. {
  1207. // check if the File is in use
  1208. if ((hFile = CreateFile(pTmp, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  1209. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
  1210. {
  1211. // File is in use which will trig the reboot if we actually install this section.
  1212. gst_hNeedReboot = S_OK;
  1213. // no need to continue if at least one file is in use, reboot is needed.
  1214. retVal = FILEOP_ABORT;
  1215. }
  1216. else
  1217. {
  1218. // file not in use
  1219. CloseHandle(hFile);
  1220. }
  1221. }
  1222. }
  1223. break;
  1224. case SPFILENOTIFY_NEEDMEDIA:
  1225. return ( MyFileQueueCallback2( Context, Notification, parm1, parm2 ) );
  1226. default:
  1227. return ( pfSetupDefaultQueueCallback( Context, Notification, parm1, parm2 ) );
  1228. }
  1229. return( retVal );
  1230. }
  1231. //***************************************************************************
  1232. //* *
  1233. //* NAME: RebootCheckOnInstall *
  1234. //* *
  1235. //* SYNOPSIS: Check reboot condition if given INF install section is *
  1236. //* installed. *
  1237. //* *
  1238. //* REQUIRES: hWnd: Handle to parent window. *
  1239. //* PCSTR The INF filename *
  1240. //* PCSTR INF Section name *
  1241. //* *
  1242. //* RETURNS: HRESULT: *
  1243. //* *
  1244. //***************************************************************************
  1245. HRESULT WINAPI RebootCheckOnInstall( HWND hWnd, PCSTR pszINF, PCSTR pszSection, DWORD dwFlags )
  1246. {
  1247. HRESULT hRet = S_FALSE;
  1248. char szSrcDir[MAX_PATH];
  1249. char szRealSec[100];
  1250. // Validate parameters:
  1251. // if INF filename info is missing, invalid.
  1252. if ( !pszINF || !*pszINF )
  1253. return hRet;
  1254. ctx.wQuietMode = QUIETMODE_ALL;
  1255. ctx.hWnd = hWnd;
  1256. if ( !IsFullPath( pszINF ) )
  1257. {
  1258. hRet = E_INVALIDARG;
  1259. goto done;
  1260. }
  1261. else
  1262. {
  1263. lstrcpy( szSrcDir, pszINF );
  1264. GetParentDir( szSrcDir );
  1265. }
  1266. hRet = CommonInstallInit( pszINF, pszSection, szRealSec, sizeof(szRealSec), NULL, FALSE, COREINSTALL_REBOOTCHECKONINSTALL );
  1267. if ( FAILED( hRet ) )
  1268. {
  1269. goto done;
  1270. }
  1271. hRet = SetLDIDs( pszINF, szRealSec, 0, NULL );
  1272. if ( FAILED( hRet ) )
  1273. {
  1274. goto done;
  1275. }
  1276. gst_hNeedReboot = S_FALSE;
  1277. hRet = ProcessFileSections( szRealSec, szSrcDir, MyFileCheckCallback );
  1278. if ( SUCCEEDED(hRet) || (gst_hNeedReboot == S_OK) )
  1279. {
  1280. hRet = gst_hNeedReboot;
  1281. }
  1282. done:
  1283. CommonInstallCleanup();
  1284. return hRet;
  1285. }
  1286. //***************************************************************************
  1287. //* *
  1288. //* NAME: RegSaveRestoreOnINF *
  1289. //* *
  1290. //* SYNOPSIS: Save or restore the given INF section to given reg key *
  1291. //* *
  1292. //* REQUIRES: hWnd: Handle to parent window. *
  1293. //* PCSTR The Title if messagebox displayed *
  1294. //* PCSTR The INF filename *
  1295. //* PCSTR INF Section name *
  1296. //* HKEY The backup reg key handle *
  1297. //* DWORD Flags *
  1298. //* *
  1299. //* RETURNS: HRESULT: *
  1300. //* *
  1301. //***************************************************************************
  1302. HRESULT WINAPI RegSaveRestoreOnINF( HWND hWnd, PCSTR pcszTitle, PCSTR pszInf,
  1303. PCSTR pszSection, HKEY hLMBackKey, HKEY hCUBackKey, DWORD dwFlags )
  1304. {
  1305. HRESULT hRet = S_OK;
  1306. CHAR szRealInstallSection[100];
  1307. PSTR pszOldTitle;
  1308. HWND hwndOld;
  1309. BOOL bDoCommonInit = FALSE;
  1310. AdvWriteToLog("RegSaveRestoreOnINF: Inf=%1\r\n", pszInf);
  1311. hwndOld = ctx.hWnd;
  1312. pszOldTitle = ctx.lpszTitle;
  1313. if (hWnd != INVALID_HANDLE_VALUE)
  1314. ctx.hWnd = hWnd;
  1315. if ( dwFlags & ARSR_NOMESSAGES )
  1316. ctx.wQuietMode |= QUIETMODE_ALL;
  1317. if ( pcszTitle != NULL )
  1318. ctx.lpszTitle = (PSTR)pcszTitle;
  1319. if ( (dwFlags & ARSR_RESTORE) && !(dwFlags & ARSR_REMOVREGBKDATA) && !pszInf && !pszSection )
  1320. {
  1321. HRESULT hret1 = S_OK;
  1322. // restore all case
  1323. if ( hLMBackKey )
  1324. hRet = RegRestoreAllEx( hLMBackKey );
  1325. if ( ( hLMBackKey != hCUBackKey) && hCUBackKey )
  1326. hret1 = RegRestoreAllEx( hCUBackKey );
  1327. if ( FAILED(hret1) )
  1328. hRet = hret1;
  1329. goto done;
  1330. }
  1331. // params validation checks
  1332. if ( !IsFullPath(pszInf) || (!hLMBackKey && !hCUBackKey) || (dwFlags & ARSR_REGSECTION) && !pszSection
  1333. || !(dwFlags & ARSR_RESTORE) && (dwFlags & ARSR_REMOVREGBKDATA) )
  1334. {
  1335. hRet = E_INVALIDARG;
  1336. goto done;
  1337. }
  1338. if ( !hCUBackKey )
  1339. hCUBackKey = hLMBackKey;
  1340. else if ( !hLMBackKey )
  1341. hLMBackKey = hCUBackKey;
  1342. bDoCommonInit = TRUE;
  1343. hRet = CommonInstallInit( pszInf, (dwFlags & ARSR_REGSECTION) ? NULL : pszSection, szRealInstallSection,
  1344. sizeof(szRealInstallSection), NULL, FALSE, 0 );
  1345. if ( FAILED( hRet ) )
  1346. {
  1347. goto done;
  1348. }
  1349. if ( dwFlags & ARSR_REGSECTION )
  1350. {
  1351. // process One Reg Section to do Save / restore based on given flags
  1352. hRet = ProcessOneRegSec( hWnd, pcszTitle, pszInf, pszSection, hLMBackKey, hCUBackKey, dwFlags, NULL );
  1353. }
  1354. else
  1355. {
  1356. // process All Reg sections
  1357. hRet = ProcessAllRegSec( hWnd, pcszTitle, pszInf, szRealInstallSection, hLMBackKey, hCUBackKey, dwFlags, NULL );
  1358. }
  1359. done:
  1360. if ( bDoCommonInit )
  1361. CommonInstallCleanup();
  1362. ctx.hWnd = hwndOld;
  1363. ctx.lpszTitle = pszOldTitle;
  1364. AdvWriteToLog("RegSaveRestoreOnINF: End hr=0x%1!x!\r\n", hRet);
  1365. return hRet;
  1366. }
  1367. //***************************************************************************
  1368. //* *
  1369. //* NAME: FileSaveRestoreOnINF *
  1370. //* *
  1371. //* SYNOPSIS: Save or restore Files defined by GenInstall INF section *
  1372. //* *
  1373. //* REQUIRES: hWnd: Handle to parent window. *
  1374. //* PCSTR The Title if messagebox displayed *
  1375. //* PCSTR The INF filename *
  1376. //* PCSTR INF Section name *
  1377. //* PCSTR backup directory path *
  1378. //* PCSTR backup file basename *
  1379. //* DWORD Flags *
  1380. //* *
  1381. //* RETURNS: HRESULT: *
  1382. //* *
  1383. //***************************************************************************
  1384. HRESULT WINAPI FileSaveRestoreOnINF( HWND hWnd, PCSTR pszTitle, PCSTR pszInf,
  1385. PCSTR pszSection, PCSTR pszBackupDir,
  1386. PCSTR pszBaseBkFile, DWORD dwFlags )
  1387. {
  1388. HRESULT hRet = S_OK;
  1389. char szRealInstallSection[100] = {0};
  1390. char szSrcDir[MAX_PATH] = {0};
  1391. PSTR pszOldTitle;
  1392. HWND hOldwnd;
  1393. BOOL bDoCommonInit = FALSE;
  1394. CHAR szCatalogName[MAX_PATH];
  1395. AdvWriteToLog("FileSaveRestoreOnINF: Inf=%1\r\n", (pszInf != NULL) ? pszInf : "NULL");
  1396. if ( dwFlags & AFSR_NOMESSAGES )
  1397. ctx.wQuietMode = QUIETMODE_ALL;
  1398. hOldwnd = ctx.hWnd;
  1399. if ( hWnd != INVALID_HANDLE_VALUE )
  1400. ctx.hWnd = hWnd;
  1401. pszOldTitle = ctx.lpszTitle;
  1402. if ( pszTitle != NULL )
  1403. ctx.lpszTitle = (PSTR)pszTitle;
  1404. // params validation checks
  1405. if ( !pszBackupDir || !*pszBackupDir || !pszBaseBkFile || !*pszBaseBkFile )
  1406. {
  1407. hRet = E_INVALIDARG;
  1408. goto done;
  1409. }
  1410. if ( (dwFlags & AFSR_RESTORE) && !pszInf && !pszSection )
  1411. {
  1412. dwFlags |= IE4_FRDOALL;
  1413. }
  1414. if ( !(dwFlags & IE4_FRDOALL) )
  1415. {
  1416. if ( !IsFullPath(pszInf) )
  1417. {
  1418. hRet = E_INVALIDARG;
  1419. goto done;
  1420. }
  1421. else
  1422. {
  1423. bDoCommonInit = TRUE;
  1424. hRet = CommonInstallInit( pszInf, pszSection, szRealInstallSection,
  1425. sizeof(szRealInstallSection), NULL, FALSE, 0 );
  1426. if ( FAILED( hRet ) )
  1427. {
  1428. goto done;
  1429. }
  1430. }
  1431. }
  1432. if (pszInf != NULL)
  1433. {
  1434. lstrcpy( szSrcDir, pszInf );
  1435. GetParentDir( szSrcDir );
  1436. }
  1437. // get the catalog name, if specified
  1438. ZeroMemory(szCatalogName, sizeof(szCatalogName));
  1439. if (pszInf == NULL)
  1440. {
  1441. CHAR szFullCatalogName[MAX_PATH];
  1442. // NOTE: assume that the catalog name is <BaseBkFile>.cat.
  1443. // can't use the REGKEY_SAVERESTORE key to read the catalog name
  1444. // because this API doesn't go thru SaveRestoreInfo which updates
  1445. // the REGKEY_SAVERESTORE key.
  1446. // check if the catalog file exists in the BackupDir
  1447. lstrcpy(szFullCatalogName, pszBackupDir);
  1448. AddPath(szFullCatalogName, pszBaseBkFile);
  1449. lstrcat(szFullCatalogName, ".cat");
  1450. if (FileExists(szFullCatalogName))
  1451. wsprintf(szCatalogName, "%s.cat", pszBaseBkFile);
  1452. }
  1453. else
  1454. GetTranslatedString(pszInf, szRealInstallSection, ADVINF_CATALOG_NAME, szCatalogName, sizeof(szCatalogName), NULL);
  1455. if (*szCatalogName)
  1456. {
  1457. // load sfc.dll and the relevant proc's
  1458. if (!LoadSfcDLL())
  1459. {
  1460. // couldn't load -- so empty out CatalogName
  1461. *szCatalogName = '\0';
  1462. }
  1463. }
  1464. // Process all the INF file sections
  1465. hRet = ProcessAllFiles( hWnd, szRealInstallSection, szSrcDir, pszBackupDir, pszBaseBkFile, szCatalogName, NULL, dwFlags );
  1466. done:
  1467. UnloadSfcDLL();
  1468. if ( bDoCommonInit )
  1469. CommonInstallCleanup();
  1470. ctx.lpszTitle = pszOldTitle;
  1471. ctx.hWnd = hOldwnd;
  1472. AdvWriteToLog("FileSaveRestoreOnINF: End hr=0x%1!x!\r\n", hRet);
  1473. return hRet;
  1474. }
  1475. #if 0
  1476. //-----------------------------------------------------------------------------------------
  1477. //
  1478. // MyGetSpecialFolder( int )
  1479. //
  1480. //-----------------------------------------------------------------------------------------
  1481. HRESULT MyGetSpecialFolder( HWND hwnd, int nFd, PSTR szPath )
  1482. {
  1483. LPITEMIDLIST pidl;
  1484. HRESULT hRet;
  1485. *szPath = 0;
  1486. hRet = SHGetSpecialFolderLocation( hwnd, nFd, &pidl );
  1487. if ( hRet == NOERROR )
  1488. {
  1489. if ( !SHGetPathFromIDList( pidl, szPath ) )
  1490. {
  1491. hRet = E_INVALIDARG;
  1492. }
  1493. }
  1494. return hRet;
  1495. }
  1496. #endif
  1497. void MySetSpecialFolder( HKEY hkey, PCSTR pcszValueN, PSTR pszPath )
  1498. {
  1499. DWORD dwTmp;
  1500. if ( (ctx.wOSVer >= _OSVER_WINNT40) && AddEnvInPath( pszPath, pszPath ) )
  1501. dwTmp = REG_EXPAND_SZ;
  1502. else
  1503. dwTmp = REG_SZ;
  1504. RegSetValueExA( hkey, pcszValueN, 0, dwTmp, pszPath, lstrlen(pszPath)+1 );
  1505. }
  1506. //-----------------------------------------------------------------------------------------
  1507. //
  1508. // SetSysPathsInReg()
  1509. //
  1510. //-----------------------------------------------------------------------------------------
  1511. void SetSysPathsInReg()
  1512. {
  1513. HKEY hkey;
  1514. char szPath[MAX_PATH];
  1515. char szAS[100];
  1516. DWORD dwTmp;
  1517. int i = 0;
  1518. PSTR pszValName, pszKeyName;
  1519. // Add StartUp, StartMenu, Programs and accessories sys pathes to registries for further ref
  1520. // only if it is not set before.
  1521. if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, 0, KEY_READ|KEY_WRITE, &hkey) == ERROR_SUCCESS )
  1522. {
  1523. // Program Files path
  1524. dwTmp = sizeof( szPath );
  1525. if ( RegQueryValueEx( hkey, REGVAL_PROGRAMFILESPATH, 0, NULL, (LPBYTE)szPath, &dwTmp ) != ERROR_SUCCESS )
  1526. {
  1527. if ( GetProgramFilesDir( szPath, sizeof(szPath) ) )
  1528. {
  1529. MySetSpecialFolder( hkey, REGVAL_PROGRAMFILESPATH, szPath );
  1530. }
  1531. }
  1532. // use wordpad.inf to look into the strings
  1533. GetWindowsDirectory( szPath, sizeof(szPath) );
  1534. AddPath( szPath, "inf\\wordpad.inf" );
  1535. // accessories Names
  1536. for ( i=0; i<2; i++ )
  1537. {
  1538. if ( i == 0 )
  1539. {
  1540. // start menu name
  1541. pszValName = REGVAL_SM_ACCESSORIES;
  1542. pszKeyName = "APPS_DESC";
  1543. }
  1544. else
  1545. {
  1546. pszValName = REGVAL_PF_ACCESSORIES;
  1547. if ( ctx.wOSVer >= _OSVER_WINNT40 )
  1548. pszKeyName = "APPS_DESC";
  1549. else
  1550. pszKeyName = "Accessories";
  1551. }
  1552. dwTmp = sizeof( szAS );
  1553. if ( RegQueryValueEx( hkey, pszValName, 0, NULL, (LPBYTE)szAS, &dwTmp ) != ERROR_SUCCESS )
  1554. {
  1555. // need to open the new INF so save the current context
  1556. if (SaveGlobalContext())
  1557. {
  1558. if ( FAILED(GetTranslatedString(szPath, "Strings", pszKeyName, szAS, sizeof(szAS), NULL)))
  1559. {
  1560. lstrcpy(szAS, "Accessories");
  1561. }
  1562. RegSetValueExA( hkey, pszValName, 0, REG_SZ, szAS, lstrlen(szAS)+1 );
  1563. RestoreGlobalContext();
  1564. }
  1565. }
  1566. }
  1567. RegCloseKey(hkey);
  1568. }
  1569. }
  1570. //-----------------------------------------------------------------------------------------
  1571. //
  1572. // ProcessPerUserSec
  1573. //
  1574. //-----------------------------------------------------------------------------------------
  1575. HRESULT ProcessPerUserSec( PCSTR pcszInf, PCSTR pcszSec )
  1576. {
  1577. char szSec[MAX_PATH];
  1578. DWORD dwTmp;
  1579. HRESULT hRet = S_OK;
  1580. PERUSERSECTION PU_Sec = {0};
  1581. if (SUCCEEDED(GetTranslatedString(pcszInf, pcszSec, ADVINF_PERUSER, szSec, sizeof(szSec), NULL)))
  1582. {
  1583. AdvWriteToLog("ProcessPerUserSec: \r\n");
  1584. AdvWriteToLog("Inf=%1, InstallSec=%2, PerUserInstall=%3\r\n", pcszInf, pcszSec, szSec);
  1585. // get GUID to create subkey
  1586. if ( SUCCEEDED( GetTranslatedString( pcszInf, szSec, ADVINF_PU_GUID, PU_Sec.szGUID, sizeof(PU_Sec.szGUID), &dwTmp) ) )
  1587. {
  1588. PU_Sec.dwIsInstalled = GetTranslatedInt(pcszInf, szSec, ADVINF_PU_ISINST, 999);
  1589. PU_Sec.bRollback = (BOOL)GetTranslatedInt(pcszInf, szSec, ADVINF_PU_ROLLBK, 0);
  1590. GetTranslatedString( pcszInf, szSec, ADVINF_PU_DSP, PU_Sec.szDispName, sizeof(PU_Sec.szDispName), &dwTmp);
  1591. GetTranslatedString( pcszInf, szSec, ADVINF_PU_VER, PU_Sec.szVersion, sizeof(PU_Sec.szVersion), &dwTmp);
  1592. GetTranslatedString( pcszInf, szSec, ADVINF_PU_STUB, PU_Sec.szStub, sizeof(PU_Sec.szStub), &dwTmp);
  1593. GetTranslatedString( pcszInf, szSec, ADVINF_PU_LANG, PU_Sec.szLocale, sizeof(PU_Sec.szLocale), &dwTmp);
  1594. GetTranslatedString( pcszInf, szSec, ADVINF_PU_CID, PU_Sec.szCompID, sizeof(PU_Sec.szCompID), &dwTmp);
  1595. // since we are close to beta1, we may hack here to avoid the external comp changes
  1596. //if (IsThisRollbkUninst(PU_Sec.szGUID))
  1597. // PU_Sec.bRollback = TRUE;
  1598. hRet = SetPerUserSecValues(&PU_Sec);
  1599. }
  1600. else
  1601. {
  1602. AdvWriteToLog("Failure: No GUID specified\r\n");
  1603. //hRet = E_FAIL; //unknown GUID, advpack will do nothing for this comp!
  1604. }
  1605. AdvWriteToLog("ProcessPerUserSec: End hr=0x%1!x!\r\n", hRet);
  1606. }
  1607. return hRet;
  1608. }
  1609. //-----------------------------------------------------------------------------------------
  1610. //
  1611. // SetPerUserSecValues help functions
  1612. //
  1613. //-----------------------------------------------------------------------------------------
  1614. BOOL CopyRegValue( HKEY hFromkey, HKEY hTokey, LPCSTR pszFromVal, LPCSTR pszToVal)
  1615. {
  1616. DWORD dwSize,dwType;
  1617. char szBuf[BUF_1K];
  1618. BOOL bRet = FALSE;
  1619. //backup the older reg values
  1620. //AdvWriteToLog("CopyRegValue:");
  1621. dwSize = sizeof(szBuf);
  1622. if (RegQueryValueEx(hFromkey, pszFromVal, NULL, &dwType, (LPBYTE)szBuf, &dwSize)==ERROR_SUCCESS)
  1623. {
  1624. if (RegSetValueEx(hTokey, pszToVal, 0, dwType, szBuf, lstrlen(szBuf)+1)==ERROR_SUCCESS)
  1625. {
  1626. //AdvWriteToLog("From %1 to %2: %3", pszFromVal, pszToVal, szBuf);
  1627. bRet = TRUE;
  1628. }
  1629. }
  1630. //AdvWriteToLog("\r\n");
  1631. return bRet;
  1632. }
  1633. void SetSecRegValues( HKEY hSubKey, PPERUSERSECTION pPU, BOOL bUseStubWrapper )
  1634. {
  1635. char szBuf[BUF_1K];
  1636. if (pPU->szStub[0])
  1637. {
  1638. if (ctx.wOSVer >= _OSVER_WINNT40)
  1639. {
  1640. AddEnvInPath( pPU->szStub, szBuf );
  1641. if (bUseStubWrapper)
  1642. RegSetValueEx( hSubKey, REGVAL_REALSTUBPATH, 0, REG_EXPAND_SZ, szBuf, lstrlen(szBuf)+1 );
  1643. else
  1644. RegSetValueEx( hSubKey, ADVINF_PU_STUB, 0, REG_EXPAND_SZ, szBuf, lstrlen(szBuf)+1 );
  1645. }
  1646. else
  1647. {
  1648. if (bUseStubWrapper)
  1649. RegSetValueEx( hSubKey, REGVAL_REALSTUBPATH, 0, REG_SZ, pPU->szStub, lstrlen(pPU->szStub)+1 );
  1650. else
  1651. RegSetValueEx( hSubKey, ADVINF_PU_STUB, 0, REG_SZ, pPU->szStub, lstrlen(pPU->szStub)+1 );
  1652. }
  1653. }
  1654. if (pPU->szVersion[0])
  1655. {
  1656. RegSetValueEx( hSubKey, ADVINF_PU_VER, 0, REG_SZ, pPU->szVersion, lstrlen(pPU->szVersion)+1 );
  1657. // if we update the base version value, delete the previous QFE version
  1658. RegDeleteValue( hSubKey, "QFEVersion" );
  1659. }
  1660. if (pPU->szLocale[0])
  1661. RegSetValueEx( hSubKey, ADVINF_PU_LANG, 0, REG_SZ, pPU->szLocale, lstrlen(pPU->szLocale)+1 );
  1662. if (pPU->szCompID[0])
  1663. RegSetValueEx( hSubKey, ADVINF_PU_CID, 0, REG_SZ, pPU->szCompID, lstrlen(pPU->szCompID)+1 );
  1664. if (pPU->szDispName[0])
  1665. RegSetValueEx( hSubKey, "", 0, REG_SZ, pPU->szDispName, lstrlen(pPU->szDispName)+1 );
  1666. RegSetValueEx( hSubKey, ADVINF_PU_ISINST, 0, REG_DWORD, (LPBYTE)&(pPU->dwIsInstalled), sizeof(DWORD) );
  1667. }
  1668. //-----------------------------------------------------------------------------------------
  1669. //
  1670. // SetPerUserSecValues
  1671. //
  1672. //-----------------------------------------------------------------------------------------
  1673. HRESULT WINAPI SetPerUserSecValues( PPERUSERSECTION pPU )
  1674. {
  1675. HKEY hkey = NULL;
  1676. HKEY hSubKey = NULL;
  1677. HKEY hCUKey;
  1678. HRESULT hRet = S_OK;
  1679. DWORD dwTmp, dwSize;
  1680. char szBuf[BUF_1K];
  1681. BOOL bStubWrapper = FALSE;
  1682. AdvWriteToLog("SetPerUserSecValues:\r\n");
  1683. if ( (pPU == NULL) || (pPU->szGUID[0]==0) )
  1684. {
  1685. AdvWriteToLog("SetPerUserSecValues: End Warning: No Data\r\n");
  1686. return hRet;
  1687. }
  1688. AdvWriteToLog("Input params: %1,%2,%3,%4,%5,%6\r\n",
  1689. pPU->szGUID, pPU->szDispName, pPU->szLocale, pPU->szStub, pPU->szVersion,
  1690. pPU->dwIsInstalled ? "1" : "0");
  1691. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, c_szActiveSetupKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
  1692. NULL, &hkey, &dwTmp ) != ERROR_SUCCESS )
  1693. {
  1694. hRet = E_FAIL;
  1695. AdvWriteToLog("Failure: Cannot open %1 key\r\n", c_szActiveSetupKey);
  1696. goto done;
  1697. }
  1698. if ( RegCreateKeyEx( hkey, pPU->szGUID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE,
  1699. NULL, &hSubKey, &dwTmp ) != ERROR_SUCCESS )
  1700. {
  1701. hRet = E_FAIL;
  1702. AdvWriteToLog("Failure: Cannot create %1 key\r\n", pPU->szGUID);
  1703. goto done;
  1704. }
  1705. if (pPU->dwIsInstalled == 1)
  1706. {
  1707. // This is the install case. Need to do the following tasks:
  1708. //
  1709. // 1) If the given GUID key exists, has IsInstalled set to 1. Then check
  1710. // if the existing major version is smaller than the one to be installed. If so,
  1711. // backup the existing Version, Locale, StubPath values to OldVersion, OldLocale,
  1712. // OldStubPath first. Set the StubPath to advpack Install Stub Wrapper function.
  1713. // Set the Version, Locale, InstallStubPath based on the current INF PerUserInstall section values.
  1714. // 2) If there is no exist GUID key or the existing GUID key has IsInstalled set to 0,
  1715. // just set the current values and set IsInstalled to 1. ( as it is today)
  1716. // 3) Delete {GUID}.Restore key if exists.
  1717. //
  1718. dwSize = sizeof(DWORD);
  1719. if ((pPU->bRollback) &&
  1720. (RegQueryValueEx(hSubKey, ADVINF_PU_ISINST, NULL, NULL, (LPBYTE)&dwTmp, &dwSize)==ERROR_SUCCESS) &&
  1721. (dwTmp == 1) )
  1722. {
  1723. WORD wRegVer[4], wInfVer[4];
  1724. // case (1)
  1725. dwSize = sizeof(szBuf);
  1726. if (RegQueryValueEx(hSubKey, ADVINF_PU_VER, NULL, NULL, (LPBYTE)szBuf, &dwSize)==ERROR_SUCCESS)
  1727. {
  1728. ConvertVersionString(szBuf, wRegVer, ',');
  1729. if (pPU->szVersion[0])
  1730. {
  1731. ConvertVersionString(pPU->szVersion, wInfVer, ',');
  1732. // we only rollback to previous major version now so we only compare major ver.
  1733. if ( wRegVer[0] < wInfVer[0] )
  1734. {
  1735. CopyRegValue(hSubKey, hSubKey, "", REGVAL_OLDDISPN);
  1736. CopyRegValue(hSubKey, hSubKey, ADVINF_PU_VER, REGVAL_OLDVER);
  1737. CopyRegValue(hSubKey, hSubKey, ADVINF_PU_LANG, REGVAL_OLDLANG);
  1738. if (CopyRegValue(hSubKey, hSubKey, ADVINF_PU_STUB, REGVAL_OLDSTUB))
  1739. {
  1740. CopyRegValue(hSubKey, hSubKey, REGVAL_REALSTUBPATH, REGVAL_OLDREALSTUBPATH);
  1741. wsprintf(szBuf, ADV_INSTSTUBWRAPPER, pPU->szGUID);
  1742. RegSetValueEx( hSubKey, ADVINF_PU_STUB, 0, REG_SZ, szBuf, lstrlen(szBuf)+1 );
  1743. bStubWrapper = TRUE;
  1744. }
  1745. }
  1746. else
  1747. {
  1748. // the case user have already backup the previous state, we only update
  1749. // the real stub path since its StubPath will point to Wrapper function
  1750. dwSize = sizeof(szBuf);
  1751. if (RegQueryValueEx(hSubKey, REGVAL_REALSTUBPATH, NULL, NULL, (LPBYTE)szBuf, &dwSize)==ERROR_SUCCESS)
  1752. bStubWrapper = TRUE;
  1753. }
  1754. }
  1755. }
  1756. }
  1757. // case (2)
  1758. SetSecRegValues(hSubKey, pPU, bStubWrapper);
  1759. // case (3)
  1760. lstrcpy(szBuf, pPU->szGUID);
  1761. lstrcat(szBuf, ".Restore");
  1762. RegDeleteKey(hkey, szBuf);
  1763. }
  1764. else if (pPU->dwIsInstalled == 0)
  1765. {
  1766. // This is the uninstall case, need to do the following tasks
  1767. //
  1768. // 1) If the {GUID} key OldVersion, OldStubpath, OldLocale exist, set them back to Version, Locale StubPath value and set IsInstall to 1 to reflect the current install state;
  1769. // 2) Then, Create the '{GUID}.Restore' key with the values of the version ( adjusted max( GUID�s Version, GUID�s MaxRestoreVersion)+1 ), locale, stubpath calling
  1770. // advpack.dll UserStubWraper with the {GUID}.Restore as param and the RestoreStubPath with the INF StubPath value. Set IsInstalled to 1.
  1771. // 3) If none of the above is applied, just set the current GUID key IsInstall to 0 like it is now.
  1772. //
  1773. if (CopyRegValue(hSubKey, hSubKey, REGVAL_OLDVER, ADVINF_PU_VER))
  1774. {
  1775. HKEY hResKey;
  1776. // case (1)
  1777. // restore the old version data
  1778. CopyRegValue(hSubKey, hSubKey, REGVAL_OLDDISPN, "");
  1779. CopyRegValue(hSubKey, hSubKey, REGVAL_OLDLANG, ADVINF_PU_LANG);
  1780. if(CopyRegValue(hSubKey, hSubKey, REGVAL_OLDSTUB, ADVINF_PU_STUB))
  1781. {
  1782. CopyRegValue(hSubKey, hSubKey, REGVAL_OLDREALSTUBPATH, REGVAL_REALSTUBPATH);
  1783. // case (2)
  1784. lstrcpy(szBuf, pPU->szGUID);
  1785. lstrcat(szBuf, ".Restore" );
  1786. if (RegCreateKeyEx(hkey, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE,
  1787. NULL, &hResKey, &dwTmp ) == ERROR_SUCCESS )
  1788. {
  1789. wsprintf(szBuf, ADV_UNINSTSTUBWRAPPER, pPU->szGUID);
  1790. RegSetValueEx(hResKey, ADVINF_PU_STUB, 0, REG_SZ, szBuf, lstrlen(szBuf)+1);
  1791. bStubWrapper = TRUE;
  1792. // also copy DontAskFlag
  1793. CopyRegValue(hSubKey, hResKey, c_szRegDontAskValue, c_szRegDontAskValue);
  1794. SetSecRegValues(hResKey, pPU, bStubWrapper);
  1795. RegCloseKey(hResKey);
  1796. }
  1797. }
  1798. // cleanup the backup data
  1799. RegDeleteValue(hSubKey, REGVAL_OLDDISPN);
  1800. RegDeleteValue(hSubKey, REGVAL_OLDLANG);
  1801. RegDeleteValue(hSubKey, REGVAL_OLDVER);
  1802. RegDeleteValue(hSubKey, REGVAL_OLDSTUB);
  1803. RegDeleteValue(hSubKey, REGVAL_OLDREALSTUBPATH);
  1804. }
  1805. else
  1806. {
  1807. // case (3)
  1808. SetSecRegValues(hSubKey, pPU, bStubWrapper);
  1809. }
  1810. }
  1811. done:
  1812. if ( hSubKey )
  1813. RegCloseKey( hSubKey );
  1814. if ( hkey )
  1815. RegCloseKey( hkey );
  1816. AdvWriteToLog("SetPerUserSecValues: End hr=0x%1!x!\r\n", hRet);
  1817. return hRet;
  1818. }
  1819. //-----------------------------------------------------------------------------------------
  1820. //
  1821. // PerUser Install stub wrapper
  1822. //
  1823. //-----------------------------------------------------------------------------------------
  1824. HRESULT WINAPI UserInstStubWrapper(HWND hwnd, HINSTANCE hInst, LPSTR pszParams, INT nShow)
  1825. {
  1826. HKEY hkList, hkcuGUIDRes, hkGUID;
  1827. char szBuf[MAX_PATH];
  1828. DWORD cbData,dwType;
  1829. HRESULT hRet = S_OK;
  1830. /* Component is an uninstall stub. */
  1831. if ((pszParams == NULL) || (*pszParams == 0))
  1832. {
  1833. hRet = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1834. return hRet;
  1835. }
  1836. AdvWriteToLog("UserInstStubWrapper:\r\n");
  1837. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szActiveSetupKey, 0,
  1838. KEY_READ, &hkList) == ERROR_SUCCESS)
  1839. {
  1840. if ( RegOpenKeyEx(hkList, pszParams, 0, KEY_READ, &hkGUID) == ERROR_SUCCESS)
  1841. {
  1842. // run the real stub first
  1843. cbData = sizeof(szBuf);
  1844. if ((RegQueryValueEx(hkGUID, REGVAL_REALSTUBPATH, NULL, &dwType,
  1845. (LPBYTE)szBuf, &cbData) == ERROR_SUCCESS) && szBuf[0])
  1846. {
  1847. char szBuf2[MAX_PATH*2];
  1848. if (dwType == REG_EXPAND_SZ)
  1849. ExpandEnvironmentStrings(szBuf, szBuf2, sizeof(szBuf2));
  1850. else
  1851. lstrcpy(szBuf2,szBuf);
  1852. if ( LaunchAndWait( szBuf2, NULL, NULL, INFINITE, RUNCMDS_QUIET ) == E_FAIL )
  1853. {
  1854. char szMessage[BIG_STRING];
  1855. hRet = HRESULT_FROM_WIN32(GetLastError());
  1856. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  1857. szMessage, sizeof(szMessage), NULL );
  1858. ErrorMsg2Param( ctx.hWnd, IDS_ERR_CREATE_PROCESS, szBuf2, szMessage );
  1859. RegCloseKey(hkGUID);
  1860. RegCloseKey(hkList);
  1861. return hRet;
  1862. }
  1863. }
  1864. // create {GUID}.Restore to enable the uninstall later
  1865. lstrcpy(szBuf, c_szActiveSetupKey);
  1866. AddPath(szBuf, pszParams);
  1867. lstrcat(szBuf,".Restore");
  1868. if (RegCreateKeyEx( HKEY_CURRENT_USER, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE,
  1869. KEY_READ|KEY_WRITE, NULL, &hkcuGUIDRes, &cbData) == ERROR_SUCCESS)
  1870. {
  1871. CopyRegValue(hkGUID, hkcuGUIDRes, ADVINF_PU_VER, ADVINF_PU_VER);
  1872. CopyRegValue(hkGUID, hkcuGUIDRes, ADVINF_PU_LANG, ADVINF_PU_LANG);
  1873. RegCloseKey(hkcuGUIDRes);
  1874. }
  1875. RegCloseKey(hkGUID);
  1876. }
  1877. RegCloseKey(hkList);
  1878. }
  1879. AdvWriteToLog("UserInstStubWrapper: End hr=0x%1!x!\r\n", hRet);
  1880. return hRet;
  1881. }
  1882. //-----------------------------------------------------------------------------------------
  1883. //
  1884. // PerUser uninstall stub wrapper
  1885. //
  1886. //-----------------------------------------------------------------------------------------
  1887. HRESULT WINAPI UserUnInstStubWrapper(HWND hwnd, HINSTANCE hInst, LPSTR pszParams, INT nShow)
  1888. {
  1889. HKEY hkList, hkGUIDRes, hkGUID, hkcuGUID;
  1890. char szBuf[MAX_PATH];
  1891. DWORD cbData, dwType;
  1892. HRESULT hRet = S_OK;
  1893. /* Component is an uninstall stub. */
  1894. if ((pszParams == NULL) || (*pszParams == 0))
  1895. {
  1896. hRet = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1897. return hRet;
  1898. }
  1899. AdvWriteToLog("UserUnInstStubWrapper:\r\n");
  1900. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szActiveSetupKey, 0,
  1901. KEY_READ|KEY_WRITE, &hkList) == ERROR_SUCCESS)
  1902. {
  1903. // restore the Installed IE version from HKLM
  1904. if ( RegOpenKeyEx( hkList, pszParams, 0, KEY_READ, &hkGUID) == ERROR_SUCCESS)
  1905. {
  1906. lstrcpy(szBuf, c_szActiveSetupKey);
  1907. AddPath(szBuf, pszParams);
  1908. if ( RegOpenKeyEx( HKEY_CURRENT_USER, szBuf, 0,
  1909. KEY_READ|KEY_WRITE, &hkcuGUID) == ERROR_SUCCESS)
  1910. {
  1911. CopyRegValue(hkGUID, hkcuGUID, ADVINF_PU_VER, ADVINF_PU_VER);
  1912. CopyRegValue(hkGUID, hkcuGUID, ADVINF_PU_LANG, ADVINF_PU_LANG);
  1913. RegCloseKey(hkcuGUID);
  1914. }
  1915. RegCloseKey(hkGUID);
  1916. }
  1917. // run the stub if needed
  1918. lstrcpy(szBuf, pszParams);
  1919. lstrcat(szBuf,".Restore");
  1920. if (RegOpenKeyEx( hkList, szBuf, 0, KEY_READ, &hkGUIDRes) == ERROR_SUCCESS)
  1921. {
  1922. cbData = sizeof(szBuf);
  1923. if ((RegQueryValueEx(hkGUIDRes, REGVAL_REALSTUBPATH, NULL, &dwType,
  1924. (LPBYTE)szBuf, &cbData) == ERROR_SUCCESS) && szBuf[0])
  1925. {
  1926. char szBuf2[MAX_PATH*2];
  1927. if (dwType == REG_EXPAND_SZ)
  1928. ExpandEnvironmentStrings(szBuf, szBuf2, sizeof(szBuf2));
  1929. else
  1930. lstrcpy(szBuf2,szBuf);
  1931. if ( LaunchAndWait( szBuf2, NULL, NULL, INFINITE, RUNCMDS_QUIET ) == E_FAIL )
  1932. {
  1933. char szMessage[BIG_STRING];
  1934. hRet = HRESULT_FROM_WIN32(GetLastError());
  1935. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  1936. szMessage, sizeof(szMessage), NULL );
  1937. ErrorMsg2Param( ctx.hWnd, IDS_ERR_CREATE_PROCESS, szBuf2, szMessage );
  1938. }
  1939. }
  1940. RegCloseKey(hkGUIDRes);
  1941. }
  1942. RegCloseKey(hkList);
  1943. }
  1944. AdvWriteToLog("UserUnInstStubWrapper: End hr=0x%1!x!\r\n", hRet);
  1945. return hRet;
  1946. }
  1947. //***************************************************************************
  1948. //* *
  1949. //* NAME: TranslateInfStringEx *
  1950. //* *
  1951. //* SYNOPSIS: Translates a string in an Advanced inf file -- replaces *
  1952. //* LDIDs with the directory. This new API requires called to *
  1953. //* init the INF first for efficiency. *
  1954. //* *
  1955. //* REQUIRES: *
  1956. //* *
  1957. //* RETURNS: *
  1958. //* *
  1959. //***************************************************************************
  1960. HRESULT WINAPI TranslateInfStringEx( HINF hInf, PCSTR pszInfFilename,
  1961. PCSTR pszTranslateSection, PCSTR pszTranslateKey,
  1962. PSTR pszBuffer, DWORD dwBufferSize,
  1963. PDWORD pdwRequiredSize, PVOID pvReserved )
  1964. {
  1965. HRESULT hReturnCode = S_OK;
  1966. // Validate parameters
  1967. if ( (hInf != ctx.hInf) || pszInfFilename == NULL || pszTranslateSection == NULL
  1968. || pszTranslateKey == NULL || pdwRequiredSize == NULL )
  1969. {
  1970. hReturnCode = E_INVALIDARG;
  1971. goto done;
  1972. }
  1973. hReturnCode = GetTranslatedString( pszInfFilename, pszTranslateSection, pszTranslateKey,
  1974. pszBuffer, dwBufferSize, pdwRequiredSize );
  1975. done:
  1976. return hReturnCode;
  1977. }
  1978. //***************************************************************************
  1979. //* *
  1980. //* NAME: OpenINFEngine *
  1981. //* *
  1982. //* SYNOPSIS: Initialize the INF Engine and open INF file for use. *
  1983. //* *
  1984. //* REQUIRES: *
  1985. //* *
  1986. //* RETURNS: HINF hInf the opened INF file handle *
  1987. //* *
  1988. //***************************************************************************
  1989. HRESULT WINAPI OpenINFEngine( PCSTR pszInfFilename, PCSTR pszInstallSection,
  1990. DWORD dwFlags, HINF *phInf, PVOID pvReserved )
  1991. {
  1992. HRESULT hReturnCode = S_OK;
  1993. CHAR szRealInstallSection[256];
  1994. BOOL fSaveContext = FALSE;
  1995. // Validate parameters
  1996. if ( (pszInfFilename == NULL) || !phInf)
  1997. {
  1998. hReturnCode = E_INVALIDARG;
  1999. goto done;
  2000. }
  2001. *phInf = NULL;
  2002. if (!SaveGlobalContext())
  2003. {
  2004. hReturnCode = E_OUTOFMEMORY;
  2005. goto done;
  2006. }
  2007. fSaveContext = TRUE;
  2008. ctx.wQuietMode = QUIETMODE_ALL;
  2009. hReturnCode = CommonInstallInit( pszInfFilename, pszInstallSection,
  2010. szRealInstallSection, sizeof(szRealInstallSection), NULL, FALSE, 0 );
  2011. if ( FAILED( hReturnCode ) ) {
  2012. goto done;
  2013. }
  2014. if ( ctx.dwSetupEngine != ENGINE_SETUPAPI )
  2015. {
  2016. hReturnCode = E_UNEXPECTED;
  2017. goto done;
  2018. }
  2019. hReturnCode = SetLDIDs( (LPSTR)pszInfFilename, szRealInstallSection, 0, NULL );
  2020. if ( FAILED( hReturnCode ) ) {
  2021. goto done;
  2022. }
  2023. *phInf = ctx.hInf;
  2024. done:
  2025. if ( FAILED(hReturnCode) )
  2026. {
  2027. CommonInstallCleanup();
  2028. if ( fSaveContext )
  2029. {
  2030. RestoreGlobalContext();
  2031. }
  2032. }
  2033. return hReturnCode;
  2034. }
  2035. //***************************************************************************
  2036. //* *
  2037. //* NAME: CloseINFEngine *
  2038. //* *
  2039. //* SYNOPSIS: Close the INF Engine and the current INF file. *
  2040. //* *
  2041. //* REQUIRES: *
  2042. //* *
  2043. //* RETURNS: HINF hInf the opened INF file handle *
  2044. //* *
  2045. //***************************************************************************
  2046. HRESULT WINAPI CloseINFEngine( HINF hInf )
  2047. {
  2048. if ( hInf == ctx.hInf )
  2049. {
  2050. CommonInstallCleanup();
  2051. RestoreGlobalContext();
  2052. }
  2053. else
  2054. return E_INVALIDARG;
  2055. return S_OK;
  2056. }
  2057. #define BACKUPBASE "%s.%03d"
  2058. BOOL GetUniBackupName( HKEY hKey, LPSTR pszBackupBase, DWORD dwInSize, LPCSTR pszBackupPath, LPCSTR pszModule )
  2059. {
  2060. char szBuf[MAX_PATH];
  2061. DWORD dwSize;
  2062. BOOL bFound = FALSE;
  2063. // 1st check to see if the backup filename already in registry, if so, we use it.
  2064. dwSize = sizeof( szBuf );
  2065. if ( RegQueryValueEx(hKey, REGVAL_BKFILE, NULL, NULL, szBuf, &dwSize) == ERROR_SUCCESS )
  2066. {
  2067. LPSTR pszTmp;
  2068. pszTmp = ANSIStrRChr( szBuf, '\\' );
  2069. if ( pszTmp )
  2070. {
  2071. lstrcpy( pszBackupBase, CharNext(pszTmp) );
  2072. pszTmp = ANSIStrRChr( pszBackupBase, '.' );
  2073. if ( pszTmp && (lstrcmpi(pszTmp, ".dat")==0) )
  2074. {
  2075. *pszTmp = 0;
  2076. }
  2077. bFound = TRUE;
  2078. }
  2079. }
  2080. if ( !bFound )
  2081. {
  2082. int i;
  2083. char szFilePath[MAX_PATH];
  2084. // 2nd, check to see if the default Module name has been used as the basename
  2085. lstrcpy( szFilePath, pszBackupPath );
  2086. AddPath( szFilePath, pszModule );
  2087. lstrcat( szFilePath, ".dat" );
  2088. if ( !FileExists(szFilePath) )
  2089. {
  2090. bFound = TRUE;
  2091. lstrcpy( pszBackupBase, pszModule );
  2092. }
  2093. else
  2094. {
  2095. for ( i = 1; i<999; i++ )
  2096. {
  2097. wsprintf( szBuf, BACKUPBASE, pszModule, i );
  2098. lstrcpy( szFilePath, pszBackupPath);
  2099. AddPath( szFilePath, szBuf );
  2100. lstrcat( szFilePath, ".dat" );
  2101. if ( !FileExists(szFilePath) )
  2102. {
  2103. bFound = TRUE;
  2104. lstrcpy( pszBackupBase, szBuf );
  2105. break;
  2106. }
  2107. }
  2108. }
  2109. }
  2110. return bFound;
  2111. }
  2112. BOOL GetUniHiveKeyName( HKEY hKey, LPSTR pszRegHiveKey, DWORD dwInSize, LPCSTR pszBackupPath )
  2113. {
  2114. char szBuf[MAX_PATH];
  2115. DWORD dwSize;
  2116. BOOL bFound = FALSE;
  2117. // For each component, we always try to get the HIVE key from the reg backup filename
  2118. // 4 possibilities exist:
  2119. // Case 1: Reg uinstall file exists but IE4RegBackup doesn't exist
  2120. // - user is upgrading over IE4, load the file as a hive
  2121. // Case 2: Reg uinstall file doesn't exist and IE4RegBackup doesn't exist
  2122. // - clean install, create a hive under HKEY_LOCAL_MACHINE
  2123. // Case 3: Reg uninstall file doesn't exist but IE4RegBackup exists
  2124. // - user is upgrading over an older IE4 build which saved
  2125. // the reg backup info into the registry itself, call RegSaveKey
  2126. // to export the backup key to a file, then delete the backup key
  2127. // and load the file as a hive
  2128. // Case 4: Reg uninstall file exists and IE4RegBackup exists
  2129. // - THIS CASE SHOULDN'T HAPPEN AT ALL! If somehow happens,
  2130. // we will default to Case 1.
  2131. // For case 1 & 4: we should get the hive key name out of the existing reg value data
  2132. // For case 2 & 3: we should generate the unique hive key name with "AINF%d" format
  2133. dwSize = sizeof( szBuf );
  2134. if ( RegQueryValueEx(hKey, c_szRegUninstPath, NULL, NULL, szBuf, &dwSize) == ERROR_SUCCESS )
  2135. {
  2136. LPSTR pszTmp;
  2137. pszTmp = ANSIStrRChr( szBuf, '\\' );
  2138. if ( pszTmp )
  2139. {
  2140. lstrcpy( pszRegHiveKey, CharNext(pszTmp) );
  2141. bFound = TRUE;
  2142. }
  2143. }
  2144. if ( !bFound )
  2145. {
  2146. int i;
  2147. HKEY hKey;
  2148. char szRegFilePath[MAX_PATH];
  2149. for ( i = 0; i<9999; i++ )
  2150. {
  2151. wsprintf( szBuf, c_szHiveKey_FMT, i );
  2152. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  2153. {
  2154. RegCloseKey( hKey );
  2155. }
  2156. else
  2157. {
  2158. lstrcpy( szRegFilePath, pszBackupPath);
  2159. AddPath( szRegFilePath, szBuf );
  2160. if ( GetFileAttributes( szRegFilePath ) == (DWORD)-1 )
  2161. {
  2162. bFound = TRUE;
  2163. lstrcpy( pszRegHiveKey, szBuf );
  2164. break;
  2165. }
  2166. }
  2167. }
  2168. }
  2169. return bFound;
  2170. }
  2171. void SetPathForRegHiveUse( LPSTR pszPath, DWORD * adwAttr, int iLevels, BOOL bSave )
  2172. {
  2173. int i;
  2174. char szBuf[MAX_PATH];
  2175. lstrcpy( szBuf, pszPath );
  2176. // create the folder if it does not exist without hiden
  2177. if ( bSave )
  2178. CreateFullPath( szBuf, FALSE );
  2179. for ( i =0; i<iLevels ; i++ )
  2180. {
  2181. if ( bSave )
  2182. {
  2183. adwAttr[i] = GetFileAttributes( szBuf );
  2184. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  2185. }
  2186. else
  2187. {
  2188. SetFileAttributes( szBuf, adwAttr[i] );
  2189. }
  2190. if ( !GetParentDir( szBuf ) )
  2191. break;
  2192. }
  2193. }
  2194. BOOL NeedBackupData(LPCSTR pszInf, LPCSTR pszSec)
  2195. {
  2196. char szBuf[MAX_PATH];
  2197. BOOL bRet = TRUE;
  2198. if ( (ctx.wOSVer >= _OSVER_WINNT50) &&
  2199. GetEnvironmentVariable( "Upgrade", szBuf, sizeof(szBuf) ) )
  2200. {
  2201. if ( GetModuleFileName( NULL, szBuf, sizeof(szBuf) ) )
  2202. {
  2203. LPSTR pszFile;
  2204. // if setup.exe is last filenane
  2205. pszFile = ANSIStrRChr( szBuf,'\\' );
  2206. if ( pszFile++ && (lstrcmpi(pszFile,"setup.exe")==0) )
  2207. bRet = FALSE;
  2208. }
  2209. }
  2210. if (bRet)
  2211. {
  2212. // check if INF specify not backup on this platform
  2213. if (SUCCEEDED(GetTranslatedString(pszInf, pszSec, ADVINF_NOBACKPLATF, szBuf, sizeof(szBuf), NULL)) && szBuf[0])
  2214. {
  2215. char szInfPlatform[10];
  2216. int i = 0;
  2217. while (GetFieldString(szBuf, i++, szInfPlatform, sizeof(szInfPlatform)))
  2218. {
  2219. if (!lstrcmpi(c_pszPlatform[ctx.wOSVer], szInfPlatform))
  2220. {
  2221. bRet = FALSE;
  2222. break;
  2223. }
  2224. }
  2225. }
  2226. }
  2227. return bRet;
  2228. }
  2229. void DeleteOldBackupData( HKEY hKey )
  2230. {
  2231. CHAR szBuf[MAX_PATH];
  2232. DWORD dwSize;
  2233. // delete the backup files
  2234. dwSize = sizeof(szBuf);
  2235. if ( RegQueryValueEx( hKey, REGVAL_BKFILE, NULL, NULL, szBuf, &dwSize ) == ERROR_SUCCESS )
  2236. {
  2237. LPSTR pszExt;
  2238. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  2239. DeleteFile( szBuf );
  2240. pszExt = ANSIStrRChr( szBuf, '.' );
  2241. if ( pszExt )
  2242. {
  2243. lstrcpy( pszExt, ".INI" );
  2244. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  2245. DeleteFile( szBuf );
  2246. }
  2247. // delete the catalogs
  2248. dwSize = sizeof(szBuf);
  2249. if (RegQueryValueEx(hKey, REGVAL_BKDIR, NULL, NULL, szBuf, &dwSize) == ERROR_SUCCESS)
  2250. {
  2251. HKEY hkCatalogKey;
  2252. if (RegOpenKeyEx(hKey, REGSUBK_CATALOGS, 0, KEY_READ, &hkCatalogKey) == ERROR_SUCCESS)
  2253. {
  2254. CHAR szCatalogName[MAX_PATH];
  2255. DWORD dwIndex;
  2256. dwIndex = 0;
  2257. dwSize = sizeof(szCatalogName);
  2258. while (RegEnumValue(hkCatalogKey, dwIndex, szCatalogName, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  2259. {
  2260. CHAR szFullCatalogName[MAX_PATH];
  2261. lstrcpy(szFullCatalogName, szBuf);
  2262. AddPath(szFullCatalogName, szCatalogName);
  2263. SetFileAttributes(szFullCatalogName, FILE_ATTRIBUTE_NORMAL);
  2264. DeleteFile(szFullCatalogName);
  2265. dwIndex++;
  2266. dwSize = sizeof(szCatalogName);
  2267. }
  2268. RegCloseKey(hkCatalogKey);
  2269. }
  2270. }
  2271. }
  2272. // delete reg data backup file if there
  2273. dwSize = sizeof(szBuf);
  2274. if ( RegQueryValueEx( hKey, c_szRegUninstPath, NULL, NULL, szBuf, &dwSize ) == ERROR_SUCCESS )
  2275. {
  2276. SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL );
  2277. DeleteFile( szBuf );
  2278. }
  2279. return;
  2280. }
  2281. BOOL RemoveBackupBaseOnVer( LPCSTR pszInf, LPCSTR pszSection )
  2282. {
  2283. BOOL fRet = TRUE;
  2284. char szBuf[MAX_PATH], szModule[MAX_PATH];
  2285. HKEY hKey, hRootKey;
  2286. DWORD dwSize;
  2287. WORD wInfVer, wRegVer;
  2288. if (FAILED(GetTranslatedString( pszInf, pszSection, ADVINF_MODNAME, szModule, sizeof(szModule), NULL)))
  2289. {
  2290. // no ops if there is no ComponentName
  2291. goto done;
  2292. }
  2293. // Check if the Component MajorVer matches up the backup data version stamp, if not, delete the old backup data.
  2294. //
  2295. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_SAVERESTORE, 0, KEY_WRITE|KEY_READ, &hRootKey) == ERROR_SUCCESS)
  2296. {
  2297. if ( RegOpenKeyEx( hRootKey, szModule, 0, KEY_WRITE|KEY_READ, &hKey) == ERROR_SUCCESS)
  2298. {
  2299. dwSize = sizeof(szBuf);
  2300. if ( RegQueryValueEx( hKey, REGVAL_BKMODVER, NULL, NULL, szBuf, &dwSize ) == ERROR_SUCCESS )
  2301. {
  2302. WORD wVer[4];
  2303. ConvertVersionString( szBuf, wVer, '.' );
  2304. wRegVer = wVer[0]; // taking Major version only
  2305. }
  2306. else
  2307. wRegVer = 0; // indication no version stamp
  2308. if (SUCCEEDED(GetTranslatedString(pszInf, pszSection, ADVINF_MODVER, szBuf, sizeof(szBuf), NULL)))
  2309. {
  2310. WORD wVer[4];
  2311. ConvertVersionString( szBuf, wVer, '.' );
  2312. wInfVer = wVer[0]; // taking Major version only
  2313. }
  2314. else
  2315. wInfVer = 0; // indication no version stamp
  2316. if ( wInfVer > wRegVer )
  2317. {
  2318. // delete HKLM branch
  2319. DeleteOldBackupData( hKey );
  2320. RegCloseKey( hKey );
  2321. RegDeleteKeyRecursively( hRootKey, szModule );
  2322. // delete HKCU branch
  2323. if ( RegOpenKeyEx( HKEY_CURRENT_USER, REGKEY_SAVERESTORE, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
  2324. {
  2325. RegDeleteKeyRecursively( hKey, szModule );
  2326. RegCloseKey( hKey );
  2327. }
  2328. hKey = NULL;
  2329. }
  2330. if ( hKey )
  2331. {
  2332. RegCloseKey( hKey );
  2333. }
  2334. }
  2335. RegCloseKey( hRootKey );
  2336. }
  2337. done:
  2338. return fRet;
  2339. }
  2340. VOID AdvStartLogging()
  2341. {
  2342. CHAR szBuf[MAX_PATH], szLogFileName[MAX_PATH];
  2343. HKEY hKey;
  2344. // Need to 0 the buffer, becauce if the registry branch below does not exist
  2345. // Advpack would use what ever (garbage) was in the buffer to create a log file
  2346. *szLogFileName = '\0';
  2347. // check if logging is enabled
  2348. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SAVERESTORE, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  2349. {
  2350. DWORD dwDataLen = sizeof(szLogFileName);
  2351. if (RegQueryValueEx(hKey, "AdvpackLogFile", NULL, NULL, szLogFileName, &dwDataLen) != ERROR_SUCCESS)
  2352. *szLogFileName = '\0';
  2353. RegCloseKey(hKey);
  2354. }
  2355. if (*szLogFileName)
  2356. {
  2357. if (szLogFileName[1] != ':') // crude way of determining if fully qualified path is specified or not
  2358. {
  2359. GetWindowsDirectory(szBuf, sizeof(szBuf)); // default to windows dir
  2360. AddPath(szBuf, szLogFileName);
  2361. }
  2362. else
  2363. lstrcpy(szBuf, szLogFileName);
  2364. if ((g_hAdvLogFile == INVALID_HANDLE_VALUE) &&
  2365. (g_hAdvLogFile = CreateFile(szBuf, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
  2366. SetFilePointer(g_hAdvLogFile, 0, NULL, FILE_END); // append logging info to the file
  2367. }
  2368. }
  2369. VOID AdvWriteToLog(PCSTR pcszFormatString, ...)
  2370. {
  2371. va_list vaArgs;
  2372. LPSTR pszFullErrMsg = NULL;
  2373. DWORD dwBytesWritten;
  2374. if (g_hAdvLogFile != INVALID_HANDLE_VALUE)
  2375. {
  2376. va_start(vaArgs, pcszFormatString);
  2377. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
  2378. (LPCVOID) pcszFormatString, 0, 0, (LPSTR) &pszFullErrMsg, 0, &vaArgs);
  2379. if (pszFullErrMsg != NULL)
  2380. {
  2381. WriteFile(g_hAdvLogFile, pszFullErrMsg, lstrlen(pszFullErrMsg), &dwBytesWritten, NULL);
  2382. LocalFree(pszFullErrMsg);
  2383. }
  2384. }
  2385. }
  2386. VOID AdvStopLogging()
  2387. {
  2388. if (g_hAdvLogFile != INVALID_HANDLE_VALUE)
  2389. {
  2390. CloseHandle(g_hAdvLogFile);
  2391. g_hAdvLogFile = INVALID_HANDLE_VALUE;
  2392. }
  2393. }
  2394. VOID AdvLogDateAndTime()
  2395. {
  2396. if (g_hAdvLogFile != INVALID_HANDLE_VALUE)
  2397. {
  2398. SYSTEMTIME SystemTime;
  2399. GetLocalTime(&SystemTime);
  2400. AdvWriteToLog("Date: %1!02d!/%2!02d!/%3!04d! (mm/dd/yyyy)\tTime: %4!02d!:%5!02d!:%6!02d! (hh:mm:ss)\r\n",
  2401. SystemTime.wMonth, SystemTime.wDay, SystemTime.wYear,
  2402. SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);
  2403. }
  2404. }