Leaked source code of windows server 2003
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.

1116 lines
33 KiB

  1. //***************************************************************************
  2. //* Copyright (c) Microsoft Corporation 1995. All rights reserved. *
  3. //***************************************************************************
  4. //* *
  5. //* UTILS.C - Win32 Based Cabinet File Self-extractor and installer utils. *
  6. //* *
  7. //***************************************************************************
  8. //* *
  9. //* Originally written by Jeff Webber. *
  10. //* *
  11. //***************************************************************************
  12. //***************************************************************************
  13. //* INCLUDE FILES *
  14. //***************************************************************************
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "wextract.h"
  18. #include "regstr.h"
  19. #include "global.h"
  20. #include <commctrl.h>
  21. static TCHAR szRegRunOnceKey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
  22. static TCHAR szNT4XDelayUntilReboot[] = "System\\CurrentControlSet\\Control\\Session Manager";
  23. static TCHAR szNT4XPendingValue[] = "PendingFileRenameOperations";
  24. static TCHAR szNT3XDelayUntilReboot[] = "System\\CurrentControlSet\\Control\\Session Manager\\FileRenameOperations";
  25. static TCHAR szRegValNameTemplate[] = "wextract_cleanup%d";
  26. static TCHAR szRegValTemplate[] = "%s /D:%s";
  27. static TCHAR szRegValAdvpackTemplate[] = "rundll32.exe %sadvpack.dll,DelNodeRunDLL32 \"%s\"";
  28. static TCHAR szBATCommand[] = "Command.com /c %s";
  29. // store the RunOnce Clean-up reg keyname for this instance
  30. //
  31. TCHAR g_szRegValName[SMALL_BUF_LEN] = { 0 };
  32. BOOL g_bConvertRunOnce = FALSE;
  33. //***************************************************************************
  34. //* Functions *
  35. //***************************************************************************
  36. typedef HRESULT (*CHECKTOKENMEMBERSHIP)(HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember);
  37. BOOL CheckToken(BOOL *pfIsAdmin)
  38. {
  39. BOOL bNewNT5check = FALSE;
  40. HINSTANCE hAdvapi32 = NULL;
  41. CHECKTOKENMEMBERSHIP pf;
  42. PSID AdministratorsGroup;
  43. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  44. hAdvapi32 = LoadLibrary("advapi32.dll");
  45. if (hAdvapi32)
  46. {
  47. pf = (CHECKTOKENMEMBERSHIP)GetProcAddress(hAdvapi32, "CheckTokenMembership");
  48. if (pf)
  49. {
  50. bNewNT5check = TRUE;
  51. *pfIsAdmin = FALSE;
  52. if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  53. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) )
  54. {
  55. pf(NULL, AdministratorsGroup, pfIsAdmin);
  56. FreeSid(AdministratorsGroup);
  57. }
  58. }
  59. FreeLibrary(hAdvapi32);
  60. }
  61. return bNewNT5check;
  62. }
  63. // IsNTAdmin();
  64. // Returns true if our process has admin priviliges.
  65. // Returns false otherwise.
  66. BOOL IsNTAdmin()
  67. {
  68. static int fIsAdmin = 2;
  69. HANDLE hAccessToken;
  70. PTOKEN_GROUPS ptgGroups;
  71. DWORD dwReqSize;
  72. UINT i;
  73. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  74. PSID AdministratorsGroup;
  75. BOOL bRet;
  76. //
  77. // If we have cached a value, return the cached value. Note I never
  78. // set the cached value to false as I want to retry each time in
  79. // case a previous failure was just a temp. problem (ie net access down)
  80. //
  81. bRet = FALSE;
  82. ptgGroups = NULL;
  83. if( fIsAdmin != 2 )
  84. return (BOOL)fIsAdmin;
  85. if (!CheckToken(&bRet))
  86. {
  87. if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hAccessToken ) )
  88. return FALSE;
  89. // See how big of a buffer we need for the token information
  90. if(!GetTokenInformation( hAccessToken, TokenGroups, NULL, 0, &dwReqSize))
  91. {
  92. // GetTokenInfo should the buffer size we need - Alloc a buffer
  93. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  94. ptgGroups = (PTOKEN_GROUPS) LocalAlloc(LMEM_FIXED, dwReqSize);
  95. }
  96. // ptgGroups could be NULL for a coupla reasons here:
  97. // 1. The alloc above failed
  98. // 2. GetTokenInformation actually managed to succeed the first time (possible?)
  99. // 3. GetTokenInfo failed for a reason other than insufficient buffer
  100. // Any of these seem justification for bailing.
  101. // So, make sure it isn't null, then get the token info
  102. if(ptgGroups && GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, dwReqSize, &dwReqSize))
  103. {
  104. if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  105. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) )
  106. {
  107. // Search thru all the groups this process belongs to looking for the
  108. // Admistrators Group.
  109. for( i=0; i < ptgGroups->GroupCount; i++ )
  110. {
  111. if( EqualSid(ptgGroups->Groups[i].Sid, AdministratorsGroup) )
  112. {
  113. // Yea! This guy looks like an admin
  114. fIsAdmin = TRUE;
  115. bRet = TRUE;
  116. break;
  117. }
  118. }
  119. FreeSid(AdministratorsGroup);
  120. }
  121. }
  122. if(ptgGroups)
  123. LocalFree(ptgGroups);
  124. // BUGBUG: Close handle here? doc's aren't clear whether this is needed.
  125. CloseHandle(hAccessToken);
  126. }
  127. else if (bRet)
  128. fIsAdmin = TRUE;
  129. return bRet;
  130. }
  131. //**************************************************************************
  132. //
  133. // WarningDlgProc()
  134. //
  135. // Dialog proc for handling a continue/Exit dialog.
  136. //
  137. //**************************************************************************
  138. INT_PTR CALLBACK WarningDlgProc( HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam)
  139. {
  140. char szMsg[MAX_STRING];
  141. switch( msg )
  142. {
  143. case WM_INITDIALOG:
  144. CenterWindow( hwnd, GetDesktopWindow() );
  145. *szMsg = 0;
  146. LoadString(g_hInst, (UINT)lParam, szMsg, sizeof(szMsg));
  147. SetDlgItemText(hwnd, IDC_WARN_TEXT, szMsg);
  148. MessageBeep((UINT)-1);
  149. return( TRUE ); // Let default control be chosen.
  150. case WM_COMMAND:
  151. switch( wParam )
  152. {
  153. case IDC_EXIT:
  154. case IDC_CONTINUE:
  155. EndDialog( hwnd, wParam );
  156. break;
  157. default:
  158. return FALSE;
  159. }
  160. return TRUE;
  161. default:
  162. break;
  163. }
  164. return( FALSE ); // Let default dialog processing do all.
  165. }
  166. // returns start of next field (or null if null), sets start to begining of the first field,
  167. // with fields separated by separaters and nulls first separater after the first field
  168. TCHAR* ExtractField( TCHAR **pstart, TCHAR * separaters)
  169. {
  170. LPTSTR start = *pstart;
  171. int x = 0;
  172. while(ANSIStrChr(separaters, *start)) {
  173. if(*start == 0)
  174. return(NULL);
  175. start++;
  176. }
  177. *pstart = start;
  178. while(!ANSIStrChr(separaters, start[x]) && (start[x] != 0))
  179. x++;
  180. if(start[x] == 0)
  181. return(start + x);
  182. start[x] = 0;
  183. return(start + x + 1);
  184. }
  185. BOOL AnalyzeCmd( LPTSTR szOrigiCommand, LPTSTR *lplpCommand, BOOL *pfInfCmd )
  186. {
  187. TCHAR szTmp[MAX_PATH];
  188. TCHAR szINFFile[MAX_PATH];
  189. LPTSTR szNextField, szCurrField, szExt;
  190. UINT secLength;
  191. LPTSTR lpTempCmd, pszINFEngine;
  192. lstrcpy( szTmp, szOrigiCommand );
  193. // check if the command is LFN name
  194. if ( szTmp[0] == '"' )
  195. {
  196. szCurrField = &szTmp[1];
  197. szNextField = ExtractField( &szCurrField, "\"" );
  198. }
  199. else
  200. {
  201. szCurrField = szTmp;
  202. szNextField = ExtractField( &szCurrField, " " );
  203. }
  204. if ( !IsRootPath( szCurrField ) )
  205. {
  206. // BUGBUG: when IsRootPath Failed, we did not check if the givn
  207. // szCurrField is valid name or not. If it is not valid, the result
  208. // of the AddPath will produce invalid file path. The error will come out at
  209. // either SETUP engine or CreateProcess
  210. //
  211. lstrcpy( szINFFile, g_Sess.achDestDir );
  212. AddPath( szINFFile, szCurrField );
  213. }
  214. else
  215. lstrcpy( szINFFile, szCurrField );
  216. // check if this is a INF file command
  217. if ( ((szExt = ANSIStrRChr( szCurrField, '.' )) != NULL) && !lstrcmpi( szExt, ".INF" ) )
  218. {
  219. // check to see if this valid command
  220. if ( !FileExists( szINFFile ) )
  221. {
  222. ErrorMsg1Param( NULL, IDS_ERR_FILENOTEXIST, szINFFile );
  223. return FALSE;
  224. }
  225. // check if there is INF section install, and get the sec start point
  226. szCurrField = szNextField;
  227. szNextField = ExtractField( &szCurrField, "[" ); // skip things between .INF and [ section beginning
  228. secLength = lstrlen( achDefaultSection );
  229. if ( szNextField )
  230. {
  231. // in the case of: .INF<single-blank>[abc]
  232. // the szNextField is "" while in the case of: .INF<multiple-blanks>[abc]
  233. // szNextField points to "abc]". Therefore, the conditional pointer switch added here
  234. //
  235. if ( *szNextField )
  236. {
  237. szCurrField = szNextField;
  238. }
  239. szNextField = ExtractField( &szCurrField, "]" ); // get INF InstallSection name
  240. if ( *szCurrField )
  241. {
  242. secLength = lstrlen( szCurrField );
  243. }
  244. }
  245. lpTempCmd = (LPSTR) LocalAlloc( LPTR, 512);
  246. if ( ! lpTempCmd )
  247. {
  248. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  249. return FALSE;
  250. }
  251. // store INF name for reboot checking use
  252. g_uInfRebootOn = GetPrivateProfileInt( *szCurrField ? szCurrField : achDefaultSection, "Reboot", 0, szINFFile );
  253. *pfInfCmd = TRUE; // no RunOnce entry needed
  254. // check if we need use Advanced INF dll handling
  255. if ( GetPrivateProfileString( SEC_VERSION, KEY_ADVINF, "", lpTempCmd, 8, szINFFile )
  256. > 0 )
  257. {
  258. g_Sess.uExtractOpt |= EXTRACTOPT_ADVDLL;
  259. // re-use the buf here
  260. lstrcpy( szOrigiCommand, *szCurrField ? szCurrField : achDefaultSection );
  261. lstrcpy( lpTempCmd, szINFFile );
  262. }
  263. else
  264. {
  265. g_Sess.uExtractOpt &= ~(EXTRACTOPT_ADVDLL);
  266. if (g_wOSVer == _OSVER_WIN9X)
  267. {
  268. pszINFEngine = "setupx.dll";
  269. GetShortPathName( szINFFile, szINFFile, sizeof(szINFFile) );
  270. }
  271. else
  272. pszINFEngine = "setupapi.dll";
  273. wsprintf( lpTempCmd, achSETUPDLL, pszINFEngine,
  274. *szCurrField ? szCurrField : achDefaultSection, szINFFile );
  275. }
  276. }
  277. else if ( ((szExt = ANSIStrRChr( szCurrField, '.' )) != NULL) && !lstrcmpi( szExt, ".BAT" ) )
  278. {
  279. lpTempCmd = (LPSTR) LocalAlloc( LPTR, lstrlen( szBATCommand ) + lstrlen( szINFFile ) + 8 );
  280. if ( ! lpTempCmd )
  281. {
  282. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  283. return FALSE;
  284. }
  285. wsprintf( lpTempCmd, szBATCommand, szINFFile );
  286. }
  287. else
  288. {
  289. // assume EXE command
  290. // you are here, the szINFFile contains the command with fully qualified pathname enterred either
  291. // by User or appended by wextract.exe to Temp extracting file location.
  292. DWORD dwAttr;
  293. CHAR szCmd[2*MAX_STRING];
  294. lpTempCmd = (LPSTR) LocalAlloc( LPTR, 2*MAX_STRING ); // 1K buf
  295. if ( ! lpTempCmd )
  296. {
  297. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  298. return FALSE;
  299. }
  300. dwAttr = GetFileAttributes( szINFFile );
  301. if ( (dwAttr == -1) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY) )
  302. {
  303. // file is not found as it IS. Run it as it WAS!
  304. // IS and WAS may be the same if user enterred fully qaulified name. CreateProcess will buff it.
  305. lstrcpy( szCmd, szOrigiCommand );
  306. }
  307. else
  308. {
  309. // found it. Run it as it IS. Need to append switches if there is any.
  310. lstrcpy( szCmd, szINFFile );
  311. if ( szNextField && *szNextField )
  312. {
  313. lstrcat( szCmd, " " );
  314. lstrcat( szCmd, szNextField );
  315. }
  316. }
  317. // replace the #D with the directory this module is loaded or
  318. // #E with the fullpath of the running EXE
  319. ExpandCmdParams( szCmd, lpTempCmd );
  320. }
  321. *lplpCommand = lpTempCmd;
  322. return TRUE;
  323. }
  324. void DisplayHelp()
  325. {
  326. MsgBox1Param( NULL, IDS_HELPMSG, "", MB_ICONINFORMATION, MB_OK );
  327. }
  328. DWORD CheckReboot( VOID )
  329. {
  330. DWORD dwReturn = 0xFFFFFFFF;
  331. if ( !g_uInfRebootOn )
  332. {
  333. if (NeedReboot(g_dwRebootCheck, g_wOSVer))
  334. dwReturn = EWX_REBOOT;
  335. }
  336. else
  337. dwReturn = EWX_REBOOT; // reboot = 1 in inf file
  338. return dwReturn;
  339. }
  340. // NT reboot
  341. //
  342. BOOL MyNTReboot()
  343. {
  344. HANDLE hToken;
  345. TOKEN_PRIVILEGES tkp;
  346. // get a token from this process
  347. if ( !OpenProcessToken( GetCurrentProcess(),
  348. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
  349. {
  350. ErrorMsg( NULL, IDS_ERR_OPENPROCTK );
  351. return FALSE;
  352. }
  353. // get the LUID for the shutdown privilege
  354. LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid );
  355. tkp.PrivilegeCount = 1;
  356. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  357. //get the shutdown privilege for this proces
  358. if ( !AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0 ) )
  359. {
  360. ErrorMsg( NULL, IDS_ERR_ADJTKPRIV );
  361. return FALSE;
  362. }
  363. // shutdown the system and force all applications to close
  364. if (!ExitWindowsEx( EWX_REBOOT, 0 ) )
  365. {
  366. ErrorMsg( NULL, IDS_ERR_EXITWINEX );
  367. return FALSE;
  368. }
  369. return TRUE;
  370. }
  371. // Display a dialog asking the user to restart Windows, with a button that
  372. // will do it for them if possible.
  373. //
  374. void MyRestartDialog( DWORD dwRebootMode )
  375. {
  376. UINT id = IDCANCEL;
  377. DWORD dwReturn;
  378. // only if you checked and REBOOT_YES is true, you are here
  379. if ( dwRebootMode & REBOOT_ALWAYS )
  380. {
  381. dwReturn = EWX_REBOOT;
  382. }
  383. else
  384. {
  385. dwReturn = CheckReboot();
  386. }
  387. if ( dwReturn == EWX_REBOOT )
  388. {
  389. if ( dwRebootMode & REBOOT_SILENT )
  390. id = IDYES;
  391. else
  392. {
  393. id = MsgBox1Param( NULL, IDS_RESTARTYESNO, "", MB_ICONINFORMATION, MB_YESNO );
  394. }
  395. if ( id == IDYES )
  396. {
  397. if ( dwReturn == EWX_REBOOT )
  398. {
  399. if ( g_wOSVer == _OSVER_WIN9X )
  400. {
  401. // By default (all platforms), we assume powerdown is possible
  402. id = ExitWindowsEx( EWX_REBOOT, 0 );
  403. }
  404. else
  405. {
  406. MyNTReboot();
  407. }
  408. }
  409. }
  410. }
  411. return;
  412. }
  413. // CleanRegRunOnce()
  414. //
  415. void CleanRegRunOnce()
  416. {
  417. HKEY hKey;
  418. if ( g_szRegValName[0] == 0 )
  419. {
  420. return;
  421. }
  422. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS )
  423. {
  424. RegDeleteValue( hKey, g_szRegValName );
  425. RegCloseKey( hKey );
  426. }
  427. return;
  428. }
  429. void AddRegRunOnce()
  430. {
  431. HKEY hKey;
  432. DWORD dwDisposition;
  433. LPSTR szRegEntry;
  434. TCHAR szBuf[MAX_PATH] = "";
  435. TCHAR szAdvpack[MAX_PATH] = "";
  436. int i;
  437. DWORD dwTmp;
  438. HANDLE hSetupLibrary;
  439. BOOL fUseAdvpack = FALSE;
  440. // prepare backup registry
  441. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
  442. {
  443. // reg problem, but not block the process
  444. return;
  445. }
  446. // Check if key already exists -- if so, go with next number.
  447. //
  448. for (i=0; i<200; i++)
  449. {
  450. wsprintf( g_szRegValName, szRegValNameTemplate, i );
  451. if ( RegQueryValueEx( hKey, g_szRegValName, 0, NULL, NULL, &dwTmp ) != ERROR_SUCCESS )
  452. {
  453. // g_szRegValName now has the key name we need for this instance
  454. break;
  455. }
  456. }
  457. if ( i == 200 )
  458. {
  459. // something is wrong, there are at lease 200 RunOnce enteries in the Registry
  460. // bail out, don't add any more
  461. RegCloseKey( hKey );
  462. g_szRegValName[0] = 0;
  463. return;
  464. }
  465. // check if ADVPACK in the system dir exports DelNodeRunDLL32;
  466. // if so, use szRegValAdvpackTemplate, otherwise, use szRegValTemplate
  467. GetSystemDirectory(szAdvpack, sizeof(szAdvpack));
  468. AddPath(szAdvpack, ADVPACKDLL);
  469. if ((hSetupLibrary = LoadLibrary(szAdvpack)) != NULL)
  470. {
  471. fUseAdvpack = GetProcAddress(hSetupLibrary, "DelNodeRunDLL32") != NULL;
  472. FreeLibrary(hSetupLibrary);
  473. }
  474. if (fUseAdvpack)
  475. {
  476. if (GetSystemDirectory(szBuf, sizeof(szBuf)))
  477. AddPath(szBuf, "");
  478. }
  479. else
  480. {
  481. // get current EXE filename
  482. //
  483. if ( !GetModuleFileName( g_hInst, szBuf, (DWORD)sizeof(szBuf) ) )
  484. {
  485. RegCloseKey( hKey );
  486. return;
  487. }
  488. }
  489. // alloc mem for store reg entry values
  490. //
  491. szRegEntry = (LPSTR) LocalAlloc( LPTR, lstrlen(szBuf) + lstrlen(g_Sess.achDestDir) + SMALL_BUF_LEN );
  492. if ( !szRegEntry )
  493. {
  494. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  495. RegCloseKey( hKey );
  496. return;
  497. }
  498. g_bConvertRunOnce = !fUseAdvpack;
  499. wsprintf(szRegEntry, fUseAdvpack ? szRegValAdvpackTemplate : szRegValTemplate, szBuf, g_Sess.achDestDir);
  500. RegSetValueEx( hKey, g_szRegValName, 0, REG_SZ, (CONST BYTE*)szRegEntry, lstrlen(szRegEntry)+1);
  501. RegCloseKey(hKey);
  502. LocalFree( szRegEntry );
  503. return;
  504. }
  505. // Change the RunOnce entry that cleans up extracted files to use ADVPACK instead of wextract
  506. void ConvertRegRunOnce()
  507. {
  508. if (*g_szRegValName)
  509. {
  510. HKEY hKey;
  511. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS)
  512. {
  513. TCHAR szRegEntry[2 * MAX_PATH + sizeof(szRegValAdvpackTemplate)];
  514. DWORD dwSize = sizeof(szRegEntry);
  515. // read the old value data that uses wextract and get the extracted files dir
  516. if (RegQueryValueEx(hKey, g_szRegValName, NULL, NULL, (LPBYTE) szRegEntry, &dwSize) == ERROR_SUCCESS)
  517. {
  518. TCHAR szSysDir[MAX_PATH] = "";
  519. if (GetSystemDirectory(szSysDir, sizeof(szSysDir)))
  520. AddPath(szSysDir, "");
  521. wsprintf(szRegEntry, szRegValAdvpackTemplate, szSysDir, g_Sess.achDestDir);
  522. RegSetValueEx(hKey, g_szRegValName, 0, REG_SZ, (CONST BYTE *) szRegEntry, lstrlen(szRegEntry) + 1);
  523. }
  524. RegCloseKey(hKey);
  525. }
  526. }
  527. return;
  528. }
  529. void DeleteMyDir( LPSTR lpDir )
  530. {
  531. char szFile[MAX_PATH];
  532. WIN32_FIND_DATA fileData;
  533. HANDLE hFindFile;
  534. if ( lpDir == NULL || *lpDir == '\0' )
  535. return;
  536. lstrcpy( szFile, lpDir );
  537. lstrcat( szFile, "*" );
  538. hFindFile = FindFirstFile( szFile, &fileData );
  539. if ( hFindFile == INVALID_HANDLE_VALUE )
  540. return;
  541. do
  542. {
  543. lstrcpy( szFile, lpDir );
  544. if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  545. {
  546. if ( lstrcmp( fileData.cFileName, "." ) == 0 ||
  547. lstrcmp( fileData.cFileName, ".." ) == 0 )
  548. continue;
  549. // delete the sub-dir
  550. lstrcat( szFile, fileData.cFileName );
  551. AddPath( szFile, "");
  552. DeleteMyDir( szFile );
  553. }
  554. else
  555. {
  556. // delete the file
  557. lstrcat( szFile, fileData.cFileName );
  558. SetFileAttributes( szFile, FILE_ATTRIBUTE_NORMAL );
  559. DeleteFile( szFile );
  560. }
  561. } while ( FindNextFile( hFindFile, &fileData ) );
  562. FindClose( hFindFile );
  563. RemoveDirectory( lpDir );
  564. }
  565. #if 0
  566. //==================================================================
  567. // AddPath()
  568. //
  569. void AddPath(LPSTR szPath, LPCSTR szName )
  570. {
  571. LPSTR szTmp;
  572. // Find end of the string
  573. szTmp = szPath + lstrlen(szPath);
  574. // If no trailing backslash then add one
  575. if ( szTmp > szPath && *(AnsiPrev( szPath, szTmp )) != '\\' )
  576. *(szTmp++) = '\\';
  577. // Add new name to existing path string
  578. while ( *szName == ' ' ) szName++;
  579. lstrcpy( szTmp, szName );
  580. }
  581. #endif
  582. //---------------------------------------------------------------------------
  583. // Returns TRUE if the given string is a UNC path.
  584. //
  585. // check if a path is a root path
  586. //
  587. // returns:
  588. // TRUE for "X:\..." "\\foo\asdf\..."
  589. // FALSE for others
  590. BOOL IsRootPath(LPCSTR pPath)
  591. {
  592. if ( !pPath || (lstrlen(pPath) < 3) )
  593. {
  594. return FALSE;
  595. }
  596. // BUGBUG: this just smell like UNC, possible invalid UNC. If so,
  597. // user will get error when later create process
  598. if ( ( (*(pPath+1) == ':') && (*(pPath+2) == '\\') ) || // "X:\" case
  599. ( (*pPath == '\\') && (*(pPath + 1) == '\\' ) ) ) // UNC \\.... case
  600. return TRUE;
  601. else
  602. return FALSE;
  603. }
  604. // BUGBUG:BUGBUG:BUGBUG:BUGBUG
  605. // The code below is duplicated in advpack.dll. If you do changed/fixes to this code
  606. // make sure to also change the code in advpack.dll
  607. // Returns the size of wininit.ini in the windows directory.
  608. // 0 if not found
  609. DWORD GetWininitSize()
  610. {
  611. TCHAR szPath[MAX_PATH];
  612. HFILE hFile;
  613. DWORD dwSize = (DWORD)0;
  614. if ( GetWindowsDirectory( szPath, MAX_PATH ) )
  615. {
  616. AddPath( szPath, "wininit.ini" );
  617. // Make sure all changes have been saved to disk for accurate size reading
  618. WritePrivateProfileString(NULL, NULL, NULL, szPath);
  619. if ((hFile = _lopen(szPath, OF_READ|OF_SHARE_DENY_NONE)) != HFILE_ERROR)
  620. {
  621. dwSize = _llseek(hFile, 0L, FILE_END);
  622. _lclose(hFile);
  623. }
  624. }
  625. return dwSize;
  626. }
  627. // Returns the size of the value lpcszValue under lpcszRegKey
  628. // 0 if the registry key or the value were not found
  629. DWORD GetRegValueSize(LPCSTR lpcszRegKey, LPCSTR lpcszValue)
  630. {
  631. HKEY hKey;
  632. DWORD dwValueSize = (DWORD)0;
  633. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpcszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  634. {
  635. if (RegQueryValueEx(hKey, lpcszValue, NULL, NULL, NULL,&dwValueSize) != ERROR_SUCCESS)
  636. dwValueSize = (DWORD)0;
  637. RegCloseKey(hKey);
  638. }
  639. return dwValueSize;
  640. }
  641. // Returns the number of Values in the key
  642. // 0 if the registry key was not found or RegQueryInfoKey failed
  643. DWORD GetNumberOfValues(LPCSTR lpcszRegKey)
  644. {
  645. HKEY hKey;
  646. DWORD dwValueSize = (DWORD)0;
  647. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpcszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  648. {
  649. if (RegQueryInfoKey(hKey,
  650. NULL, NULL, NULL, NULL, NULL, NULL,
  651. &dwValueSize,
  652. NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
  653. dwValueSize = (DWORD)0;
  654. RegCloseKey(hKey);
  655. }
  656. return dwValueSize;
  657. }
  658. // Returns the rebootcheck value depending on the OS we get passed in.
  659. DWORD NeedRebootInit(WORD wOSVer)
  660. {
  661. DWORD dwReturn = (DWORD)0;
  662. switch (wOSVer)
  663. {
  664. case _OSVER_WIN9X:
  665. dwReturn = GetWininitSize();
  666. break;
  667. case _OSVER_WINNT40:
  668. case _OSVER_WINNT50:
  669. dwReturn = GetRegValueSize(szNT4XDelayUntilReboot, szNT4XPendingValue);
  670. break;
  671. case _OSVER_WINNT3X:
  672. dwReturn = GetNumberOfValues(szNT3XDelayUntilReboot);
  673. break;
  674. }
  675. return dwReturn;
  676. }
  677. // Checks the passed in reboot check value against the current value.
  678. // If they are different, we need to reboot.
  679. // The reboot check value is dependend on the OS
  680. BOOL NeedReboot(DWORD dwRebootCheck, WORD wOSVer)
  681. {
  682. return (dwRebootCheck != NeedRebootInit(wOSVer));
  683. }
  684. // check if Dir does not exist, create one.
  685. //
  686. BOOL IfNotExistCreateDir( LPTSTR lpDir )
  687. {
  688. DWORD attr;
  689. if ( (attr = GetFileAttributes( lpDir )) == -1 )
  690. {
  691. return ( CreateDirectory( lpDir, NULL ) );
  692. }
  693. return (attr & FILE_ATTRIBUTE_DIRECTORY);
  694. }
  695. // check if the given dir is on Windows Drive
  696. //
  697. BOOL IsWindowsDrive( LPTSTR szPath )
  698. {
  699. TCHAR szWin[MAX_PATH];
  700. if ( !GetWindowsDirectory( szWin, MAX_PATH ) )
  701. {
  702. ErrorMsg( NULL, IDS_ERR_GET_WIN_DIR );
  703. ASSERT( FALSE );
  704. }
  705. return ( *szPath == szWin[0] );
  706. }
  707. PSTR MyULtoA( ULONG ulParam, PSTR pszOut )
  708. {
  709. wsprintf( pszOut, "%lu", ulParam );
  710. return pszOut;
  711. }
  712. // display diskspace checking Error message
  713. // it always return FALSE except that User answer YES on msgbox
  714. //
  715. BOOL DiskSpaceErrMsg( UINT msgType, ULONG ulExtractNeeded, DWORD dwInstNeeded, LPTSTR lpDrv )
  716. {
  717. TCHAR szSize[10];
  718. BOOL bRet = FALSE;
  719. // all the cases except one are returning FALSE, so we set Error code here
  720. g_dwExitCode = ERROR_DISK_FULL;
  721. if ( msgType == MSG_REQDSK_ERROR )
  722. {
  723. ErrorMsg1Param( NULL, IDS_ERR_NO_SPACE_ERR, MyULtoA((ulExtractNeeded+dwInstNeeded), szSize) );
  724. }
  725. else if ( msgType == MSG_REQDSK_RETRYCANCEL )
  726. {
  727. if ( MsgBox1Param( NULL, IDS_ERR_NO_SPACE_BOTH, MyULtoA( (ulExtractNeeded+dwInstNeeded), szSize),
  728. MB_ICONQUESTION, MB_RETRYCANCEL|MB_DEFBUTTON1 ) == IDRETRY )
  729. bRet = TRUE;
  730. else
  731. bRet = FALSE;
  732. }
  733. else if ( msgType == MSG_REQDSK_WARN )
  734. {
  735. // in /Q mode: MsgBox2Param return MB_OK which is not IDYES, so we fail the process.
  736. //
  737. if ( MsgBox2Param( NULL, IDS_ERR_NO_SPACE_INST, MyULtoA(dwInstNeeded, szSize), lpDrv,
  738. MB_ICONINFORMATION, MB_YESNO | MB_DEFBUTTON2 ) == IDYES )
  739. {
  740. bRet = TRUE;
  741. g_dwExitCode = S_OK;
  742. }
  743. }
  744. //else ( msgType == MSG_REQDSK_NONE ) do nothing
  745. return bRet;
  746. }
  747. BOOL GetFileTobeChecked( LPSTR szPath, int iSize, LPCSTR szNameStr )
  748. {
  749. char ch;
  750. BOOL bComplete = FALSE;
  751. szPath[0] = 0;
  752. if ( *szNameStr == '#' )
  753. {
  754. ch = (CHAR)CharUpper((PSTR)*(++szNameStr));
  755. szNameStr = CharNext( CharNext( szNameStr ) );
  756. switch ( ch )
  757. {
  758. case 'S':
  759. GetSystemDirectory( szPath, iSize );
  760. break;
  761. case 'W':
  762. GetWindowsDirectory( szPath, iSize );
  763. break;
  764. case 'A':
  765. default:
  766. {
  767. // look into reg AppPath
  768. char szSubKey[MAX_PATH];
  769. DWORD dwSize = sizeof( szSubKey );
  770. HKEY hKey;
  771. DWORD dwType;
  772. lstrcpy( szSubKey, REGSTR_PATH_APPPATHS );
  773. AddPath( szSubKey, szNameStr );
  774. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey ) == ERROR_SUCCESS )
  775. {
  776. if ( RegQueryValueEx(hKey, "", NULL, &dwType, (LPBYTE)szPath, &dwSize) == ERROR_SUCCESS )
  777. {
  778. if ((dwType == REG_EXPAND_SZ) &&
  779. (ExpandEnvironmentStrings(szPath, szSubKey, sizeof(szSubKey))))
  780. {
  781. lstrcpy(szPath, szSubKey);
  782. bComplete = TRUE;
  783. }
  784. else if (dwType == REG_SZ)
  785. bComplete = TRUE;
  786. }
  787. RegCloseKey( hKey );
  788. }
  789. }
  790. break;
  791. }
  792. }
  793. else
  794. GetSystemDirectory( szPath, iSize );
  795. if ( !bComplete )
  796. AddPath( szPath, szNameStr );
  797. return TRUE;
  798. }
  799. BOOL CheckFileVersion( PTARGETVERINFO ptargetVers, LPSTR szPath, int isize, int *pidx )
  800. {
  801. unsigned uiSize;
  802. DWORD dwVerInfoSize;
  803. DWORD dwHandle;
  804. VS_FIXEDFILEINFO * lpVSFixedFileInfo;
  805. void FAR *lpBuffer;
  806. HGLOBAL hgbl = NULL;
  807. BOOL bRet = FALSE;
  808. int ifrAnswer[2], itoAnswer[2], i, j;
  809. PVERCHECK pfileV;
  810. for ( i=0; i< (int)(ptargetVers->dwNumFiles); i++ )
  811. {
  812. pfileV = (PVERCHECK)( ptargetVers->szBuf + ptargetVers->dwFileOffs + i*sizeof(VERCHECK) );
  813. if ( !GetFileTobeChecked( szPath, isize, (ptargetVers->szBuf + pfileV->dwNameOffs) ) )
  814. goto EXIT;
  815. dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle);
  816. if (dwVerInfoSize)
  817. {
  818. // Alloc the memory for the version stamping
  819. hgbl = GlobalAlloc(GHND, dwVerInfoSize);
  820. if (hgbl == NULL)
  821. goto EXIT;
  822. lpBuffer = GlobalLock(hgbl);
  823. if (lpBuffer == NULL)
  824. goto EXIT;
  825. // Read version stamping info
  826. if (GetFileVersionInfo(szPath, dwHandle, dwVerInfoSize, lpBuffer))
  827. {
  828. // Get the value for Translation
  829. if ( VerQueryValue(lpBuffer, "\\", (void FAR*FAR*)&lpVSFixedFileInfo, &uiSize) && (uiSize) )
  830. {
  831. for ( j=0; j<2; j++ )
  832. {
  833. ifrAnswer[j] = CompareVersion( lpVSFixedFileInfo->dwFileVersionMS, lpVSFixedFileInfo->dwFileVersionLS,
  834. pfileV->vr[j].frVer.dwMV, pfileV->vr[j].frVer.dwLV );
  835. itoAnswer[j] = CompareVersion( lpVSFixedFileInfo->dwFileVersionMS, lpVSFixedFileInfo->dwFileVersionLS,
  836. pfileV->vr[j].toVer.dwMV, pfileV->vr[j].toVer.dwLV );
  837. }
  838. if ( (ifrAnswer[0] >= 0 && itoAnswer[0] <= 0) || (ifrAnswer[1] >= 0 && itoAnswer[1] <= 0) )
  839. ;
  840. else
  841. {
  842. GlobalUnlock(hgbl);
  843. goto EXIT;
  844. }
  845. }
  846. }
  847. GlobalUnlock(hgbl);
  848. }
  849. else
  850. {
  851. // file not exist case, if author specify install 1st ranges from version 0 to 0. Then do it!
  852. if ( pfileV->vr[0].frVer.dwMV || pfileV->vr[0].frVer.dwLV )
  853. {
  854. goto EXIT;
  855. }
  856. }
  857. }
  858. bRet = TRUE;
  859. EXIT:
  860. *pidx = i;
  861. if ( hgbl )
  862. GlobalFree( hgbl );
  863. return bRet;
  864. }
  865. UINT GetMsgboxFlag( DWORD dwFlag )
  866. {
  867. UINT uButton;
  868. if ( dwFlag & VERCHK_YESNO )
  869. uButton = MB_YESNO | MB_DEFBUTTON2;
  870. else if ( dwFlag & VERCHK_OKCANCEL )
  871. uButton = MB_OKCANCEL | MB_DEFBUTTON2;
  872. else
  873. uButton = MB_OK;
  874. return uButton;
  875. }
  876. int CompareVersion(DWORD dwMS1, DWORD dwLS1, DWORD dwMS2, DWORD dwLS2)
  877. {
  878. if (dwMS1 < dwMS2)
  879. return -1 ;
  880. if (dwMS1 > dwMS2)
  881. return 1 ;
  882. if (dwLS1 < dwLS2)
  883. return -1 ;
  884. if (dwLS1 > dwLS2)
  885. return 1 ;
  886. return 0 ;
  887. }
  888. void ExpandCmdParams( PCSTR pszInParam, PSTR pszOutParam )
  889. {
  890. CHAR szModulePath[MAX_PATH];
  891. LPSTR pszTmp;
  892. *pszOutParam = '\0';
  893. if ( !pszInParam || !*pszInParam )
  894. return;
  895. // get Module path
  896. GetModuleFileName( g_hInst, szModulePath, (DWORD)sizeof(szModulePath) );
  897. while ( *pszInParam != '\0' )
  898. {
  899. if (IsDBCSLeadByte(*pszInParam))
  900. {
  901. *pszOutParam = *pszInParam;
  902. *(pszOutParam+1) = *(pszInParam+1);
  903. }
  904. else
  905. *pszOutParam = *pszInParam;
  906. if ( *pszInParam == '#' )
  907. {
  908. pszInParam = CharNext(pszInParam);
  909. if ( (CHAR)CharUpper((PSTR)*pszInParam) == 'D' )
  910. {
  911. GetParentDir( szModulePath );
  912. pszTmp = CharPrev(szModulePath, &szModulePath[lstrlen(szModulePath)]);
  913. if (pszTmp && (*pszTmp == '\\'))
  914. *pszTmp = '\0';
  915. lstrcpy( pszOutParam, szModulePath );
  916. pszOutParam += lstrlen( szModulePath );
  917. }
  918. else if ( (CHAR)CharUpper((PSTR)*pszInParam) == 'E' )
  919. {
  920. lstrcpy( pszOutParam, szModulePath );
  921. pszOutParam += lstrlen( szModulePath );
  922. }
  923. else if ( *pszInParam == '#' )
  924. pszOutParam = CharNext( pszOutParam );
  925. }
  926. else
  927. pszOutParam = CharNext( pszOutParam );
  928. pszInParam = CharNext(pszInParam);
  929. }
  930. *pszOutParam = '\0';
  931. }