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.

4191 lines
156 KiB

  1. //***************************************************************************
  2. //* Copyright (c) Microsoft Corporation 1995. All rights reserved. *
  3. //***************************************************************************
  4. //* *
  5. //* WEXTRACT.C - Win32 Based Cabinet File Self-extractor and installer. *
  6. //* *
  7. //***************************************************************************
  8. //***************************************************************************
  9. //* INCLUDE FILES *
  10. //***************************************************************************
  11. #include "pch.h"
  12. #pragma hdrstop
  13. #include "wextract.h"
  14. #include "sdsutils.h"
  15. //***************************************************************************
  16. //* GLOBAL VARIABLES *
  17. //***************************************************************************
  18. FAKEFILE g_FileTable[FILETABLESIZE]; // File Table
  19. SESSION g_Sess; // Session
  20. WORD g_wOSVer;
  21. BOOL g_fOSSupportsFullUI = TRUE; // Minimal UI for NT3.5
  22. BOOL g_fOSSupportsINFInstalls = TRUE; // TRUE if INF installs are allowed
  23. // on the target platform.
  24. HANDLE g_hInst;
  25. LPSTR g_szLicense;
  26. HWND g_hwndExtractDlg = NULL;
  27. DWORD g_dwFileSizes[MAX_NUMCLUSTERS+1];
  28. FARPROC g_lpfnOldMEditWndProc;
  29. UINT g_uInfRebootOn;
  30. CMDLINE_DATA g_CMD;
  31. DWORD g_dwRebootCheck;
  32. int g_dwExitCode;
  33. HANDLE g_hCancelEvent = NULL;
  34. HANDLE g_hMutex = NULL;
  35. char g_szBrowsePath[MAX_PATH];
  36. #define CMD_REGSERV "RegServer"
  37. #define COMPRESS_FACTOR 2
  38. #define SIZE_100MB 102400
  39. int _stdcall ModuleEntry(void)
  40. {
  41. int i;
  42. STARTUPINFO si;
  43. LPSTR pszCmdLine = GetCommandLine();
  44. if ( *pszCmdLine == '\"' ) {
  45. /*
  46. * Scan, and skip over, subsequent characters until
  47. * another double-quote or a null is encountered.
  48. */
  49. while ( *++pszCmdLine && (*pszCmdLine != '\"') );
  50. /*
  51. * If we stopped on a double-quote (usual case), skip
  52. * over it.
  53. */
  54. if ( *pszCmdLine == '\"' )
  55. pszCmdLine++;
  56. }
  57. else {
  58. while (*pszCmdLine > ' ')
  59. pszCmdLine++;
  60. }
  61. /*
  62. * Skip past any white space preceeding the second token.
  63. */
  64. while (*pszCmdLine && (*pszCmdLine <= ' ')) {
  65. pszCmdLine++;
  66. }
  67. si.dwFlags = 0;
  68. GetStartupInfoA(&si);
  69. i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
  70. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  71. ExitProcess(i);
  72. return i; // We never comes here.
  73. }
  74. //***************************************************************************
  75. //* *
  76. //* NAME: WinMain *
  77. //* *
  78. //* SYNOPSIS: Main entry point for the program. *
  79. //* *
  80. //* REQUIRES: hInstance: *
  81. //* hPrevInstance: *
  82. //* lpszCmdLine: *
  83. //* nCmdShow: *
  84. //* *
  85. //* RETURNS: int: *
  86. //* *
  87. //***************************************************************************
  88. INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  89. LPTSTR lpszCmdLine, INT nCmdShow )
  90. {
  91. BOOL fReturn = FALSE;
  92. // initailize to SUCCESS return
  93. // this value is updated inside DoMain() ..
  94. //
  95. g_dwExitCode = S_OK;
  96. if ( Init( hInstance, lpszCmdLine, nCmdShow ) )
  97. {
  98. fReturn = DoMain();
  99. CleanUp();
  100. }
  101. if ( fReturn )
  102. {
  103. // get reboot info
  104. if ( !(g_CMD.szRunonceDelDir[0]) && (g_Sess.dwReboot & REBOOT_YES) )
  105. {
  106. MyRestartDialog( g_Sess.dwReboot );
  107. }
  108. }
  109. // BUGBUG: ParseCommandLine() seems to use exit() directly.
  110. // one other exit of this EXE will be at /? case in parsecmdline
  111. // so we do close there if not NULL.
  112. //
  113. if (g_hMutex)
  114. CloseHandle(g_hMutex);
  115. return g_dwExitCode;
  116. }
  117. //***************************************************************************
  118. //* *
  119. //* NAME: Init *
  120. //* *
  121. //* SYNOPSIS: Initialization for the program is done here. *
  122. //* *
  123. //* REQUIRES: hInstance: *
  124. //* hPrevInstance: *
  125. //* lpszCmdLine: *
  126. //* nCmdShow: *
  127. //* *
  128. //* RETURNS: BOOL: *
  129. //* *
  130. //***************************************************************************
  131. BOOL Init( HINSTANCE hInstance, LPCTSTR lpszCmdLine, INT nCmdShow )
  132. {
  133. DWORD dwSize;
  134. PTARGETVERINFO pTargetVer = NULL;
  135. HRSRC hRc;
  136. HGLOBAL hMemVer;
  137. g_hInst = hInstance;
  138. ZeroMemory( &g_Sess, sizeof(g_Sess) );
  139. ZeroMemory( &g_CMD, sizeof(g_CMD) );
  140. ZeroMemory( g_szBrowsePath, sizeof(g_szBrowsePath) );
  141. // Initialize the structure
  142. g_Sess.fAllCabinets = TRUE;
  143. // Get Application Title Name
  144. dwSize = GetResource( achResTitle, g_Sess.achTitle,
  145. sizeof(g_Sess.achTitle) - 1 );
  146. if ( dwSize == 0 || dwSize > sizeof(g_Sess.achTitle) ) {
  147. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  148. return FALSE;
  149. }
  150. g_hCancelEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
  151. SetEvent( g_hCancelEvent );
  152. if ( !GetResource( achResExtractOpt, &(g_Sess.uExtractOpt), sizeof(g_Sess.uExtractOpt) ) )
  153. {
  154. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  155. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  156. return FALSE;
  157. }
  158. if ( ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKPROMPT ) ||
  159. ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKBLOCK ) )
  160. {
  161. char szCookie[MAX_PATH];
  162. if ( !GetResource( achResOneInstCheck, szCookie, sizeof(szCookie) ) )
  163. {
  164. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  165. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  166. return FALSE;
  167. }
  168. g_hMutex = CreateMutex(NULL, TRUE, szCookie );
  169. if ((g_hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
  170. {
  171. if ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKBLOCK )
  172. {
  173. ErrorMsg1Param( NULL, IDS_ERR_ALREADY_RUNNING, g_Sess.achTitle );
  174. }
  175. else if ( MsgBox1Param( NULL, IDS_MULTIINST, g_Sess.achTitle, MB_ICONQUESTION, MB_YESNO) == IDYES )
  176. {
  177. goto CONTINUE;
  178. }
  179. CloseHandle(g_hMutex);
  180. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  181. return FALSE;
  182. }
  183. }
  184. CONTINUE:
  185. g_uInfRebootOn = 0;
  186. if ( !ParseCmdLine(lpszCmdLine) )
  187. {
  188. ErrorMsg( NULL, IDS_ERR_BADCMDLINE );
  189. return FALSE;
  190. }
  191. // if this is runoncde called for cleanup only purpose, clenup and return
  192. if ( g_CMD.szRunonceDelDir[0] )
  193. {
  194. DeleteMyDir( g_CMD.szRunonceDelDir );
  195. return FALSE;
  196. }
  197. hRc = FindResource( hInstance, achResVerCheck, RT_RCDATA );
  198. if ( hRc )
  199. {
  200. hMemVer = LoadResource( hInstance, hRc );
  201. pTargetVer = (PTARGETVERINFO) hMemVer;
  202. }
  203. if ( g_fOSSupportsFullUI )
  204. {
  205. // Allow Use of Progress Bar
  206. InitCommonControls();
  207. }
  208. // if user want to extract files only with /C command switch, no further check is needed!
  209. // If package is built for extract only, checks are needed!
  210. if ( g_CMD.fUserBlankCmd )
  211. {
  212. return TRUE;
  213. }
  214. if ( !CheckOSVersion( pTargetVer ) )
  215. {
  216. return FALSE;
  217. }
  218. // Check for Administrator rights on NT
  219. // Don't do the check if this is quiet mode. This
  220. // will probably change when we add support in cabpack
  221. // to make this check or not
  222. if( ((g_wOSVer == _OSVER_WINNT3X) || (g_wOSVer == _OSVER_WINNT40) || (g_wOSVer == _OSVER_WINNT50)) &&
  223. ( g_Sess.uExtractOpt & EXTRACTOPT_CHKADMRIGHT ) &&
  224. !( g_CMD.wQuietMode & QUIETMODE_ALL ) )
  225. {
  226. if(!IsNTAdmin())
  227. {
  228. if(MyDialogBox(g_hInst, MAKEINTRESOURCE(IDD_WARNING),
  229. NULL, WarningDlgProc, IDS_NOTADMIN, (INT_PTR)IDC_EXIT) != (INT_PTR)IDC_CONTINUE)
  230. return FALSE;
  231. }
  232. }
  233. return TRUE;
  234. }
  235. //***************************************************************************
  236. //* *
  237. //* NAME: DoMain *
  238. //* *
  239. //* SYNOPSIS: This is the main function that processes the package. *
  240. //* *
  241. //* REQUIRES: Nothing *
  242. //* *
  243. //* RETURNS: Nothing *
  244. //* *
  245. //***************************************************************************
  246. BOOL DoMain( VOID )
  247. {
  248. typedef BOOL (WINAPI *DECRYPTFILEAPTR)(LPCSTR, DWORD);
  249. HINSTANCE hAdvapi32;
  250. DECRYPTFILEAPTR DecryptFileAPtr = NULL;
  251. char szPath[MAX_PATH + 1];
  252. // If a prompt is defined, then pop it up in a message box
  253. // Display License file
  254. // if cmdline option: /Q or /Q:1 or /Q:A or /Q:U is used, batch mode is on. No UI needed
  255. if ( !g_CMD.wQuietMode && !g_CMD.fUserBlankCmd )
  256. {
  257. if ( !GetUsersPermission() )
  258. {
  259. return FALSE;
  260. }
  261. }
  262. if ( !g_CMD.wQuietMode )
  263. {
  264. if ( !DisplayLicense() )
  265. {
  266. return FALSE;
  267. }
  268. }
  269. // get package extracting size and install size resource
  270. //
  271. if ( ! GetFileList() ) {
  272. return FALSE;
  273. }
  274. // Set Directory to Extract Into
  275. if ( ! GetTempDirectory() ) {
  276. //ErrorMsg( NULL, IDS_ERR_FIND_TEMP );
  277. return FALSE;
  278. }
  279. //
  280. // Try to turn off encryption on the directory (winseraid #23464.)
  281. //
  282. GetSystemDirectory(szPath, sizeof(szPath));
  283. AddPath(szPath, "advapi32.dll");
  284. hAdvapi32 = LoadLibrary(szPath);
  285. if ( hAdvapi32 ) {
  286. DecryptFileAPtr = (DECRYPTFILEAPTR)GetProcAddress( hAdvapi32, "DecryptFileA" );
  287. if ( DecryptFileAPtr )
  288. DecryptFileAPtr( g_Sess.achDestDir, 0 );
  289. }
  290. FreeLibrary(hAdvapi32);
  291. // check if windows dir has enough space for install,
  292. //
  293. if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly && !CheckWinDir() )
  294. {
  295. return FALSE;
  296. }
  297. // Change to that directory
  298. if ( ! SetCurrentDirectory( g_Sess.achDestDir ) ) {
  299. ErrorMsg( NULL, IDS_ERR_CHANGE_DIR );
  300. g_dwExitCode = MyGetLastError();
  301. return FALSE;
  302. }
  303. // Extract the files
  304. if ( !g_CMD.fNoExtracting )
  305. {
  306. if ( ! ExtractFiles() ) {
  307. return FALSE;
  308. }
  309. }
  310. if ( (g_CMD.dwFlags & CMDL_DELAYREBOOT) ||
  311. (g_CMD.dwFlags & CMDL_DELAYPOSTCMD) )
  312. g_dwRebootCheck = 0;
  313. else
  314. g_dwRebootCheck = NeedRebootInit(g_wOSVer);
  315. // Install using the specified installation command
  316. // if not Command option, check if user op-out run command
  317. if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly )
  318. {
  319. if ( ! RunInstallCommand() ) {
  320. return FALSE;
  321. }
  322. }
  323. // Popup a message that it has finished
  324. if ( !g_CMD.wQuietMode && !g_CMD.fUserBlankCmd )
  325. {
  326. FinishMessage();
  327. }
  328. return TRUE;
  329. }
  330. //***************************************************************************
  331. //* *
  332. //* NAME: CleanUp *
  333. //* *
  334. //* SYNOPSIS: Any last-minute application cleanup activities. *
  335. //* *
  336. //* REQUIRES: Nothing *
  337. //* *
  338. //* RETURNS: Nothing *
  339. //* *
  340. //***************************************************************************
  341. VOID CleanUp( VOID )
  342. {
  343. // Delete extracted files - will do nothing if no files extracted
  344. DeleteExtractedFiles();
  345. }
  346. //***************************************************************************
  347. //* *
  348. //* NAME: MEditSubClassWnd *
  349. //* *
  350. //* SYNOPSIS: Subclasses a multiline edit control so that a edit message *
  351. //* to select the entire contents is ignored. *
  352. //* *
  353. //* REQUIRES: hWnd: Handle of the edit window *
  354. //* fnNewProc: New window handler proc *
  355. //* lpfnOldProc: (returns) Old window handler proc *
  356. //* *
  357. //* RETURNS: Nothing *
  358. //* *
  359. //* NOTE: A selected edit message is not generated when the user *
  360. //* selects text with the keyboard or mouse. *
  361. //* *
  362. //***************************************************************************
  363. VOID NEAR PASCAL MEditSubClassWnd( HWND hWnd, FARPROC fnNewProc )
  364. {
  365. g_lpfnOldMEditWndProc = (FARPROC) GetWindowLongPtr( hWnd, GWLP_WNDPROC );
  366. SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR) MakeProcInstance( fnNewProc,
  367. (HINSTANCE) GetWindowWord( hWnd, GWW_HINSTANCE ) ) );
  368. }
  369. //***************************************************************************
  370. //* *
  371. //* NAME: MEditSubProc *
  372. //* *
  373. //* SYNOPSIS: New multiline edit window procedure to ignore selection of *
  374. //* all contents. *
  375. //* *
  376. //* REQUIRES: hWnd: *
  377. //* msg: *
  378. //* wParam: *
  379. //* lParam: *
  380. //* *
  381. //* RETURNS: LONG: *
  382. //* *
  383. //* NOTE: A selected edit message is not generated when the user *
  384. //* selects text with the keyboard or mouse. *
  385. //* *
  386. //***************************************************************************
  387. LRESULT CALLBACK MEditSubProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  388. {
  389. if ( msg == EM_SETSEL ) {
  390. if ( wParam == 0 && lParam == -2 ) {
  391. return 0;
  392. }
  393. }
  394. return CallWindowProc( (WNDPROC) g_lpfnOldMEditWndProc, hWnd, msg,
  395. wParam, lParam );
  396. }
  397. //***************************************************************************
  398. //* *
  399. //* NAME: LicenseDlgProc *
  400. //* *
  401. //* SYNOPSIS: Dialog Procedure for our license dialog window. *
  402. //* *
  403. //* REQUIRES: hwndDlg: *
  404. //* uMsg: *
  405. //* wParam: *
  406. //* lParam: *
  407. //* *
  408. //* RETURNS: BOOL: *
  409. //* *
  410. //***************************************************************************
  411. INT_PTR CALLBACK LicenseDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
  412. LPARAM lParam )
  413. {
  414. static LRESULT RC;
  415. static BOOL fSetSel = FALSE;
  416. static TCHAR achMessage[MSG_MAX];
  417. switch (uMsg) {
  418. //*********************************************************************
  419. case WM_INITDIALOG:
  420. //*********************************************************************
  421. CenterWindow( hwndDlg, GetDesktopWindow() );
  422. SetDlgItemText( hwndDlg, IDC_EDIT_LICENSE, g_szLicense );
  423. SetWindowText( hwndDlg, g_Sess.achTitle );
  424. SetForegroundWindow( hwndDlg );
  425. // Subclass the multiline edit control.
  426. MEditSubClassWnd( GetDlgItem( hwndDlg, IDC_EDIT_LICENSE ),
  427. (FARPROC) MEditSubProc );
  428. return TRUE;
  429. //*********************************************************************
  430. case WM_PAINT:
  431. //*********************************************************************
  432. // For some reason, the EM_SETSEL message doesn't work when sent
  433. // from within WM_INITDIALOG. That's why this hack of using a
  434. // flag and putting it in the WM_PAINT is used.
  435. if ( ! fSetSel ) {
  436. RC = SendDlgItemMessage( hwndDlg, IDC_EDIT_LICENSE, EM_SETSEL,
  437. (WPARAM) -1, (LPARAM) 0 );
  438. fSetSel = TRUE;
  439. }
  440. return FALSE;
  441. //*********************************************************************
  442. case WM_CLOSE:
  443. //*********************************************************************
  444. EndDialog( hwndDlg, FALSE );
  445. return TRUE;
  446. //*********************************************************************
  447. case WM_COMMAND:
  448. //*********************************************************************
  449. if (wParam == IDYES) {
  450. EndDialog( hwndDlg, TRUE );
  451. } else if (wParam == IDNO) {
  452. EndDialog( hwndDlg, FALSE );
  453. }
  454. return TRUE;
  455. }
  456. return FALSE;
  457. }
  458. //***************************************************************************
  459. //* *
  460. //* NAME: IsFullPath *
  461. //* *
  462. //* SYNOPSIS: *
  463. //* *
  464. //* REQUIRES: *
  465. //* *
  466. //* RETURNS: *
  467. //* *
  468. //***************************************************************************
  469. // return TRUE if given path is FULL pathname
  470. //
  471. BOOL IsFullPath( LPSTR pszPath )
  472. {
  473. if ( (pszPath == NULL) || (lstrlen(pszPath) < 3) )
  474. {
  475. return FALSE;
  476. }
  477. if ( (pszPath[1] == ':') || ((pszPath[0] == '\\') && (pszPath[1]=='\\') ) )
  478. return TRUE;
  479. else
  480. return FALSE;
  481. }
  482. //***************************************************************************
  483. //* *
  484. //* NAME: TempDirDlgProc *
  485. //* *
  486. //* SYNOPSIS: Dialog Procedure for our temporary dir dialog window. *
  487. //* *
  488. //* REQUIRES: hwndDlg: *
  489. //* uMsg: *
  490. //* wParam: *
  491. //* lParam: *
  492. //* *
  493. //* RETURNS: BOOL: *
  494. //* *
  495. //***************************************************************************
  496. INT_PTR CALLBACK TempDirDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
  497. LPARAM lParam )
  498. {
  499. static TCHAR achDir[MAX_PATH];
  500. static TCHAR achMsg[MSG_MAX];
  501. switch (uMsg) {
  502. //*********************************************************************
  503. case WM_INITDIALOG:
  504. //*********************************************************************
  505. {
  506. CenterWindow( hwndDlg, GetDesktopWindow() );
  507. SetWindowText( hwndDlg, g_Sess.achTitle );
  508. SendDlgItemMessage( hwndDlg, IDC_EDIT_TEMPDIR, EM_SETLIMITTEXT, (sizeof(g_Sess.achDestDir)-1), 0 );
  509. // if ( ( g_wOSVer == _OSVER_WINNT3X ) || ( g_wOSVer == _OSVER_WINNT40 ))
  510. if ( ( g_wOSVer == _OSVER_WINNT3X ) )
  511. {
  512. EnableWindow( GetDlgItem( hwndDlg, IDC_BUT_BROWSE ), FALSE );
  513. }
  514. return TRUE;
  515. }
  516. //*********************************************************************
  517. case WM_CLOSE:
  518. //*********************************************************************
  519. EndDialog( hwndDlg, FALSE );
  520. return TRUE;
  521. //*********************************************************************
  522. case WM_COMMAND:
  523. //*********************************************************************
  524. switch ( wParam ) {
  525. //*************************************************************
  526. case IDOK:
  527. //*************************************************************
  528. {
  529. DWORD dwAttribs = 0;
  530. UINT chkType;
  531. if ( !GetDlgItemText( hwndDlg, IDC_EDIT_TEMPDIR, g_Sess.achDestDir,
  532. sizeof(g_Sess.achDestDir)) || !IsFullPath(g_Sess.achDestDir) )
  533. {
  534. ErrorMsg( hwndDlg, IDS_ERR_EMPTY_DIR_FIELD );
  535. return TRUE;
  536. }
  537. dwAttribs = GetFileAttributes( g_Sess.achDestDir );
  538. if ( dwAttribs == 0xFFFFFFFF )
  539. {
  540. if ( MsgBox1Param( hwndDlg, IDS_CREATE_DIR, g_Sess.achDestDir, MB_ICONQUESTION, MB_YESNO )
  541. == IDYES )
  542. {
  543. if ( ! CreateDirectory( g_Sess.achDestDir, NULL ) )
  544. {
  545. ErrorMsg1Param( hwndDlg, IDS_ERR_CREATE_DIR, g_Sess.achDestDir );
  546. return TRUE;
  547. }
  548. }
  549. else
  550. return TRUE;
  551. }
  552. AddPath( g_Sess.achDestDir, "" );
  553. if ( ! IsGoodTempDir( g_Sess.achDestDir ) ) {
  554. ErrorMsg( hwndDlg, IDS_ERR_INVALID_DIR );
  555. return TRUE;
  556. }
  557. if ( (g_Sess.achDestDir[0] == '\\') && (g_Sess.achDestDir[1] == '\\') )
  558. chkType = CHK_REQDSK_NONE;
  559. else
  560. chkType = CHK_REQDSK_EXTRACT;
  561. if ( ! IsEnoughSpace( g_Sess.achDestDir, chkType, MSG_REQDSK_ERROR ) ) {
  562. return TRUE;
  563. }
  564. EndDialog( hwndDlg, TRUE );
  565. return TRUE;
  566. }
  567. //*************************************************************
  568. case IDCANCEL:
  569. //*************************************************************
  570. EndDialog( hwndDlg, FALSE );
  571. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  572. return TRUE;
  573. //*************************************************************
  574. case IDC_BUT_BROWSE:
  575. //*************************************************************
  576. if ( LoadString( g_hInst, IDS_SELECTDIR, achMsg,
  577. sizeof(achMsg) ) == 0 )
  578. {
  579. ErrorMsg( hwndDlg, IDS_ERR_NO_RESOURCE );
  580. EndDialog( hwndDlg, FALSE );
  581. return TRUE;
  582. }
  583. if ( ! BrowseForDir( hwndDlg, achMsg, achDir ) ) {
  584. return TRUE;
  585. }
  586. if ( ! SetDlgItemText( hwndDlg, IDC_EDIT_TEMPDIR, achDir ) )
  587. {
  588. ErrorMsg( hwndDlg, IDS_ERR_UPDATE_DIR );
  589. EndDialog( hwndDlg, FALSE );
  590. return TRUE;
  591. }
  592. return TRUE;
  593. }
  594. return TRUE;
  595. }
  596. return FALSE;
  597. }
  598. //***************************************************************************
  599. //* *
  600. //* NAME: OverwriteDlgProc *
  601. //* *
  602. //* SYNOPSIS: Dialog Procedure for asking if file should be overwritten. *
  603. //* *
  604. //* REQUIRES: hwndDlg: *
  605. //* uMsg: *
  606. //* wParam: *
  607. //* lParam: *
  608. //* *
  609. //* RETURNS: BOOL: *
  610. //* *
  611. //***************************************************************************
  612. INT_PTR CALLBACK OverwriteDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
  613. LPARAM lParam )
  614. {
  615. switch (uMsg) {
  616. //*********************************************************************
  617. case WM_INITDIALOG:
  618. //*********************************************************************
  619. CenterWindow( hwndDlg, GetDesktopWindow() );
  620. SetWindowText( hwndDlg, g_Sess.achTitle );
  621. SetDlgItemText( hwndDlg, IDC_TEXT_FILENAME,g_Sess.cszOverwriteFile );
  622. SetForegroundWindow( hwndDlg );
  623. return TRUE;
  624. //*********************************************************************
  625. case WM_CLOSE:
  626. //*********************************************************************
  627. EndDialog( hwndDlg, IDCANCEL );
  628. return TRUE;
  629. //*********************************************************************
  630. case WM_COMMAND:
  631. //*********************************************************************
  632. switch ( wParam ) {
  633. //*************************************************************
  634. case IDC_BUT_YESTOALL:
  635. //*************************************************************
  636. g_Sess.fOverwrite = TRUE;
  637. //*************************************************************
  638. case IDYES:
  639. case IDNO:
  640. //*************************************************************
  641. EndDialog( hwndDlg, wParam );
  642. return TRUE;
  643. }
  644. return TRUE;
  645. }
  646. return FALSE;
  647. }
  648. //***************************************************************************
  649. //* *
  650. //* NAME: ExtractDlgProc *
  651. //* *
  652. //* SYNOPSIS: Dialog Procedure for our main dialog window. *
  653. //* *
  654. //* REQUIRES: hwndDlg: *
  655. //* uMsg: *
  656. //* wParam: *
  657. //* lParam: *
  658. //* *
  659. //* RETURNS: BOOL: *
  660. //* *
  661. //***************************************************************************
  662. INT_PTR CALLBACK ExtractDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
  663. LPARAM lParam )
  664. {
  665. static DWORD dwThreadID;
  666. static HANDLE hExtractThread;
  667. static TCHAR achMessage[MSG_MAX];
  668. switch (uMsg) {
  669. //*********************************************************************
  670. case WM_INITDIALOG:
  671. //*********************************************************************
  672. g_hwndExtractDlg = hwndDlg;
  673. CenterWindow( hwndDlg, GetDesktopWindow() );
  674. if ( g_fOSSupportsFullUI ) {
  675. Animate_Open( GetDlgItem( hwndDlg, IDC_USER1 ), IDA_FILECOPY );
  676. Animate_Play( GetDlgItem( hwndDlg, IDC_USER1 ), 0, -1, -1 );
  677. }
  678. SetWindowText( hwndDlg, g_Sess.achTitle );
  679. // Launch Extraction Thread
  680. hExtractThread = CreateThread( NULL, 0,
  681. (LPTHREAD_START_ROUTINE) ExtractThread,
  682. NULL, 0, &dwThreadID );
  683. if ( !hExtractThread ) {
  684. ErrorMsg( hwndDlg, IDS_ERR_CREATE_THREAD );
  685. EndDialog( hwndDlg, FALSE );
  686. }
  687. return TRUE;
  688. //*********************************************************************
  689. case UM_EXTRACTDONE:
  690. //*********************************************************************
  691. TerminateThread( hExtractThread, 0 );
  692. EndDialog( hwndDlg, (BOOL) wParam );
  693. return TRUE;
  694. //*********************************************************************
  695. case WM_CLOSE:
  696. //*********************************************************************
  697. g_Sess.fCanceled = TRUE;
  698. EndDialog( hwndDlg, FALSE );
  699. return TRUE;
  700. //*********************************************************************
  701. case WM_CHAR:
  702. //*********************************************************************
  703. if ( wParam == VK_ESCAPE ) {
  704. g_Sess.fCanceled = TRUE;
  705. EndDialog( hwndDlg, FALSE );
  706. }
  707. return TRUE;
  708. //*********************************************************************
  709. case WM_COMMAND:
  710. //*********************************************************************
  711. if ( wParam == IDCANCEL ) {
  712. int iMsgRet ;
  713. ResetEvent( g_hCancelEvent );
  714. iMsgRet = MsgBox1Param( g_hwndExtractDlg, IDS_ERR_USER_CANCEL, "",
  715. MB_ICONQUESTION, MB_YESNO ) ;
  716. // We will get back IDOK if we are in /q:1 mode.
  717. //
  718. if ( (iMsgRet == IDYES) || (iMsgRet == IDOK) )
  719. {
  720. g_Sess.fCanceled = TRUE;
  721. SetEvent( g_hCancelEvent );
  722. WaitForObject( hExtractThread );
  723. EndDialog( hwndDlg, FALSE );
  724. return TRUE;
  725. }
  726. SetEvent( g_hCancelEvent );
  727. }
  728. return TRUE;
  729. }
  730. return FALSE;
  731. }
  732. //***************************************************************************
  733. //* *
  734. //* NAME: WaitForObject *
  735. //* *
  736. //* SYNOPSIS: Waits for an object while still dispatching messages. *
  737. //* *
  738. //* REQUIRES: Handle to the object. *
  739. //* *
  740. //* RETURNS: Nothing *
  741. //* *
  742. //***************************************************************************
  743. VOID WaitForObject( HANDLE hObject )
  744. {
  745. BOOL fDone = FALSE;
  746. DWORD dwRet = 0;
  747. while ( ! fDone ) {
  748. dwRet = MsgWaitForMultipleObjects( 1, &hObject, FALSE, INFINITE, QS_ALLINPUT );
  749. if ( dwRet == WAIT_OBJECT_0 ) {
  750. fDone = TRUE;
  751. }
  752. else
  753. {
  754. MSG msg;
  755. // read all of the messages in this next loop
  756. // removing each message as we read it
  757. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
  758. // if it's a quit message we're out of here
  759. if ( msg.message == WM_QUIT ) {
  760. fDone = TRUE;
  761. } else {
  762. // otherwise dispatch it
  763. DispatchMessage( &msg );
  764. } // end of PeekMessage while loop
  765. }
  766. }
  767. }
  768. }
  769. //***************************************************************************
  770. //* *
  771. //* NAME: CheckOSVersion *
  772. //* *
  773. //* SYNOPSIS: Checks the OS version and sets some global variables. *
  774. //* *
  775. //* REQUIRES: Nothing *
  776. //* *
  777. //* RETURNS: Nothing *
  778. //* *
  779. //***************************************************************************
  780. BOOL CheckOSVersion( PTARGETVERINFO ptargetVers )
  781. {
  782. OSVERSIONINFO verinfo; // Version Check
  783. UINT uErrid = 0;
  784. PVERCHECK pVerCheck;
  785. WORD CurrBld;
  786. int ifrAnswer[2], itoAnswer[2], i;
  787. char szPath[MAX_PATH];
  788. // Operating System Version Check: For NT versions below 3.50 set flag to
  789. // prevent use of common controls (progress bar and AVI) not available.
  790. verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  791. if ( GetVersionEx( &verinfo ) == FALSE )
  792. {
  793. uErrid = IDS_ERR_OS_VERSION;
  794. goto EXIT;
  795. }
  796. switch( verinfo.dwPlatformId )
  797. {
  798. case VER_PLATFORM_WIN32_WINDOWS: // Win95
  799. // Accept for INF installs and Accept for animations
  800. g_wOSVer = _OSVER_WIN9X;
  801. g_fOSSupportsFullUI = TRUE;
  802. g_fOSSupportsINFInstalls = TRUE;
  803. break;
  804. case VER_PLATFORM_WIN32_NT: // Win NT
  805. g_fOSSupportsFullUI = TRUE;
  806. g_fOSSupportsINFInstalls = TRUE;
  807. g_wOSVer = _OSVER_WINNT40;
  808. if ( verinfo.dwMajorVersion <= 3 )
  809. {
  810. g_wOSVer = _OSVER_WINNT3X;
  811. if ( (verinfo.dwMajorVersion < 3) ||
  812. ((verinfo.dwMajorVersion == 3) && (verinfo.dwMinorVersion < 51 )) )
  813. {
  814. // Reject for INF installs and Reject for animations
  815. g_fOSSupportsFullUI = FALSE;
  816. g_fOSSupportsINFInstalls = FALSE;
  817. }
  818. }
  819. else if ( verinfo.dwMajorVersion >= 5 )
  820. g_wOSVer = _OSVER_WINNT50;
  821. break;
  822. default:
  823. uErrid = IDS_ERR_OS_UNSUPPORTED;
  824. goto EXIT;
  825. }
  826. // check if the current OS/File versions
  827. //
  828. if ( !g_CMD.fNoVersionCheck && ptargetVers )
  829. {
  830. if ( g_wOSVer == _OSVER_WIN9X )
  831. pVerCheck = &(ptargetVers->win9xVerCheck);
  832. else
  833. pVerCheck = &(ptargetVers->ntVerCheck);
  834. CurrBld = LOWORD( verinfo.dwBuildNumber );
  835. for ( i=0; i<2; i++ )
  836. {
  837. ifrAnswer[i] = CompareVersion( verinfo.dwMajorVersion, verinfo.dwMinorVersion,
  838. pVerCheck->vr[i].frVer.dwMV, pVerCheck->vr[i].frVer.dwLV );
  839. itoAnswer[i] = CompareVersion( verinfo.dwMajorVersion, verinfo.dwMinorVersion,
  840. pVerCheck->vr[i].toVer.dwMV, pVerCheck->vr[i].toVer.dwLV );
  841. if ( ifrAnswer[i] >= 0 && itoAnswer[i] <=0 )
  842. {
  843. if ( (ifrAnswer[i] == 0) && (itoAnswer[i] == 0) )
  844. {
  845. if ( CurrBld < pVerCheck->vr[i].frVer.dwBd || CurrBld > pVerCheck->vr[i].toVer.dwBd )
  846. goto RE_TRY;
  847. }
  848. else if ( ifrAnswer[i] == 0 )
  849. {
  850. if ( CurrBld < pVerCheck->vr[i].frVer.dwBd )
  851. goto RE_TRY;
  852. }
  853. else if ( itoAnswer[i] == 0 )
  854. {
  855. if ( CurrBld > pVerCheck->vr[i].toVer.dwBd )
  856. goto RE_TRY;
  857. }
  858. // if you are here, meaning you are fine with this Version range, no more check is needed
  859. break;
  860. RE_TRY:
  861. if ( i == 0 )
  862. continue;
  863. uErrid = IDS_ERR_TARGETOS;
  864. break;
  865. }
  866. else if ( i == 1 ) // not in any of the ranges
  867. {
  868. uErrid = IDS_ERR_TARGETOS;
  869. break;
  870. }
  871. }
  872. // if passed OS check, go on file check
  873. if ( uErrid == 0 )
  874. {
  875. if ( ptargetVers->dwNumFiles && !CheckFileVersion( ptargetVers, szPath, sizeof(szPath), &i ) )
  876. uErrid = IDS_ERR_FILEVER;
  877. }
  878. }
  879. EXIT:
  880. if ( (uErrid == IDS_ERR_FILEVER) || (uErrid == IDS_ERR_TARGETOS) )
  881. {
  882. LPSTR pParam2 = NULL, pMsg;
  883. UINT uButton, id;
  884. if ( uErrid == IDS_ERR_FILEVER )
  885. {
  886. pVerCheck = (PVERCHECK) (ptargetVers->szBuf + ptargetVers->dwFileOffs + i*sizeof(VERCHECK) );
  887. pParam2 = szPath;
  888. }
  889. pMsg = ptargetVers->szBuf + pVerCheck->dwstrOffs;
  890. uButton = GetMsgboxFlag( pVerCheck->dwFlag );
  891. if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) && *pMsg )
  892. {
  893. MessageBeep( MB_OK );
  894. id = MessageBox( NULL, pMsg, g_Sess.achTitle, MB_ICONEXCLAMATION | uButton |
  895. ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0));
  896. if ( uButton & MB_YESNO )
  897. {
  898. if ( id == IDYES )
  899. uErrid = 0;
  900. }
  901. else if (uButton & MB_OKCANCEL )
  902. {
  903. if ( id == IDOK )
  904. uErrid = 0;
  905. }
  906. }
  907. else
  908. {
  909. MsgBox2Param( NULL, uErrid, g_Sess.achTitle, pParam2, MB_ICONEXCLAMATION, MB_OK);
  910. }
  911. }
  912. else if ( uErrid )
  913. ErrorMsg( NULL, uErrid );
  914. return ( uErrid? FALSE : TRUE );
  915. }
  916. //***************************************************************************
  917. //* *
  918. //* NAME: DisplayLicense *
  919. //* *
  920. //* SYNOPSIS: Displays a license file and asks if user accepts it. *
  921. //* *
  922. //* REQUIRES: Nothing *
  923. //* *
  924. //* RETURNS: BOOL: TRUE if user accepts, FALSE if an error *
  925. //* occurs or user rejects. *
  926. //* *
  927. //***************************************************************************
  928. BOOL DisplayLicense( VOID )
  929. {
  930. DWORD dwSize;
  931. INT_PTR iDlgRC;
  932. dwSize = GetResource( achResLicense, NULL, 0 );
  933. g_szLicense = (LPSTR) LocalAlloc( LPTR, dwSize + 1 );
  934. if ( ! g_szLicense ) {
  935. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  936. g_dwExitCode = MyGetLastError();
  937. return FALSE;
  938. }
  939. if ( ! GetResource( achResLicense, g_szLicense, dwSize ) ) {
  940. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  941. LocalFree( g_szLicense );
  942. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  943. return FALSE;
  944. }
  945. if ( lstrcmp( g_szLicense, achResNone ) != 0 ) {
  946. iDlgRC = MyDialogBox( g_hInst,
  947. MAKEINTRESOURCE(IDD_LICENSE),
  948. NULL, LicenseDlgProc, (LPARAM)0, 0 );
  949. LocalFree( g_szLicense );
  950. if ( iDlgRC == 0 ) {
  951. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  952. return FALSE;
  953. }
  954. } else {
  955. LocalFree( g_szLicense );
  956. }
  957. g_dwExitCode = S_OK;
  958. return TRUE;
  959. }
  960. //***************************************************************************
  961. //* *
  962. //* NAME: ExtractFiles *
  963. //* *
  964. //* SYNOPSIS: Starts extraction of the files. *
  965. //* *
  966. //* REQUIRES: Nothing *
  967. //* *
  968. //* RETURNS: BOOL: TRUE if extraction OK, FALSE on error *
  969. //* *
  970. //***************************************************************************
  971. BOOL ExtractFiles( VOID )
  972. {
  973. UINT wIndex;
  974. INT_PTR iDlgRC;
  975. BOOL extCodeThread = 0;
  976. // FDI does all its file I/O as callbacks up to functions provided by
  977. // this program. Each file is identified by a "handle" similar to a
  978. // file handle. In order to support the file that is actually a
  979. // resource in memory we implement our own file table. The offsets
  980. // into this table are the handles that FDI uses. The table itself
  981. // stores either a real file handle in the case of disk files or
  982. // information (pointer to memory block, current offset) for a memory
  983. // file. The following initializes the table.
  984. for ( wIndex = 0; wIndex < FILETABLESIZE; wIndex++ ) {
  985. g_FileTable[wIndex].avail = TRUE;
  986. }
  987. if ( (g_CMD.wQuietMode & QUIETMODE_ALL) || (g_Sess.uExtractOpt & EXTRACTOPT_UI_NO) )
  988. {
  989. extCodeThread = ExtractThread();
  990. if ( extCodeThread == 0 )
  991. {
  992. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
  993. return FALSE;
  994. }
  995. }
  996. else
  997. {
  998. iDlgRC = MyDialogBox( g_hInst, ( g_fOSSupportsFullUI ) ?
  999. MAKEINTRESOURCE(IDD_EXTRACT) :
  1000. MAKEINTRESOURCE(IDD_EXTRACT_MIN),
  1001. NULL, ExtractDlgProc,
  1002. (LPARAM)0, 0 );
  1003. if ( iDlgRC == 0 )
  1004. {
  1005. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
  1006. return FALSE;
  1007. }
  1008. }
  1009. // Extract EXTRA files tagged on with updfile.exe
  1010. if ( ! TravelUpdatedFiles( ProcessUpdatedFile_Write ) ) {
  1011. // g_dwExitCode is set in TravelUpdatedFiles()
  1012. return FALSE;
  1013. }
  1014. g_dwExitCode = S_OK;
  1015. return TRUE;
  1016. }
  1017. //***************************************************************************
  1018. //* *
  1019. //* NAME: RunInstallCommand *
  1020. //* *
  1021. //* SYNOPSIS: Executes the installation command or INF file. *
  1022. //* *
  1023. //* REQUIRES: Nothing *
  1024. //* *
  1025. //* RETURNS: BOOL: TRUE if installation OK, FALSE on error *
  1026. //* *
  1027. //***************************************************************************
  1028. BOOL RunInstallCommand( VOID )
  1029. {
  1030. //DWORD dwExitCode; // Return Status from Setup Process
  1031. UINT bShowWindow;
  1032. LPTSTR szCommand;
  1033. TCHAR szResCommand[MAX_PATH];
  1034. DWORD dwSize;
  1035. STARTUPINFO sti;
  1036. BOOL fInfCmd = FALSE;
  1037. DOINFINSTALL pfDoInfInstall = NULL;
  1038. HANDLE hSetupLibrary;
  1039. ADVPACKARGS AdvPackArgs;
  1040. UINT i = 0;
  1041. BOOL bFoundQCmd = FALSE, bRunOnceAdded = FALSE;
  1042. g_dwExitCode = S_OK;
  1043. // get reboot info
  1044. if ( !g_CMD.fUserReboot )
  1045. {
  1046. // no command line, get from resource
  1047. dwSize = GetResource( achResReboot, &g_Sess.dwReboot,sizeof(g_Sess.dwReboot) );
  1048. if ( dwSize == 0 || dwSize > sizeof(g_Sess.dwReboot) )
  1049. {
  1050. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1051. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  1052. return FALSE;
  1053. }
  1054. }
  1055. for ( i = 0; i < 2; i += 1 )
  1056. {
  1057. fInfCmd = FALSE; // Default to FALSE;
  1058. memset( &sti, 0, sizeof(sti) );
  1059. sti.cb = sizeof(STARTUPINFO);
  1060. if ( !g_CMD.szUserCmd[0] )
  1061. {
  1062. dwSize = GetResource( achResShowWindow, &bShowWindow,
  1063. sizeof(bShowWindow) );
  1064. if ( dwSize == 0 || dwSize > sizeof(bShowWindow) ) {
  1065. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1066. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  1067. return FALSE;
  1068. }
  1069. if ( bShowWindow == bResShowHidden ) {
  1070. sti.dwFlags = STARTF_USESHOWWINDOW;
  1071. sti.wShowWindow = SW_HIDE;
  1072. } else if ( bShowWindow == bResShowMin ) {
  1073. sti.dwFlags = STARTF_USESHOWWINDOW;
  1074. sti.wShowWindow = SW_MINIMIZE;
  1075. } else if ( bShowWindow == bResShowMax ) {
  1076. sti.dwFlags = STARTF_USESHOWWINDOW;
  1077. sti.wShowWindow = SW_MAXIMIZE;
  1078. }
  1079. if ( i == 0 )
  1080. {
  1081. // if user specify the quiet mode command, use it. Otherwise, assume
  1082. // quiet mode or not, they run the same command.
  1083. //
  1084. if ( g_CMD.wQuietMode )
  1085. {
  1086. LPCSTR pResName;
  1087. if ( g_CMD.wQuietMode & QUIETMODE_ALL )
  1088. pResName = achResAdminQCmd;
  1089. else if ( g_CMD.wQuietMode & QUIETMODE_USER )
  1090. pResName = achResUserQCmd;
  1091. if ( !GetResource( pResName, szResCommand, sizeof(szResCommand) ) )
  1092. {
  1093. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1094. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  1095. return FALSE;
  1096. }
  1097. if ( lstrcmpi(szResCommand, achResNone) )
  1098. {
  1099. bFoundQCmd = TRUE;
  1100. }
  1101. }
  1102. if ( !bFoundQCmd && !GetResource( achResRunProgram, szResCommand, sizeof(szResCommand) ) )
  1103. {
  1104. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1105. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  1106. return FALSE;
  1107. }
  1108. }
  1109. }
  1110. else
  1111. {
  1112. lstrcpy( szResCommand, g_CMD.szUserCmd );
  1113. }
  1114. if ( i == 1 )
  1115. {
  1116. // if there is PostInstallCommand to be run
  1117. if ( ! GetResource( achResPostRunCmd, szResCommand, sizeof(szResCommand) ) ) {
  1118. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1119. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  1120. return FALSE;
  1121. }
  1122. if ( g_CMD.szUserCmd[0] || !lstrcmpi( szResCommand, achResNone ) )
  1123. {
  1124. break;
  1125. }
  1126. }
  1127. if ( !AnalyzeCmd( szResCommand, &szCommand, &fInfCmd ) )
  1128. {
  1129. return FALSE;
  1130. }
  1131. // before we run the app, add runonce entry, if it return, we delete this entry
  1132. if ( !bRunOnceAdded && (g_wOSVer != _OSVER_WINNT3X) && g_CMD.fCreateTemp && !fInfCmd ) {
  1133. bRunOnceAdded = TRUE;
  1134. AddRegRunOnce();
  1135. }
  1136. if ( fInfCmd && ! g_fOSSupportsINFInstalls ) {
  1137. ErrorMsg( NULL, IDS_ERR_NO_INF_INSTALLS );
  1138. LocalFree( szCommand );
  1139. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
  1140. return FALSE;
  1141. }
  1142. if ( fInfCmd && g_Sess.uExtractOpt & EXTRACTOPT_ADVDLL )
  1143. {
  1144. hSetupLibrary = MyLoadLibrary( ADVPACKDLL );
  1145. if ( hSetupLibrary == NULL ) {
  1146. ErrorMsg1Param( NULL, IDS_ERR_LOAD_DLL, ADVPACKDLL );
  1147. LocalFree( szCommand );
  1148. g_dwExitCode = MyGetLastError();
  1149. return FALSE;
  1150. }
  1151. pfDoInfInstall = (DOINFINSTALL) GetProcAddress( hSetupLibrary, szDOINFINSTALL );
  1152. if ( pfDoInfInstall == NULL ) {
  1153. ErrorMsg1Param( NULL, IDS_ERR_GET_PROC_ADDR, szDOINFINSTALL );
  1154. FreeLibrary( hSetupLibrary );
  1155. LocalFree( szCommand );
  1156. g_dwExitCode = MyGetLastError();
  1157. return FALSE;
  1158. }
  1159. AdvPackArgs.hWnd = NULL;
  1160. AdvPackArgs.lpszTitle = g_Sess.achTitle;
  1161. AdvPackArgs.lpszInfFilename = szCommand;
  1162. AdvPackArgs.lpszSourceDir = g_Sess.achDestDir;
  1163. AdvPackArgs.lpszInstallSection = szResCommand;
  1164. AdvPackArgs.wOSVer = g_wOSVer;
  1165. AdvPackArgs.dwFlags = g_CMD.wQuietMode;
  1166. if ( g_CMD.fNoGrpConv )
  1167. {
  1168. AdvPackArgs.dwFlags |= ADVFLAGS_NGCONV;
  1169. }
  1170. if ( g_Sess.uExtractOpt & EXTRACTOPT_COMPRESSED )
  1171. {
  1172. AdvPackArgs.dwFlags |= ADVFLAGS_COMPRESSED;
  1173. }
  1174. if ( g_Sess.uExtractOpt & EXTRACTOPT_UPDHLPDLLS )
  1175. {
  1176. AdvPackArgs.dwFlags |= ADVFLAGS_UPDHLPDLLS;
  1177. }
  1178. if ( g_CMD.dwFlags & CMDL_DELAYREBOOT )
  1179. {
  1180. AdvPackArgs.dwFlags |= ADVFLAGS_DELAYREBOOT;
  1181. }
  1182. if ( g_CMD.dwFlags & CMDL_DELAYPOSTCMD )
  1183. {
  1184. AdvPackArgs.dwFlags |= ADVFLAGS_DELAYPOSTCMD;
  1185. }
  1186. AdvPackArgs.dwPackInstSize = g_Sess.cbPackInstSize;
  1187. if ( FAILED(g_dwExitCode = pfDoInfInstall(&AdvPackArgs)) ) {
  1188. FreeLibrary( hSetupLibrary );
  1189. LocalFree( szCommand );
  1190. return FALSE;
  1191. }
  1192. FreeLibrary( hSetupLibrary );
  1193. }
  1194. else
  1195. {
  1196. if ( !RunApps( szCommand, &sti ) )
  1197. {
  1198. LocalFree( szCommand );
  1199. return FALSE;
  1200. }
  1201. }
  1202. LocalFree( szCommand );
  1203. } // end for
  1204. // convert the RunOnce entry added by AddRegRunOnce to use ADVPACK instead
  1205. // of wextract if g_bConvertRunOnce is TRUE
  1206. if (g_bConvertRunOnce)
  1207. ConvertRegRunOnce();
  1208. return TRUE;
  1209. }
  1210. //***************************************************************************
  1211. //* *
  1212. //* NAME: RunApps *
  1213. //* *
  1214. //* SYNOPSIS: *
  1215. //* *
  1216. //* REQUIRES: *
  1217. //* *
  1218. //* RETURNS: *
  1219. //* *
  1220. //***************************************************************************
  1221. BOOL RunApps( LPSTR lpCommand, STARTUPINFO *lpsti )
  1222. {
  1223. DWORD dwExitCode;
  1224. PROCESS_INFORMATION pi; // Setup Process Launch
  1225. BOOL bRet = TRUE;
  1226. TCHAR achMessage[MAX_STRING];
  1227. if ( !lpCommand )
  1228. {
  1229. return FALSE;
  1230. }
  1231. memset( &pi, 0, sizeof(pi) );
  1232. if ( CreateProcess( NULL, lpCommand, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, lpsti, &pi ) )
  1233. {
  1234. WaitForSingleObject( pi.hProcess, INFINITE );
  1235. GetExitCodeProcess( pi.hProcess, &dwExitCode );
  1236. // check if this return code is cabpack aware
  1237. // if so, use it as reboot code
  1238. if ( !g_CMD.fUserReboot && (g_Sess.dwReboot & REBOOT_YES) &&
  1239. !(g_Sess.dwReboot & REBOOT_ALWAYS) && ((dwExitCode & 0xFF000000) == RC_WEXTRACT_AWARE) )
  1240. {
  1241. g_Sess.dwReboot = dwExitCode;
  1242. }
  1243. // store app return code to system standard return code if necessary
  1244. // g_dwExitCode is set in this function, make sure it is not re-set afterward
  1245. //
  1246. savAppExitCode( dwExitCode );
  1247. CloseHandle( pi.hThread );
  1248. CloseHandle( pi.hProcess );
  1249. if ( g_Sess.uExtractOpt & EXTRACTOPT_CMDSDEPENDED )
  1250. {
  1251. if ( FAILED( dwExitCode ) )
  1252. bRet = FALSE;
  1253. }
  1254. }
  1255. else
  1256. {
  1257. g_dwExitCode = MyGetLastError();
  1258. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  1259. achMessage, sizeof(achMessage), NULL );
  1260. ErrorMsg2Param( NULL, IDS_ERR_CREATE_PROCESS, lpCommand, achMessage );
  1261. bRet = FALSE;
  1262. }
  1263. return bRet;
  1264. }
  1265. // convert app return code to sys return code
  1266. //
  1267. void savAppExitCode( DWORD dwAppRet )
  1268. {
  1269. if ( g_Sess.uExtractOpt & EXTRACTOPT_PASSINSTRETALWAYS )
  1270. {
  1271. g_dwExitCode = dwAppRet;
  1272. }
  1273. else
  1274. {
  1275. // called from AdvINFInstall
  1276. if ( (CheckReboot() == EWX_REBOOT) ||
  1277. ( ((dwAppRet & 0xFF000000) == RC_WEXTRACT_AWARE) && (dwAppRet & REBOOT_YES)) )
  1278. {
  1279. g_dwExitCode = ERROR_SUCCESS_REBOOT_REQUIRED;
  1280. }
  1281. else if ( g_Sess.uExtractOpt & EXTRACTOPT_PASSINSTRET )
  1282. {
  1283. // if author specified, relay back whatever EXE returns
  1284. //
  1285. g_dwExitCode = dwAppRet;
  1286. }
  1287. }
  1288. }
  1289. //***************************************************************************
  1290. //* *
  1291. //* NAME: FinishMessage *
  1292. //* *
  1293. //* SYNOPSIS: Displays the final message to the user when everything *
  1294. //* was successfull. *
  1295. //* *
  1296. //* REQUIRES: Nothing *
  1297. //* *
  1298. //* RETURNS: Nothing *
  1299. //* *
  1300. //***************************************************************************
  1301. VOID FinishMessage( VOID )
  1302. {
  1303. LPSTR szFinishMsg;
  1304. DWORD dwSize;
  1305. dwSize = GetResource( achResFinishMsg, NULL, 0 );
  1306. szFinishMsg = (LPSTR) LocalAlloc( LPTR, dwSize + 1 );
  1307. if ( ! szFinishMsg ) {
  1308. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  1309. return;
  1310. }
  1311. if ( ! GetResource( achResFinishMsg, szFinishMsg, dwSize ) )
  1312. {
  1313. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  1314. LocalFree( szFinishMsg );
  1315. return;
  1316. }
  1317. if ( lstrcmp( szFinishMsg, achResNone ) != 0 ) {
  1318. MsgBox1Param( NULL, IDS_PROMPT, szFinishMsg,
  1319. MB_ICONINFORMATION, MB_OK );
  1320. }
  1321. LocalFree( szFinishMsg );
  1322. }
  1323. int CALLBACK BrowseCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  1324. {
  1325. switch(uMsg) {
  1326. case BFFM_INITIALIZED:
  1327. // lpData is the path string
  1328. SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
  1329. break;
  1330. }
  1331. return 0;
  1332. }
  1333. //***************************************************************************
  1334. //* *
  1335. //* NAME: BrowseForDir *
  1336. //* *
  1337. //* SYNOPSIS: Let user browse for a directory on their system or network. *
  1338. //* *
  1339. //* REQUIRES: hwndParent: *
  1340. //* szTitle: *
  1341. //* szResult: *
  1342. //* *
  1343. //* RETURNS: BOOL: *
  1344. //* *
  1345. //* NOTES: It would be really cool to set the status line of the *
  1346. //* browse window to display "Yes, there's enough space", or *
  1347. //* "no there is not". *
  1348. //* *
  1349. //***************************************************************************
  1350. BOOL BrowseForDir( HWND hwndParent, LPCTSTR szTitle, LPTSTR szResult )
  1351. {
  1352. BROWSEINFO bi;
  1353. LPITEMIDLIST pidl;
  1354. HINSTANCE hShell32Lib;
  1355. SHFREE pfSHFree;
  1356. SHGETPATHFROMIDLIST pfSHGetPathFromIDList;
  1357. SHBROWSEFORFOLDER pfSHBrowseForFolder;
  1358. LPSTR lpTmp;
  1359. ASSERT( szResult );
  1360. // Load the Shell 32 Library to get the SHBrowseForFolder() features
  1361. if ( ( hShell32Lib = LoadLibrary( achShell32Lib ) ) != NULL ) {
  1362. if ( ( !( pfSHBrowseForFolder = (SHBROWSEFORFOLDER)
  1363. GetProcAddress( hShell32Lib, achSHBrowseForFolder ) ) )
  1364. || ( ! ( pfSHFree = (SHFREE) GetProcAddress( hShell32Lib,
  1365. MAKEINTRESOURCE(SHFREE_ORDINAL) ) ) )
  1366. || ( ! ( pfSHGetPathFromIDList = (SHGETPATHFROMIDLIST)
  1367. GetProcAddress( hShell32Lib, achSHGetPathFromIDList ) ) ) )
  1368. {
  1369. FreeLibrary( hShell32Lib );
  1370. ErrorMsg( hwndParent, IDS_ERR_LOADFUNCS );
  1371. return FALSE;
  1372. }
  1373. } else {
  1374. ErrorMsg( hwndParent, IDS_ERR_LOADDLL );
  1375. return FALSE;
  1376. }
  1377. if ( !g_szBrowsePath[0] )
  1378. {
  1379. GetTempPath( sizeof(g_szBrowsePath), g_szBrowsePath );
  1380. // The following api does not like to have trailing '\\'
  1381. lpTmp = CharPrev( g_szBrowsePath, g_szBrowsePath + lstrlen(g_szBrowsePath) );
  1382. if ( (*lpTmp == '\\') && ( *CharPrev( g_szBrowsePath, lpTmp ) != ':' ) )
  1383. *lpTmp = '\0';
  1384. }
  1385. szResult[0] = 0;
  1386. bi.hwndOwner = hwndParent;
  1387. bi.pidlRoot = NULL;
  1388. bi.pszDisplayName = NULL;
  1389. bi.lpszTitle = szTitle;
  1390. bi.ulFlags = BIF_RETURNONLYFSDIRS;
  1391. bi.lpfn = BrowseCallback;
  1392. bi.lParam = (LPARAM)g_szBrowsePath;
  1393. pidl = pfSHBrowseForFolder( &bi );
  1394. if ( pidl ) {
  1395. pfSHGetPathFromIDList( pidl, g_szBrowsePath );
  1396. if ( g_szBrowsePath[0] ) {
  1397. lstrcpy( szResult, g_szBrowsePath );
  1398. }
  1399. pfSHFree( pidl );
  1400. }
  1401. FreeLibrary( hShell32Lib );
  1402. if ( szResult[0] != 0 ) {
  1403. return TRUE;
  1404. }
  1405. else {
  1406. return FALSE;
  1407. }
  1408. }
  1409. //***************************************************************************
  1410. //* *
  1411. //* NAME: CenterWindow *
  1412. //* *
  1413. //* SYNOPSIS: Center one window within another. *
  1414. //* *
  1415. //* REQUIRES: hwndChild: *
  1416. //* hWndParent: *
  1417. //* *
  1418. //* RETURNS: BOOL: TRUE if successful, FALSE otherwise *
  1419. //* *
  1420. //***************************************************************************
  1421. BOOL CenterWindow( HWND hwndChild, HWND hwndParent )
  1422. {
  1423. RECT rChild;
  1424. RECT rParent;
  1425. int wChild;
  1426. int hChild;
  1427. int wParent;
  1428. int hParent;
  1429. int wScreen;
  1430. int hScreen;
  1431. int xNew;
  1432. int yNew;
  1433. HDC hdc;
  1434. // Get the Height and Width of the child window
  1435. GetWindowRect (hwndChild, &rChild);
  1436. wChild = rChild.right - rChild.left;
  1437. hChild = rChild.bottom - rChild.top;
  1438. // Get the Height and Width of the parent window
  1439. GetWindowRect (hwndParent, &rParent);
  1440. wParent = rParent.right - rParent.left;
  1441. hParent = rParent.bottom - rParent.top;
  1442. // Get the display limits
  1443. hdc = GetDC (hwndChild);
  1444. wScreen = GetDeviceCaps (hdc, HORZRES);
  1445. hScreen = GetDeviceCaps (hdc, VERTRES);
  1446. ReleaseDC (hwndChild, hdc);
  1447. // Calculate new X position, then adjust for screen
  1448. xNew = rParent.left + ((wParent - wChild) /2);
  1449. if (xNew < 0) {
  1450. xNew = 0;
  1451. } else if ((xNew+wChild) > wScreen) {
  1452. xNew = wScreen - wChild;
  1453. }
  1454. // Calculate new Y position, then adjust for screen
  1455. yNew = rParent.top + ((hParent - hChild) /2);
  1456. if (yNew < 0) {
  1457. yNew = 0;
  1458. } else if ((yNew+hChild) > hScreen) {
  1459. yNew = hScreen - hChild;
  1460. }
  1461. // Set it, and return
  1462. return( SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER));
  1463. }
  1464. //***************************************************************************
  1465. //* *
  1466. //* NAME: MsgBox2Param *
  1467. //* *
  1468. //* SYNOPSIS: Displays a message box with the specified string ID using *
  1469. //* 2 string parameters. *
  1470. //* *
  1471. //* REQUIRES: hWnd: Parent window *
  1472. //* nMsgID: String resource ID *
  1473. //* szParam1: Parameter 1 (or NULL) *
  1474. //* szParam2: Parameter 2 (or NULL) *
  1475. //* uIcon: Icon to display (or 0) *
  1476. //* uButtons: Buttons to display *
  1477. //* *
  1478. //* RETURNS: INT: ID of button pressed *
  1479. //* *
  1480. //* NOTES: Macros are provided for displaying 1 parameter or 0 *
  1481. //* parameter message boxes. Also see ErrorMsg() macros. *
  1482. //* *
  1483. //***************************************************************************
  1484. INT CALLBACK MsgBox2Param( HWND hWnd, UINT nMsgID, LPCSTR szParam1, LPCSTR szParam2,
  1485. UINT uIcon, UINT uButtons )
  1486. {
  1487. TCHAR achMsgBuf[STRING_BUF_LEN];
  1488. LPSTR szMessage;
  1489. INT nReturn;
  1490. CHAR achErr[] = "LoadString() Error. Could not load string resource.";
  1491. // BUGBUG: the correct quiet mode return code should be a caller's param since the caller
  1492. // knows what expected its own case.
  1493. //
  1494. if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) )
  1495. {
  1496. // BUGBUG: This section could be replaced by using FormatMessage
  1497. //
  1498. LoadSz( nMsgID, achMsgBuf, sizeof(achMsgBuf) );
  1499. if ( achMsgBuf[0] == 0 )
  1500. {
  1501. MessageBox( hWnd, achErr, g_Sess.achTitle, MB_ICONSTOP |
  1502. MB_OK | MB_SETFOREGROUND |
  1503. ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0));
  1504. return -1;
  1505. }
  1506. if ( szParam2 != NULL )
  1507. {
  1508. szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf )
  1509. + lstrlen( szParam1 )
  1510. + lstrlen( szParam2 ) + 100 );
  1511. if ( ! szMessage )
  1512. {
  1513. return -1;
  1514. }
  1515. wsprintf( szMessage, achMsgBuf, szParam1, szParam2 );
  1516. }
  1517. else if ( szParam1 != NULL )
  1518. {
  1519. szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf )
  1520. + lstrlen( szParam1 ) + 100 );
  1521. if ( ! szMessage ) {
  1522. return -1;
  1523. }
  1524. wsprintf( szMessage, achMsgBuf, szParam1 );
  1525. }
  1526. else
  1527. {
  1528. szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf ) + 1 );
  1529. if ( ! szMessage )
  1530. return -1;
  1531. lstrcpy( szMessage, achMsgBuf );
  1532. }
  1533. MessageBeep( uIcon );
  1534. nReturn = MessageBox( hWnd, szMessage, g_Sess.achTitle, uIcon |
  1535. uButtons | MB_APPLMODAL | MB_SETFOREGROUND |
  1536. ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0));
  1537. LocalFree( szMessage );
  1538. return nReturn;
  1539. }
  1540. else
  1541. return IDOK;
  1542. }
  1543. //***************************************************************************
  1544. //* *
  1545. //* NAME: GetResource *
  1546. //* *
  1547. //* SYNOPSIS: Loads a specified resource into a buffer. *
  1548. //* *
  1549. //* REQUIRES: szRes: Name of resource to load *
  1550. //* lpBuffer: Buffer to put the resource in *
  1551. //* dwMaxSize: Size of buffer (not including terminating *
  1552. //* NULL char, if it's needed. *
  1553. //* *
  1554. //* RETURNS: DWORD: 0 if it fails, otherwise size of resource *
  1555. //* *
  1556. //* NOTES: If the value returned is greater than dwMaxSize, then *
  1557. //* it means the buffer wasn't big enough and the calling *
  1558. //* function should allocate memory the size of the return val. *
  1559. //* *
  1560. //***************************************************************************
  1561. DWORD GetResource( LPCSTR szRes, VOID *lpBuffer, DWORD dwMaxSize )
  1562. {
  1563. HANDLE hRes;
  1564. DWORD dwSize;
  1565. // BUGBUG: called should not depend on this size being exact resource size.
  1566. // Resources could be padded!
  1567. //
  1568. dwSize = SizeofResource( NULL, FindResource( NULL, szRes, RT_RCDATA ) );
  1569. if ( dwSize > dwMaxSize || lpBuffer == NULL ) {
  1570. return dwSize;
  1571. }
  1572. if ( dwSize == 0 ) {
  1573. return 0;
  1574. }
  1575. hRes = LockResource( LoadResource( NULL,
  1576. FindResource( NULL, szRes, RT_RCDATA ) ) );
  1577. if ( hRes == NULL ) {
  1578. return 0;
  1579. }
  1580. memcpy( lpBuffer, hRes, dwSize );
  1581. FreeResource( hRes );
  1582. return ( dwSize );
  1583. }
  1584. //***************************************************************************
  1585. //* *
  1586. //* NAME: LoadSz *
  1587. //* *
  1588. //* SYNOPSIS: Loads specified string resource into buffer. *
  1589. //* *
  1590. //* REQUIRES: idString: *
  1591. //* lpszBuf: *
  1592. //* cbBuf: *
  1593. //* *
  1594. //* RETURNS: LPSTR: Pointer to the passed-in buffer. *
  1595. //* *
  1596. //* NOTES: If this function fails (most likely due to low memory), the *
  1597. //* returned buffer will have a leading NULL so it is generally *
  1598. //* safe to use this without checking for failure. *
  1599. //* *
  1600. //***************************************************************************
  1601. LPSTR LoadSz( UINT idString, LPSTR lpszBuf, UINT cbBuf )
  1602. {
  1603. ASSERT( lpszBuf );
  1604. // Clear the buffer and load the string
  1605. if ( lpszBuf ) {
  1606. *lpszBuf = '\0';
  1607. LoadString( g_hInst, idString, lpszBuf, cbBuf );
  1608. }
  1609. return lpszBuf;
  1610. }
  1611. //***************************************************************************
  1612. //* *
  1613. //* NAME: CatDirAndFile *
  1614. //* *
  1615. //* SYNOPSIS: Concatenate a directory with a filename. *
  1616. //* *
  1617. //* REQUIRES: pszResult: *
  1618. //* wSize: *
  1619. //* pszDir: *
  1620. //* pszFile: *
  1621. //* *
  1622. //* RETURNS: BOOL: *
  1623. //* *
  1624. //***************************************************************************
  1625. BOOL CatDirAndFile( LPTSTR pszResult, int wSize, LPCTSTR pszDir,
  1626. LPCTSTR pszFile )
  1627. {
  1628. ASSERT( lstrlen(pszDir) );
  1629. ASSERT( lstrlen(pszFile) );
  1630. if ( lstrlen(pszDir) + lstrlen(pszFile) + 1 >= wSize ) {
  1631. return FALSE;
  1632. }
  1633. lstrcpy( pszResult, pszDir );
  1634. if ( pszResult[lstrlen(pszResult)-1] != '\\'
  1635. && pszResult[lstrlen(pszResult)-1] != '/' )
  1636. {
  1637. pszResult[lstrlen(pszResult)] = '\\';
  1638. pszResult[lstrlen(pszResult)+1] = '\0';
  1639. }
  1640. lstrcat( pszResult, pszFile );
  1641. return TRUE;
  1642. }
  1643. //***************************************************************************
  1644. //* *
  1645. //* NAME: FileExists *
  1646. //* *
  1647. //* SYNOPSIS: Checks if a file exists. *
  1648. //* *
  1649. //* REQUIRES: pszFilename *
  1650. //* *
  1651. //* RETURNS: BOOL: TRUE if it exists, FALSE otherwise *
  1652. //* *
  1653. //***************************************************************************
  1654. #if 0
  1655. BOOL FileExists( LPCTSTR pszFilename )
  1656. {
  1657. HANDLE hFile;
  1658. ASSERT( pszFilename );
  1659. hFile = CreateFile( pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  1660. FILE_ATTRIBUTE_NORMAL, NULL );
  1661. if ( hFile == INVALID_HANDLE_VALUE ) {
  1662. return( FALSE );
  1663. }
  1664. CloseHandle( hFile );
  1665. return( TRUE );
  1666. }
  1667. #endif
  1668. //***************************************************************************
  1669. //* *
  1670. //* NAME: CheckOverwrite *
  1671. //* *
  1672. //* SYNOPSIS: Check for file existence and do overwrite processing. *
  1673. //* *
  1674. //* REQUIRES: pszFile: File to check *
  1675. //* *
  1676. //* RETURNS: BOOL: TRUE if file can be overwritten. *
  1677. //* FALSE if it can not be overwritten. *
  1678. //* *
  1679. //* NOTE: Should ask Yes/No/Yes-To-All instead of current Yes/No *
  1680. //* *
  1681. //***************************************************************************
  1682. BOOL CheckOverwrite( LPCTSTR cpszFile )
  1683. {
  1684. BOOL fRc = TRUE;
  1685. ASSERT( cpszFile );
  1686. // If File doesn't already exist no overwrite handling
  1687. if ( ! FileExists( cpszFile ) ) {
  1688. return TRUE;
  1689. }
  1690. // Prompt if we're supposed to
  1691. if ( !g_Sess.fOverwrite && !(g_CMD.wQuietMode & QUIETMODE_ALL) )
  1692. {
  1693. g_Sess.cszOverwriteFile = cpszFile;
  1694. switch ( MyDialogBox( g_hInst, MAKEINTRESOURCE(IDD_OVERWRITE),
  1695. g_hwndExtractDlg, OverwriteDlgProc, (LPARAM)0, (INT_PTR)IDYES ) )
  1696. {
  1697. case (INT_PTR)IDYES:
  1698. fRc = TRUE;
  1699. break;
  1700. case (INT_PTR)IDC_BUT_YESTOALL:
  1701. g_Sess.fOverwrite = TRUE;
  1702. fRc = TRUE;
  1703. break;
  1704. case (INT_PTR)IDNO:
  1705. fRc = FALSE;
  1706. break;
  1707. }
  1708. }
  1709. if ( fRc )
  1710. SetFileAttributes( cpszFile, FILE_ATTRIBUTE_NORMAL );
  1711. return fRc;
  1712. }
  1713. //***************************************************************************
  1714. //* *
  1715. //* NAME: AddFile *
  1716. //* *
  1717. //* SYNOPSIS: Add a file to the list of files we have extracted. *
  1718. //* *
  1719. //* REQUIRES: pszName: Filename to add *
  1720. //* *
  1721. //* RETURNS: BOOL: *
  1722. //* *
  1723. //* NOTE: Singly linked list - items added at front *
  1724. //* *
  1725. //***************************************************************************
  1726. BOOL AddFile( LPCTSTR pszName )
  1727. {
  1728. PFNAME NewName;
  1729. ASSERT( pszName );
  1730. // Allocate Node
  1731. NewName = (PFNAME) LocalAlloc( LPTR, sizeof(FNAME) );
  1732. if ( ! NewName ) {
  1733. ErrorMsg( g_hwndExtractDlg, IDS_ERR_NO_MEMORY );
  1734. return( FALSE );
  1735. }
  1736. // Allocate String Space
  1737. NewName->pszFilename = (LPTSTR) LocalAlloc( LPTR, lstrlen(pszName) + 1 );
  1738. if ( ! NewName->pszFilename ) {
  1739. ErrorMsg( g_hwndExtractDlg, IDS_ERR_NO_MEMORY );
  1740. LocalFree( NewName );
  1741. return( FALSE );
  1742. }
  1743. // Copy Filename
  1744. lstrcpy( NewName->pszFilename, pszName );
  1745. // Link into list
  1746. NewName->pNextName = g_Sess.pExtractedFiles;
  1747. g_Sess.pExtractedFiles = NewName;
  1748. return( TRUE );
  1749. }
  1750. //***************************************************************************
  1751. //* *
  1752. //* NAME: Win32Open *
  1753. //* *
  1754. //* SYNOPSIS: Translate a C-Runtime _open() call into appropriate Win32 *
  1755. //* CreateFile() *
  1756. //* *
  1757. //* REQUIRES: pszName: Filename to add *
  1758. //* *
  1759. //* RETURNS: HANDLE: Handle to file on success. *
  1760. //* INVALID_HANDLE_VALUE on error. *
  1761. //* *
  1762. //* NOTE: BUGBUG: Doesn't fully implement C-Runtime _open() *
  1763. //* BUGBUG: capability but it currently supports all callbacks *
  1764. //* BUGBUG: that FDI will give us *
  1765. //* *
  1766. //***************************************************************************
  1767. HANDLE Win32Open( LPCTSTR pszFile, int oflag, int pmode )
  1768. {
  1769. HANDLE FileHandle;
  1770. BOOL fExists = FALSE;
  1771. DWORD fAccess;
  1772. DWORD fCreate;
  1773. ASSERT( pszFile );
  1774. // BUGBUG: No Append Mode Support
  1775. if (oflag & _O_APPEND)
  1776. return( INVALID_HANDLE_VALUE );
  1777. // Set Read-Write Access
  1778. if ((oflag & _O_RDWR) || (oflag & _O_WRONLY))
  1779. fAccess = GENERIC_WRITE;
  1780. else
  1781. fAccess = GENERIC_READ;
  1782. // Set Create Flags
  1783. if (oflag & _O_CREAT) {
  1784. if (oflag & _O_EXCL)
  1785. fCreate = CREATE_NEW;
  1786. else if (oflag & _O_TRUNC)
  1787. fCreate = CREATE_ALWAYS;
  1788. else
  1789. fCreate = OPEN_ALWAYS;
  1790. } else {
  1791. if (oflag & _O_TRUNC)
  1792. fCreate = TRUNCATE_EXISTING;
  1793. else
  1794. fCreate = OPEN_EXISTING;
  1795. }
  1796. FileHandle = CreateFile( pszFile, fAccess, 0, NULL, fCreate,
  1797. FILE_ATTRIBUTE_NORMAL, NULL );
  1798. if ((FileHandle == INVALID_HANDLE_VALUE) && (fCreate != OPEN_EXISTING)) {
  1799. MakeDirectory( pszFile );
  1800. FileHandle = CreateFile( pszFile, fAccess, 0, NULL, fCreate,
  1801. FILE_ATTRIBUTE_NORMAL, NULL );
  1802. }
  1803. return( FileHandle );
  1804. }
  1805. //***************************************************************************
  1806. //* *
  1807. //* NAME: MakeDirectory *
  1808. //* *
  1809. //* SYNOPSIS: Make sure the directories along the given pathname exist. *
  1810. //* *
  1811. //* REQUIRES: pszFile: Name of the file being created. *
  1812. //* *
  1813. //* RETURNS: nothing *
  1814. //* *
  1815. //***************************************************************************
  1816. VOID MakeDirectory( LPCTSTR pszPath )
  1817. {
  1818. LPTSTR pchChopper;
  1819. int cExempt;
  1820. if (pszPath[0] != '\0')
  1821. {
  1822. cExempt = 0;
  1823. if ((pszPath[1] == ':') && (pszPath[2] == '\\'))
  1824. {
  1825. pchChopper = (LPTSTR) (pszPath + 3); /* skip past "C:\" */
  1826. }
  1827. else if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
  1828. {
  1829. pchChopper = (LPTSTR) (pszPath + 2); /* skip past "\\" */
  1830. cExempt = 2; /* machine & share names exempt */
  1831. }
  1832. else
  1833. {
  1834. pchChopper = (LPTSTR) (pszPath + 1); /* skip past potential "\" */
  1835. }
  1836. while (*pchChopper != '\0')
  1837. {
  1838. if ((*pchChopper == '\\') && (*(pchChopper - 1) != ':'))
  1839. {
  1840. if (cExempt != 0)
  1841. {
  1842. cExempt--;
  1843. }
  1844. else
  1845. {
  1846. *pchChopper = '\0';
  1847. CreateDirectory(pszPath,NULL);
  1848. *pchChopper = '\\';
  1849. }
  1850. }
  1851. pchChopper = CharNext(pchChopper);
  1852. }
  1853. }
  1854. }
  1855. //***************************************************************************
  1856. //* *
  1857. //* NAME: openfunc *
  1858. //* *
  1859. //* SYNOPSIS: Open File Callback from FDI *
  1860. //* *
  1861. //* REQUIRES: pszFile: *
  1862. //* oflag: *
  1863. //* pmode: *
  1864. //* *
  1865. //* RETURNS: int: Filehandle (index into file table) *
  1866. //* -1 on failure *
  1867. //* *
  1868. //***************************************************************************
  1869. //
  1870. // Sundown - 11/02/98 - if we are defining ourself as DIAMONDAPI, we need to respect
  1871. // the API types - polymorphic or not...
  1872. INT_PTR FAR DIAMONDAPI openfunc( char FAR *pszFile, int oflag, int pmode )
  1873. {
  1874. INT_PTR rc;
  1875. int i;
  1876. ASSERT( pszFile );
  1877. // Find Available File Handle in Fake File Table
  1878. for ( i = 0; i < FILETABLESIZE; i++ ) {
  1879. if ( g_FileTable[i].avail == TRUE ) {
  1880. break;
  1881. }
  1882. }
  1883. // Running out of file handles should never happen
  1884. if ( i == FILETABLESIZE ) {
  1885. ErrorMsg( g_hwndExtractDlg, IDS_ERR_FILETABLE_FULL );
  1886. return( -1 );
  1887. }
  1888. // BUGBUG Spill File Support for Quantum?
  1889. if ((*pszFile == '*') && (*(pszFile+1) != 'M')) {
  1890. // Spill File Support for Quantum Not Supported
  1891. ASSERT( TRUE );
  1892. }
  1893. // If Opening the Cabinet set up memory fake file
  1894. if ( ( lstrcmp( pszFile, achMemCab ) ) == 0 ) {
  1895. if ( ( oflag & _O_CREAT )
  1896. || ( oflag & _O_APPEND )
  1897. || ( oflag & _O_WRONLY )
  1898. || ( oflag & _O_RDWR ) )
  1899. {
  1900. return(-1);
  1901. }
  1902. g_FileTable[i].avail = FALSE;
  1903. g_FileTable[i].ftype = MEMORY_FILE;
  1904. g_FileTable[i].mfile.start = (void *) g_Sess.lpCabinet;
  1905. g_FileTable[i].mfile.length = g_Sess.cbCabSize;
  1906. g_FileTable[i].mfile.current = 0;
  1907. rc = i;
  1908. } else { // Else its a normal file - Open it
  1909. g_FileTable[i].hf = Win32Open(pszFile, oflag, pmode );
  1910. if ( g_FileTable[i].hf != INVALID_HANDLE_VALUE ) {
  1911. g_FileTable[i].avail = FALSE;
  1912. g_FileTable[i].ftype = NORMAL_FILE;
  1913. rc = i;
  1914. } else {
  1915. rc = -1;
  1916. }
  1917. }
  1918. return( rc );
  1919. }
  1920. //***************************************************************************
  1921. //* *
  1922. //* NAME: readfunc *
  1923. //* *
  1924. //* SYNOPSIS: FDI read() callback *
  1925. //* *
  1926. //* REQUIRES: hf: *
  1927. //* pv: *
  1928. //* cb: *
  1929. //* *
  1930. //* RETURNS: UINT: *
  1931. //* *
  1932. //***************************************************************************
  1933. UINT FAR DIAMONDAPI readfunc( INT_PTR hf, void FAR *pv, UINT cb )
  1934. {
  1935. int rc;
  1936. int cbRead;
  1937. ASSERT( hf < (INT_PTR)FILETABLESIZE );
  1938. ASSERT( g_FileTable[hf].avail == FALSE );
  1939. ASSERT( pv );
  1940. // Normal File: Call Read
  1941. // Memory File: Compute read amount so as to not read
  1942. // past eof. Copy into requesters buffer
  1943. switch ( g_FileTable[hf].ftype ) {
  1944. case NORMAL_FILE:
  1945. if ( ! ReadFile( g_FileTable[hf].hf, pv, cb, (DWORD *) &cb, NULL ) )
  1946. {
  1947. rc = -1;
  1948. } else {
  1949. rc = cb;
  1950. }
  1951. break;
  1952. case MEMORY_FILE:
  1953. // XXX BAD CAST - SIGN PROBLEM FIX THIS!
  1954. cbRead = __min( cb, (UINT) g_FileTable[hf].mfile.length
  1955. - g_FileTable[hf].mfile.current );
  1956. ASSERT( cbRead >= 0 );
  1957. CopyMemory( pv, (const void *) ((char *) g_FileTable[hf].mfile.start + g_FileTable[hf].mfile.current),
  1958. cbRead );
  1959. g_FileTable[hf].mfile.current += cbRead;
  1960. rc = cbRead;
  1961. break;
  1962. }
  1963. return( rc );
  1964. }
  1965. //***************************************************************************
  1966. //* *
  1967. //* NAME: writefunc *
  1968. //* *
  1969. //* SYNOPSIS: FDI write() callback *
  1970. //* *
  1971. //* REQUIRES: hf: *
  1972. //* pv: *
  1973. //* cb: *
  1974. //* *
  1975. //* RETURNS: UINT: *
  1976. //* *
  1977. //***************************************************************************
  1978. UINT FAR DIAMONDAPI writefunc( INT_PTR hf, void FAR *pv, UINT cb )
  1979. {
  1980. int rc;
  1981. ASSERT( hf < (INT_PTR)FILETABLESIZE );
  1982. ASSERT( g_FileTable[hf].avail == FALSE );
  1983. ASSERT( pv );
  1984. ASSERT( g_FileTable[hf].ftype != MEMORY_FILE );
  1985. WaitForObject( g_hCancelEvent );
  1986. // If Cancel has been pressed, let's fake a write error so that diamond
  1987. // will immediately send us a close for the file currently being written
  1988. // to so that we can kill our process.
  1989. //
  1990. if ( g_Sess.fCanceled ) {
  1991. return (UINT) -1 ;
  1992. }
  1993. if ( ! WriteFile( g_FileTable[hf].hf, pv, cb, (DWORD *) &cb, NULL ) ) {
  1994. rc = -1;
  1995. } else {
  1996. rc = cb;
  1997. }
  1998. // Progress Bar: Keep count of bytes written and adjust progbar
  1999. if ( rc != -1 ) {
  2000. // Update count of bytes written
  2001. g_Sess.cbWritten += rc;
  2002. // Update the Progress Bar
  2003. if ( g_fOSSupportsFullUI && g_hwndExtractDlg ) {
  2004. SendDlgItemMessage( g_hwndExtractDlg, IDC_GENERIC1, PBM_SETPOS,
  2005. (WPARAM) g_Sess.cbWritten * 100 /
  2006. g_Sess.cbTotal, (LPARAM) 0 );
  2007. }
  2008. }
  2009. return( rc );
  2010. }
  2011. //***************************************************************************
  2012. //* *
  2013. //* NAME: closefunc *
  2014. //* *
  2015. //* SYNOPSIS: FDI close file callback *
  2016. //* *
  2017. //* REQUIRES: hf: *
  2018. //* *
  2019. //* RETURNS: int: *
  2020. //* *
  2021. //***************************************************************************
  2022. int FAR DIAMONDAPI closefunc( INT_PTR hf )
  2023. {
  2024. int rc;
  2025. ASSERT(hf < (INT_PTR)FILETABLESIZE);
  2026. ASSERT(g_FileTable[hf].avail == FALSE);
  2027. // If memory file reset values else close the file
  2028. if ( g_FileTable[hf].ftype == MEMORY_FILE ) {
  2029. g_FileTable[hf].avail = TRUE;
  2030. g_FileTable[hf].mfile.start = 0;
  2031. g_FileTable[hf].mfile.length = 0;
  2032. g_FileTable[hf].mfile.current = 0;
  2033. rc = 0;
  2034. } else {
  2035. if ( CloseHandle( g_FileTable[hf].hf ) ) {
  2036. rc = 0;
  2037. g_FileTable[hf].avail = TRUE;
  2038. } else {
  2039. rc = -1;
  2040. }
  2041. }
  2042. return( rc );
  2043. }
  2044. //***************************************************************************
  2045. //* *
  2046. //* NAME: seekfunc *
  2047. //* *
  2048. //* SYNOPSIS: FDI Seek callback *
  2049. //* *
  2050. //* REQUIRES: hf: *
  2051. //* dist: *
  2052. //* seektype: *
  2053. //* *
  2054. //* RETURNS: long: *
  2055. //* *
  2056. //***************************************************************************
  2057. long FAR DIAMONDAPI seekfunc( INT_PTR hf, long dist, int seektype )
  2058. {
  2059. long rc;
  2060. DWORD W32seektype;
  2061. ASSERT(hf < (INT_PTR)FILETABLESIZE);
  2062. ASSERT(g_FileTable[hf].avail == FALSE);
  2063. // If memory file just change indexes else call SetFilePointer()
  2064. if (g_FileTable[hf].ftype == MEMORY_FILE) {
  2065. switch (seektype) {
  2066. case SEEK_SET:
  2067. g_FileTable[hf].mfile.current = dist;
  2068. break;
  2069. case SEEK_CUR:
  2070. g_FileTable[hf].mfile.current += dist;
  2071. break;
  2072. case SEEK_END:
  2073. g_FileTable[hf].mfile.current = g_FileTable[hf].mfile.length + dist; // XXX is a -1 necessary
  2074. break;
  2075. default:
  2076. return(-1);
  2077. }
  2078. rc = g_FileTable[hf].mfile.current;
  2079. } else {
  2080. // Must be Win32 File so translate to Win32 Seek type and seek
  2081. switch (seektype) {
  2082. case SEEK_SET:
  2083. W32seektype = FILE_BEGIN;
  2084. break;
  2085. case SEEK_CUR:
  2086. W32seektype = FILE_CURRENT;
  2087. break;
  2088. case SEEK_END:
  2089. W32seektype = FILE_END;
  2090. break;
  2091. }
  2092. rc = SetFilePointer(g_FileTable[hf].hf, dist, NULL, W32seektype);
  2093. if (rc == 0xffffffff)
  2094. rc = -1;
  2095. }
  2096. return( rc );
  2097. }
  2098. //***************************************************************************
  2099. //* *
  2100. //* NAME: AdjustFileTime *
  2101. //* *
  2102. //* SYNOPSIS: Change the time info for a file *
  2103. //* *
  2104. //* REQUIRES: hf: *
  2105. //* date: *
  2106. //* time: *
  2107. //* *
  2108. //* RETURNS: BOOL: *
  2109. //* *
  2110. //***************************************************************************
  2111. BOOL AdjustFileTime( INT_PTR hf, USHORT date, USHORT time )
  2112. {
  2113. FILETIME ft;
  2114. FILETIME ftUTC;
  2115. ASSERT( hf < (INT_PTR)FILETABLESIZE );
  2116. ASSERT( g_FileTable[hf].avail == FALSE );
  2117. ASSERT( g_FileTable[hf].ftype != MEMORY_FILE );
  2118. // THIS IS A DUPLICATE OF THE ASSERTION!!!!!!
  2119. // Memory File? -- Bogus
  2120. if ( g_FileTable[hf].ftype == MEMORY_FILE ) {
  2121. return( FALSE );
  2122. }
  2123. if ( ! DosDateTimeToFileTime( date, time, &ft ) ) {
  2124. return( FALSE );
  2125. }
  2126. if ( ! LocalFileTimeToFileTime( &ft, &ftUTC ) ) {
  2127. return( FALSE );
  2128. }
  2129. if ( ! SetFileTime( g_FileTable[hf].hf, &ftUTC, &ftUTC, &ftUTC ) ) {
  2130. return( FALSE );
  2131. }
  2132. return( TRUE );
  2133. }
  2134. //***************************************************************************
  2135. //* *
  2136. //* NAME: Attr32FromAttrFAT *
  2137. //* *
  2138. //* SYNOPSIS: Translate FAT attributes to Win32 Attributes *
  2139. //* *
  2140. //* REQUIRES: attrMSDOS: *
  2141. //* *
  2142. //* RETURNS: DWORD: *
  2143. //* *
  2144. //***************************************************************************
  2145. DWORD Attr32FromAttrFAT( WORD attrMSDOS )
  2146. {
  2147. //** Quick out for normal file special case
  2148. if (attrMSDOS == _A_NORMAL) {
  2149. return FILE_ATTRIBUTE_NORMAL;
  2150. }
  2151. //** Otherwise, mask off read-only, hidden, system, and archive bits
  2152. // NOTE: These bits are in the same places in MS-DOS and Win32!
  2153. return attrMSDOS & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
  2154. }
  2155. //***************************************************************************
  2156. //* *
  2157. //* NAME: allocfunc *
  2158. //* *
  2159. //* SYNOPSIS: FDI Memory Allocation Callback *
  2160. //* *
  2161. //* REQUIRES: *
  2162. //* *
  2163. //* RETURNS: *
  2164. //* *
  2165. //***************************************************************************
  2166. FNALLOC( allocfunc )
  2167. {
  2168. void *pv;
  2169. pv = (void *) GlobalAlloc( GMEM_FIXED, cb );
  2170. return( pv );
  2171. }
  2172. //***************************************************************************
  2173. //* *
  2174. //* NAME: freefunc *
  2175. //* *
  2176. //* SYNOPSIS: FDI Memory Deallocation Callback *
  2177. //* *
  2178. //* REQUIRES: *
  2179. //* *
  2180. //* RETURNS: *
  2181. //* *
  2182. //***************************************************************************
  2183. FNFREE( freefunc )
  2184. {
  2185. ASSERT(pv);
  2186. GlobalFree( pv );
  2187. }
  2188. //***************************************************************************
  2189. //* *
  2190. //* NAME: doGetNextCab *
  2191. //* *
  2192. //* SYNOPSIS: Get Next Cabinet in chain *
  2193. //* *
  2194. //* REQUIRES: *
  2195. //* *
  2196. //* RETURNS: -1 *
  2197. //* *
  2198. //* NOTES: BUGBUG: CLEANUP: STUB THIS OUT *
  2199. //* BUGBUG: STUBBED OUT IN WEXTRACT - CHAINED CABINETS NOT *
  2200. //* BUGBUG: SUPPORTED *
  2201. //* *
  2202. //***************************************************************************
  2203. FNFDINOTIFY( doGetNextCab )
  2204. {
  2205. return( -1 );
  2206. }
  2207. //***************************************************************************
  2208. //* *
  2209. //* NAME: fdiNotifyExtract *
  2210. //* *
  2211. //* SYNOPSIS: Principle FDI Callback in file extraction *
  2212. //* *
  2213. //* REQUIRES: *
  2214. //* *
  2215. //* RETURNS: *
  2216. //* *
  2217. //***************************************************************************
  2218. FNFDINOTIFY( fdiNotifyExtract )
  2219. {
  2220. INT_PTR fh;
  2221. TCHAR achFile[MAX_PATH]; // Current File
  2222. // User Hit Cancel Button? Cleanup.
  2223. if ( g_Sess.fCanceled ) {
  2224. if ( fdint == fdintCLOSE_FILE_INFO ) {
  2225. // close the file (as below)
  2226. closefunc( pfdin->hf );
  2227. }
  2228. return( -1 );
  2229. }
  2230. switch ( fdint ) {
  2231. //*******************************************************************
  2232. case fdintCABINET_INFO:
  2233. return UpdateCabinetInfo( pfdin );
  2234. //*******************************************************************
  2235. case fdintCOPY_FILE:
  2236. if ( g_hwndExtractDlg )
  2237. SetDlgItemText( g_hwndExtractDlg, IDC_FILENAME, pfdin->psz1 );
  2238. if ( ! CatDirAndFile( achFile, sizeof( achFile ),
  2239. g_Sess.achDestDir, pfdin->psz1 ) )
  2240. {
  2241. return -1; // Abort with error
  2242. }
  2243. if ( ! CheckOverwrite( achFile ) ) {
  2244. return (INT_PTR)NULL;
  2245. }
  2246. fh = openfunc( achFile, _O_BINARY | _O_TRUNC | _O_RDWR |
  2247. _O_CREAT, _S_IREAD | _S_IWRITE );
  2248. if ( fh == -1 ) {
  2249. return( -1 );
  2250. }
  2251. if ( ! AddFile( achFile ) ) {
  2252. return( -1 );
  2253. }
  2254. g_Sess.cFiles++;
  2255. return(fh);
  2256. //*******************************************************************
  2257. case fdintCLOSE_FILE_INFO:
  2258. if ( ! CatDirAndFile( achFile, sizeof(achFile),
  2259. g_Sess.achDestDir, pfdin->psz1 ) )
  2260. {
  2261. return -1; // Abort with error;
  2262. }
  2263. if ( ! AdjustFileTime( pfdin->hf, pfdin->date, pfdin->time ) ) {
  2264. return( -1 );
  2265. }
  2266. closefunc( pfdin->hf );
  2267. if ( ! SetFileAttributes( achFile,
  2268. Attr32FromAttrFAT( pfdin->attribs ) ) )
  2269. {
  2270. return( -1 );
  2271. }
  2272. return(TRUE);
  2273. //*******************************************************************
  2274. case fdintPARTIAL_FILE:
  2275. return( 0 );
  2276. //*******************************************************************
  2277. case fdintNEXT_CABINET:
  2278. return doGetNextCab( fdint, pfdin );
  2279. //*******************************************************************
  2280. default:
  2281. break;
  2282. }
  2283. return( 0 );
  2284. }
  2285. //***************************************************************************
  2286. //* *
  2287. //* NAME: UpdateCabinetInfo *
  2288. //* *
  2289. //* SYNOPSIS: update history of cabinets seen *
  2290. //* *
  2291. //* REQUIRES: pfdin: FDI info structure *
  2292. //* *
  2293. //* RETURNS: 0 *
  2294. //* *
  2295. //***************************************************************************
  2296. int UpdateCabinetInfo( PFDINOTIFICATION pfdin )
  2297. {
  2298. //** Save older cabinet info
  2299. g_Sess.acab[0] = g_Sess.acab[1];
  2300. //** Save new cabinet info
  2301. lstrcpy( g_Sess.acab[1].achCabPath , pfdin->psz3 );
  2302. lstrcpy( g_Sess.acab[1].achCabFilename, pfdin->psz1 );
  2303. lstrcpy( g_Sess.acab[1].achDiskName , pfdin->psz2 );
  2304. g_Sess.acab[1].setID = pfdin->setID;
  2305. g_Sess.acab[1].iCabinet = pfdin->iCabinet;
  2306. return 0;
  2307. }
  2308. //***************************************************************************
  2309. //* *
  2310. //* NAME: VerifyCabinet *
  2311. //* *
  2312. //* SYNOPSIS: Check that cabinet is properly formed *
  2313. //* *
  2314. //* REQUIRES: HGLOBAL: *
  2315. //* *
  2316. //* RETURNS: BOOL: TRUE if Cabinet OK, FALSE if Cabinet invalid*
  2317. //* *
  2318. //***************************************************************************
  2319. BOOL VerifyCabinet( VOID *lpCabinet )
  2320. {
  2321. HFDI hfdi;
  2322. ERF erf;
  2323. FDICABINETINFO cabinfo;
  2324. INT_PTR fh;
  2325. /* zero structure before use. FDIIsCabinet not fill in hasnext/hasprev on NT */
  2326. memset( &cabinfo, 0, sizeof(cabinfo) );
  2327. hfdi = FDICreate(allocfunc,freefunc,openfunc,readfunc,writefunc,closefunc,seekfunc,cpu80386,&erf);
  2328. if ( hfdi == NULL ) {
  2329. // BUGBUG Error Handling?
  2330. return( FALSE );
  2331. }
  2332. fh = openfunc( achMemCab, _O_BINARY | _O_RDONLY, _S_IREAD | _S_IWRITE );
  2333. if (fh == -1) {
  2334. return( FALSE );
  2335. }
  2336. if (FDIIsCabinet(hfdi, fh, &cabinfo ) == FALSE) {
  2337. return( FALSE );
  2338. }
  2339. if (cabinfo.cbCabinet != (long) g_Sess.cbCabSize) {
  2340. return( FALSE );
  2341. }
  2342. if (cabinfo.hasprev || cabinfo.hasnext) {
  2343. return( FALSE );
  2344. }
  2345. if (closefunc( fh ) == -1) {
  2346. return( FALSE );
  2347. }
  2348. if (FDIDestroy(hfdi) == FALSE) {
  2349. return( FALSE );
  2350. }
  2351. return( TRUE );
  2352. }
  2353. //***************************************************************************
  2354. //* *
  2355. //* NAME: ExtractThread *
  2356. //* *
  2357. //* SYNOPSIS: Main Body of Extract Thread *
  2358. //* *
  2359. //* REQUIRES: Nothing *
  2360. //* *
  2361. //* RETURNS: BOOL: *
  2362. //* *
  2363. //***************************************************************************
  2364. BOOL ExtractThread( VOID )
  2365. {
  2366. HFDI hfdi;
  2367. BOOL fExtractResult = TRUE;
  2368. if ( ! GetCabinet() ) {
  2369. return FALSE;
  2370. }
  2371. if ( g_hwndExtractDlg )
  2372. {
  2373. ShowWindow( GetDlgItem( g_hwndExtractDlg, IDC_EXTRACT_WAIT ), SW_HIDE ) ;
  2374. ShowWindow( GetDlgItem( g_hwndExtractDlg, IDC_EXTRACTINGFILE ), SW_SHOW ) ;
  2375. }
  2376. if ( ! VerifyCabinet( g_Sess.lpCabinet ) ) {
  2377. ErrorMsg( g_hwndExtractDlg, IDS_ERR_INVALID_CABINET );
  2378. fExtractResult = FALSE;
  2379. goto done;
  2380. }
  2381. // Extract the files
  2382. hfdi = FDICreate( allocfunc, freefunc, openfunc, readfunc, writefunc,
  2383. closefunc, seekfunc, cpu80386, &(g_Sess.erf) );
  2384. if ( hfdi == NULL ) {
  2385. ErrorMsg( g_hwndExtractDlg, g_Sess.erf.erfOper + IDS_ERR_FDI_BASE );
  2386. fExtractResult = FALSE;
  2387. goto done;
  2388. }
  2389. fExtractResult = FDICopy( hfdi, achMemCab, "", 0, fdiNotifyExtract,
  2390. NULL, (void *) &g_Sess );
  2391. if ( fExtractResult == FALSE ) {
  2392. goto done;
  2393. }
  2394. if ( FDIDestroy( hfdi ) == FALSE ) {
  2395. ErrorMsg( g_hwndExtractDlg, g_Sess.erf.erfOper + IDS_ERR_FDI_BASE );
  2396. fExtractResult = FALSE;
  2397. goto done;
  2398. }
  2399. done:
  2400. if ( g_Sess.lpCabinet )
  2401. {
  2402. FreeResource( g_Sess.lpCabinet );
  2403. g_Sess.lpCabinet = NULL;
  2404. }
  2405. if ( (fExtractResult == FALSE) && !g_Sess.fCanceled )
  2406. {
  2407. ErrorMsg( NULL, IDS_ERR_LOWSWAPSPACE );
  2408. }
  2409. if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) && !(g_Sess.uExtractOpt & EXTRACTOPT_UI_NO) )
  2410. {
  2411. SendMessage( g_hwndExtractDlg, UM_EXTRACTDONE, (WPARAM) fExtractResult, (LPARAM) 0 );
  2412. }
  2413. return fExtractResult;
  2414. }
  2415. //***************************************************************************
  2416. //* *
  2417. //* NAME: GetCabinet *
  2418. //* *
  2419. //* SYNOPSIS: Gets the cabinet from a resource. *
  2420. //* *
  2421. //* REQUIRES: Nothing *
  2422. //* *
  2423. //* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
  2424. //* *
  2425. //***************************************************************************
  2426. BOOL GetCabinet( VOID )
  2427. {
  2428. g_Sess.cbCabSize = GetResource( achResCabinet, NULL, 0 );
  2429. //g_Sess.lpCabinet = (VOID *) LocalAlloc( LPTR, g_Sess.cbCabSize + 1 );
  2430. //if ( ! g_Sess.lpCabinet ) {
  2431. // ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  2432. // return FALSE;
  2433. //}
  2434. g_Sess.lpCabinet = LockResource( LoadResource( NULL,
  2435. FindResource( NULL, achResCabinet, RT_RCDATA ) ) );
  2436. if ( g_Sess.lpCabinet == NULL ) {
  2437. return 0;
  2438. }
  2439. return TRUE;
  2440. }
  2441. //***************************************************************************
  2442. //* *
  2443. //* NAME: GetFileList *
  2444. //* *
  2445. //* SYNOPSIS: Gets the file list from resources. *
  2446. //* *
  2447. //* REQUIRES: Nothing *
  2448. //* *
  2449. //* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
  2450. //* *
  2451. //***************************************************************************
  2452. BOOL GetFileList( VOID )
  2453. {
  2454. DWORD dwSize;
  2455. dwSize = GetResource( achResSize, g_dwFileSizes, sizeof(g_dwFileSizes) );
  2456. if ( dwSize != sizeof(g_dwFileSizes) ) {
  2457. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  2458. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  2459. return FALSE;
  2460. }
  2461. // total files sizes not considering the cluster size
  2462. g_Sess.cbTotal = g_dwFileSizes[MAX_NUMCLUSTERS];
  2463. if ( g_Sess.cbTotal == 0 )
  2464. {
  2465. ErrorMsg( NULL, IDS_ERR_RESOURCEBAD );
  2466. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  2467. return FALSE;
  2468. }
  2469. // get install disk space requirement
  2470. // if there is no such resource, the value shoud be remain 0 as default
  2471. GetResource( achResPackInstSpace, &(g_Sess.cbPackInstSize), sizeof(g_Sess.cbPackInstSize) );
  2472. // Get disk space required for Extra files (files tagged onto package with Updfile.exe)
  2473. if ( ! TravelUpdatedFiles( ProcessUpdatedFile_Size ) ) {
  2474. ErrorMsg( NULL, IDS_ERR_RESOURCEBAD );
  2475. // g_dwExitCode is set in TravelUpdatedFiles()
  2476. return FALSE;
  2477. }
  2478. return TRUE;
  2479. }
  2480. //***************************************************************************
  2481. //* *
  2482. //* NAME: GetUsersPermission *
  2483. //* *
  2484. //* SYNOPSIS: Ask user if (s)he wants to perform this extraction before *
  2485. //* proceeding. If no IDS_UD_PROMPT string resource exists *
  2486. //* then we skip the prompting and just extract. *
  2487. //* *
  2488. //* REQUIRES: *
  2489. //* *
  2490. //* RETURNS: BOOL: TRUE to proceed with extraction *
  2491. //* FALSE to abort extraction *
  2492. //* *
  2493. //***************************************************************************
  2494. BOOL GetUsersPermission( VOID )
  2495. {
  2496. int ret;
  2497. LPSTR szPrompt;
  2498. DWORD dwSize;
  2499. // Get Prompt String
  2500. dwSize = GetResource( achResUPrompt, NULL, 0 );
  2501. szPrompt = (LPSTR) LocalAlloc( LPTR, dwSize + 1 );
  2502. if ( ! szPrompt ) {
  2503. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  2504. g_dwExitCode = MyGetLastError();
  2505. return FALSE;
  2506. }
  2507. if ( ! GetResource( achResUPrompt, szPrompt, dwSize ) ) {
  2508. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  2509. LocalFree( szPrompt );
  2510. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  2511. return FALSE;
  2512. }
  2513. if ( lstrcmp( szPrompt, achResNone ) == 0 ) {
  2514. LocalFree( szPrompt );
  2515. return( TRUE );
  2516. }
  2517. ret = MsgBox1Param( NULL, IDS_PROMPT, szPrompt,
  2518. MB_ICONQUESTION, MB_YESNO );
  2519. LocalFree( szPrompt );
  2520. if ( ret == IDYES ) {
  2521. g_dwExitCode = S_OK;
  2522. return( TRUE );
  2523. } else {
  2524. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2525. return( FALSE );
  2526. }
  2527. }
  2528. //***************************************************************************
  2529. //* *
  2530. //* NAME: DeleteExtractedFiles *
  2531. //* *
  2532. //* SYNOPSIS: Delete the files that were extracted into the temporary *
  2533. //* directory. *
  2534. //* *
  2535. //* REQUIRES: *
  2536. //* *
  2537. //* RETURNS: Nothing *
  2538. //* *
  2539. //***************************************************************************
  2540. VOID DeleteExtractedFiles( VOID )
  2541. {
  2542. PFNAME rover;
  2543. PFNAME temp;
  2544. rover = g_Sess.pExtractedFiles;
  2545. temp = rover;
  2546. while ( rover != NULL ) {
  2547. if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly )
  2548. {
  2549. SetFileAttributes( rover->pszFilename, FILE_ATTRIBUTE_NORMAL );
  2550. DeleteFile( rover->pszFilename );
  2551. }
  2552. rover = rover->pNextName;
  2553. LocalFree( temp->pszFilename );
  2554. LocalFree( temp );
  2555. temp = rover;
  2556. }
  2557. if ( g_CMD.fCreateTemp && (!g_CMD.fUserBlankCmd) && (!g_Sess.uExtractOnly) )
  2558. {
  2559. char szFolder[MAX_PATH];
  2560. lstrcpy( szFolder, g_Sess.achDestDir );
  2561. if (g_Sess.uExtractOpt & EXTRACTOPT_PLATFORM_DIR)
  2562. {
  2563. // potential we have create 2 level temp dir temp\platform
  2564. // if they are empty clean up
  2565. GetParentDir( szFolder );
  2566. }
  2567. SetCurrentDirectory( ".." );
  2568. DeleteMyDir( szFolder );
  2569. }
  2570. // delete the runonce reg entry if it is there since we do the cleanup ourself
  2571. if ( (g_wOSVer != _OSVER_WINNT3X) && (g_CMD.fCreateTemp) )
  2572. CleanRegRunOnce();
  2573. g_CMD.fCreateTemp = FALSE;
  2574. }
  2575. BOOL GetNewTempDir( LPCSTR lpParent, LPSTR lpFullPath )
  2576. {
  2577. int index = 0;
  2578. char szPath[MAX_PATH];
  2579. BOOL bFound = FALSE;
  2580. while ( index < 400 )
  2581. {
  2582. wsprintf(szPath, TEMP_TEMPLATE, index++);
  2583. lstrcpy( lpFullPath, lpParent );
  2584. AddPath( lpFullPath, szPath );
  2585. // if there is an empty dir, remove it first
  2586. RemoveDirectory( lpFullPath );
  2587. if ( GetFileAttributes( lpFullPath ) == -1 )
  2588. {
  2589. if ( CreateDirectory( lpFullPath , NULL ) )
  2590. {
  2591. g_CMD.fCreateTemp = TRUE;
  2592. bFound = TRUE;
  2593. }
  2594. else
  2595. bFound = FALSE;
  2596. break;
  2597. }
  2598. }
  2599. if ( !bFound && GetTempFileName( lpParent, TEMPPREFIX, 0, lpFullPath ) )
  2600. {
  2601. bFound = TRUE;
  2602. DeleteFile( lpFullPath ); // if file doesn't exist, fail it. who cares.
  2603. CreateDirectory( lpFullPath, NULL );
  2604. }
  2605. return bFound;
  2606. }
  2607. //***************************************************************************
  2608. //* *
  2609. //* NAME: CreateAndValidateSubdir *
  2610. //* *
  2611. //* SYNOPSIS: *
  2612. //* *
  2613. //* REQUIRES: *
  2614. //* *
  2615. //* RETURNS: *
  2616. //* *
  2617. //***************************************************************************
  2618. BOOL CreateAndValidateSubdir( LPCTSTR lpPath, BOOL bCreateUnique, UINT chkType )
  2619. {
  2620. TCHAR szTemp[MAX_PATH];
  2621. if ( bCreateUnique )
  2622. {
  2623. if ( GetNewTempDir( lpPath, szTemp ) )
  2624. {
  2625. lstrcpy( g_Sess.achDestDir, szTemp );
  2626. if (g_Sess.uExtractOpt & EXTRACTOPT_PLATFORM_DIR) {
  2627. SYSTEM_INFO SystemInfo;
  2628. GetSystemInfo( &SystemInfo );
  2629. switch (SystemInfo.wProcessorArchitecture) {
  2630. case PROCESSOR_ARCHITECTURE_INTEL:
  2631. AddPath( g_Sess.achDestDir, "i386" );
  2632. break;
  2633. case PROCESSOR_ARCHITECTURE_MIPS:
  2634. AddPath( g_Sess.achDestDir, "mips" );
  2635. break;
  2636. case PROCESSOR_ARCHITECTURE_ALPHA:
  2637. AddPath( g_Sess.achDestDir, "alpha" );
  2638. break;
  2639. case PROCESSOR_ARCHITECTURE_PPC:
  2640. AddPath( g_Sess.achDestDir, "ppc" );
  2641. break;
  2642. }
  2643. }
  2644. AddPath( g_Sess.achDestDir, "" );
  2645. }
  2646. else
  2647. return FALSE;
  2648. }
  2649. else
  2650. lstrcpy( g_Sess.achDestDir, lpPath );
  2651. // if not there, create dir
  2652. if ( !IsGoodTempDir( g_Sess.achDestDir ) )
  2653. {
  2654. if ( CreateDirectory( g_Sess.achDestDir, NULL ) )
  2655. {
  2656. g_CMD.fCreateTemp = TRUE;
  2657. }
  2658. else
  2659. {
  2660. g_dwExitCode = MyGetLastError();
  2661. return FALSE;
  2662. }
  2663. }
  2664. if ( IsEnoughSpace(g_Sess.achDestDir, chkType, MSG_REQDSK_NONE ) )
  2665. {
  2666. g_dwExitCode = S_OK;
  2667. return TRUE;
  2668. }
  2669. if ( g_CMD.fCreateTemp )
  2670. {
  2671. g_CMD.fCreateTemp = FALSE;
  2672. RemoveDirectory(g_Sess.achDestDir);
  2673. }
  2674. return FALSE;
  2675. }
  2676. //***************************************************************************
  2677. //* *
  2678. //* NAME: GetTempDirectory *
  2679. //* *
  2680. //* SYNOPSIS: Get a temporary Directory for extraction that is on a drive *
  2681. //* with enough disk space available. *
  2682. //* *
  2683. //* REQUIRES: *
  2684. //* *
  2685. //* RETURNS: BOOL: TRUE if successful, FALSE on error *
  2686. //* *
  2687. //***************************************************************************
  2688. BOOL GetTempDirectory( VOID )
  2689. {
  2690. INT_PTR iDlgRC;
  2691. int len;
  2692. DWORD dwSize;
  2693. LPTSTR szCommand;
  2694. char szRoot[MAX_PATH];
  2695. // Try system TEMP path first, if that isn't any good then
  2696. // we'll try the EXE directory. If both fail, ask user
  2697. // to pick a temp dir.
  2698. // check if user has empty command
  2699. dwSize = GetResource( achResRunProgram, NULL, 0 );
  2700. szCommand = (LPSTR) LocalAlloc( LPTR, dwSize + 1 );
  2701. if ( ! szCommand ) {
  2702. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  2703. g_dwExitCode = MyGetLastError();
  2704. return FALSE;
  2705. }
  2706. if ( ! GetResource( achResRunProgram, szCommand, dwSize ) )
  2707. {
  2708. ErrorMsg( NULL, IDS_ERR_NO_RESOURCE );
  2709. LocalFree( szCommand );
  2710. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  2711. return FALSE;
  2712. }
  2713. if ( !lstrcmp( szCommand, achResNone ) )
  2714. {
  2715. // only extract files, no run command
  2716. g_Sess.uExtractOnly = 1;
  2717. }
  2718. LocalFree( szCommand );
  2719. // if user use /T: option, we wont try any others
  2720. if ( g_CMD.szUserTempDir[0] )
  2721. {
  2722. UINT chkType;
  2723. if ( (g_CMD.szUserTempDir[0] == '\\') && (g_CMD.szUserTempDir[1] == '\\') )
  2724. chkType = CHK_REQDSK_NONE;
  2725. else
  2726. chkType = CHK_REQDSK_EXTRACT;
  2727. if ( CreateAndValidateSubdir( g_CMD.szUserTempDir, FALSE, chkType ) )
  2728. return TRUE;
  2729. else
  2730. {
  2731. ErrorMsg( NULL, IDS_ERR_INVALID_DIR );
  2732. return FALSE;
  2733. }
  2734. }
  2735. else
  2736. {
  2737. if ( g_CMD.fUserBlankCmd || g_Sess.uExtractOnly )
  2738. {
  2739. // ask user where files are stored
  2740. iDlgRC = MyDialogBox( g_hInst, MAKEINTRESOURCE(IDD_TEMPDIR),
  2741. NULL, TempDirDlgProc, (LPARAM)0, 0 );
  2742. //fDlgRC = UserDirPrompt( NULL, IDS_TEMP_EXTRACT, "", g_Sess.achDestDir, sizeof(g_Sess.achDestDir) );
  2743. return ( iDlgRC != 0 ) ;
  2744. }
  2745. // First - try TMP, TEMP, and current
  2746. if ( GetTempPath( sizeof(g_Sess.achDestDir), g_Sess.achDestDir ) )
  2747. {
  2748. if ( CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, (CHK_REQDSK_EXTRACT | CHK_REQDSK_INST) ) )
  2749. return TRUE;
  2750. if ( !IsWindowsDrive( g_Sess.achDestDir ) && CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, CHK_REQDSK_EXTRACT ) )
  2751. return TRUE;
  2752. }
  2753. // temp dir failed, try EXE dir
  2754. // Second - try running EXE Directory
  2755. // Too much grief, lets take this thing out
  2756. #if 0
  2757. if ( GetModuleFileName( g_hInst, g_Sess.achDestDir, (DWORD)sizeof(g_Sess.achDestDir) ) && (g_Sess.achDestDir[1] != '\\') )
  2758. {
  2759. len = lstrlen( g_Sess.achDestDir )-1;
  2760. while ( g_Sess.achDestDir[len] != '\\' )
  2761. len--;
  2762. g_Sess.achDestDir[len+1] = '\0';
  2763. if ( CreateAndValidateSubdir ( g_Sess.achDestDir, TRUE, (CHK_REQDSK_EXTRACT | CHK_REQDSK_INST) ) )
  2764. return TRUE;
  2765. if ( !IsWindowsDrive( g_Sess.achDestDir ) && CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, CHK_REQDSK_EXTRACT ) )
  2766. return TRUE;
  2767. }
  2768. #endif
  2769. // you are here--means that tmp dir and exe dir are both failed EITHER because of not enough space for
  2770. // both install and extracting and they reside the same dir as Windows OR it is non-windir but not enough space
  2771. // even for extracting itself.
  2772. // we are going to search through users's machine drive A to Z and pick up the drive(FIXED&NON-CD) meet the following conditions:
  2773. // 1) big enough for both install and extract space;
  2774. // 2) 1st Non-Windows drive which has enough space for extracting
  2775. //
  2776. do
  2777. {
  2778. lstrcpy( szRoot, "A:\\" );
  2779. while ( szRoot[0] <= 'Z' )
  2780. {
  2781. UINT uType;
  2782. DWORD dwFreeBytes = 0;
  2783. uType = GetDriveType(szRoot);
  2784. // even the drive type is OK, verify the drive has valid connection
  2785. //
  2786. if ( ( ( uType != DRIVE_RAMDISK) && (uType != DRIVE_FIXED) ) ||
  2787. ( GetFileAttributes( szRoot ) == -1) )
  2788. {
  2789. if ( (uType != DRIVE_REMOVABLE ) || (szRoot[0] == 'A') || ( szRoot[0] == 'B') ||
  2790. !(dwFreeBytes = GetSpace(szRoot)))
  2791. {
  2792. szRoot[0]++;
  2793. continue;
  2794. }
  2795. if ( dwFreeBytes < SIZE_100MB )
  2796. {
  2797. szRoot[0]++;
  2798. continue;
  2799. }
  2800. }
  2801. // fixed drive:
  2802. if ( !IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT | CHK_REQDSK_INST, MSG_REQDSK_NONE ) )
  2803. {
  2804. if ( IsWindowsDrive(szRoot) || !IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT, MSG_REQDSK_NONE ) )
  2805. {
  2806. szRoot[0]++;
  2807. continue;
  2808. }
  2809. }
  2810. // find the suitable drive
  2811. // create \msdownld.tmp dir as place for extracting location
  2812. //
  2813. if ( IsWindowsDrive(szRoot) )
  2814. {
  2815. GetWindowsDirectory( szRoot, sizeof(szRoot) );
  2816. }
  2817. AddPath( szRoot, DIR_MSDOWNLD );
  2818. if ( !IfNotExistCreateDir( szRoot ) )
  2819. {
  2820. szRoot[0]++;
  2821. szRoot[3] = '\0';
  2822. continue;
  2823. }
  2824. SetFileAttributes( szRoot, FILE_ATTRIBUTE_HIDDEN );
  2825. lstrcpy( g_Sess.achDestDir, szRoot );
  2826. if ( CreateAndValidateSubdir ( g_Sess.achDestDir, TRUE, CHK_REQDSK_NONE ) )
  2827. return TRUE;
  2828. }
  2829. GetWindowsDirectory( szRoot, MAX_PATH);
  2830. // just post message; use Windows Drive clustor size as rough estimate
  2831. //
  2832. } while ( IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT | CHK_REQDSK_INST, MSG_REQDSK_RETRYCANCEL ) );
  2833. }
  2834. return( FALSE );
  2835. }
  2836. //***************************************************************************
  2837. //* *
  2838. //* NAME: IsGoodTempDir *
  2839. //* *
  2840. //* SYNOPSIS: Find out if it's a good temporary directory or not. *
  2841. //* *
  2842. //* REQUIRES: szPath: *
  2843. //* *
  2844. //* RETURNS: BOOL: TRUE if good, FALSE if nogood *
  2845. //* *
  2846. //***************************************************************************
  2847. BOOL IsGoodTempDir( LPCTSTR szPath )
  2848. {
  2849. DWORD dwAttribs;
  2850. HANDLE hFile;
  2851. LPSTR szTestFile;
  2852. ASSERT( szPath );
  2853. szTestFile = (LPSTR) LocalAlloc( LPTR, lstrlen( szPath ) + 20 );
  2854. if ( ! szTestFile ) {
  2855. ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
  2856. g_dwExitCode = MyGetLastError();
  2857. return( FALSE );
  2858. }
  2859. lstrcpy( szTestFile, szPath );
  2860. AddPath( szTestFile, "TMP4351$.TMP" );
  2861. hFile = CreateFile( szTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  2862. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  2863. NULL );
  2864. LocalFree( szTestFile );
  2865. if ( hFile == INVALID_HANDLE_VALUE ) {
  2866. g_dwExitCode = MyGetLastError();
  2867. return( FALSE );
  2868. }
  2869. CloseHandle( hFile );
  2870. dwAttribs = GetFileAttributes( szPath );
  2871. if ( ( dwAttribs != 0xFFFFFFFF )
  2872. && ( dwAttribs & FILE_ATTRIBUTE_DIRECTORY ) )
  2873. {
  2874. g_dwExitCode = S_OK;
  2875. return( TRUE );
  2876. }
  2877. g_dwExitCode = MyGetLastError();
  2878. return( FALSE );
  2879. }
  2880. //***************************************************************************
  2881. //* *
  2882. //* NAME: IsEnoughSpace *
  2883. //* *
  2884. //* SYNOPSIS: Check to make sure that enough space is available in the *
  2885. //* directory specified. *
  2886. //* *
  2887. //* REQUIRES: szPath: *
  2888. //* *
  2889. //* RETURNS: BOOL: TRUE if enough space is available *
  2890. //* FALSE if not enough space *
  2891. //* *
  2892. //***************************************************************************
  2893. BOOL IsEnoughSpace( LPCTSTR szPath, UINT chkType, UINT msgType )
  2894. {
  2895. DWORD dwClusterSize = 0;
  2896. DWORD dwFreeBytes = 0;
  2897. ULONG ulBytesNeeded;
  2898. ULONG ulInstallNeeded;
  2899. TCHAR achOldPath[MAX_PATH];
  2900. WORD idxSize;
  2901. DWORD idxdwClusterSize = 0;
  2902. TCHAR szDrv[6];
  2903. DWORD dwMaxCompLen;
  2904. DWORD dwVolFlags;
  2905. ASSERT( szPath );
  2906. if ( chkType == CHK_REQDSK_NONE )
  2907. return TRUE;
  2908. GetCurrentDirectory( sizeof(achOldPath), achOldPath );
  2909. if ( ! SetCurrentDirectory( szPath ) ) {
  2910. ErrorMsg( NULL, IDS_ERR_CHANGE_DIR );
  2911. g_dwExitCode = MyGetLastError();
  2912. return FALSE;
  2913. }
  2914. if ((dwFreeBytes=GetDrvFreeSpaceAndClusterSize(NULL, &dwClusterSize)) == 0)
  2915. {
  2916. TCHAR szMsg[MAX_STRING]={0};
  2917. g_dwExitCode = MyGetLastError();
  2918. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  2919. szMsg, sizeof(szMsg), NULL );
  2920. ErrorMsg2Param( NULL, IDS_ERR_GET_DISKSPACE, szPath, szMsg );
  2921. SetCurrentDirectory( achOldPath );
  2922. return( FALSE );
  2923. }
  2924. // find out if the drive is compressed
  2925. if ( !GetVolumeInformation( NULL, NULL, 0, NULL,
  2926. &dwMaxCompLen, &dwVolFlags, NULL, 0 ) )
  2927. {
  2928. TCHAR szMsg[MAX_STRING]={0};
  2929. g_dwExitCode = MyGetLastError();
  2930. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  2931. szMsg, sizeof(szMsg), NULL );
  2932. ErrorMsg2Param( NULL, IDS_ERR_GETVOLINFOR, szPath, szMsg );
  2933. SetCurrentDirectory( achOldPath );
  2934. return( FALSE );
  2935. }
  2936. SetCurrentDirectory( achOldPath );
  2937. lstrcpyn( szDrv, szPath, 3 );
  2938. ulBytesNeeded = 0;
  2939. idxdwClusterSize = CLUSTER_BASESIZE;
  2940. for ( idxSize=0; idxSize<MAX_NUMCLUSTERS; idxSize++ )
  2941. {
  2942. if ( dwClusterSize == idxdwClusterSize )
  2943. {
  2944. break;
  2945. }
  2946. idxdwClusterSize = idxdwClusterSize<<1;
  2947. }
  2948. if ( idxSize == MAX_NUMCLUSTERS )
  2949. {
  2950. ErrorMsg( NULL, IDS_ERR_UNKNOWN_CLUSTER );
  2951. return( FALSE );
  2952. }
  2953. if ( (g_Sess.uExtractOpt & EXTRACTOPT_COMPRESSED) &&
  2954. ( dwVolFlags & FS_VOL_IS_COMPRESSED ) )
  2955. {
  2956. ulBytesNeeded = (ULONG)(g_dwFileSizes[idxSize]*COMPRESS_FACTOR);
  2957. ulInstallNeeded = (ULONG)(g_Sess.cbPackInstSize + g_Sess.cbPackInstSize/4);
  2958. }
  2959. else
  2960. {
  2961. ulBytesNeeded = (ULONG)g_dwFileSizes[idxSize];
  2962. ulInstallNeeded = (ULONG)g_Sess.cbPackInstSize;
  2963. }
  2964. if ( (chkType & CHK_REQDSK_EXTRACT) && (chkType & CHK_REQDSK_INST) )
  2965. {
  2966. if ( (ulBytesNeeded + ulInstallNeeded) > (ULONG) dwFreeBytes )
  2967. {
  2968. return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) );
  2969. }
  2970. }
  2971. else if ( chkType & CHK_REQDSK_EXTRACT )
  2972. {
  2973. if ( ulBytesNeeded > (ULONG) dwFreeBytes )
  2974. {
  2975. return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) );
  2976. }
  2977. }
  2978. else
  2979. {
  2980. if ( ulInstallNeeded > (ULONG)dwFreeBytes )
  2981. {
  2982. return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) );
  2983. }
  2984. }
  2985. // PATH GOOD AND SPACE AVAILABLE!
  2986. g_dwExitCode = S_OK;
  2987. return TRUE;
  2988. }
  2989. BOOL RemoveLeadTailBlanks( LPSTR szBuf, int *startIdx )
  2990. {
  2991. int i=0, j=0;
  2992. while ( (szBuf[i] != 0) && IsSpace(szBuf[i]) )
  2993. i++;
  2994. if ( szBuf[i] == 0 )
  2995. {
  2996. return FALSE;
  2997. }
  2998. j = lstrlen(&szBuf[i]) - 1;
  2999. while ( j>=0 && IsSpace( szBuf[j+i] ) )
  3000. j--;
  3001. szBuf[j+i+1] = '\0';
  3002. *startIdx = i;
  3003. return TRUE;
  3004. }
  3005. //***************************************************************************
  3006. //* *
  3007. //* ParseCmdLine() *
  3008. //* *
  3009. //* Purpose: Parses the command line looking for switches *
  3010. //* *
  3011. //* Parameters: LPSTR lpszCmdLineOrg - Original command line *
  3012. //* *
  3013. //* *
  3014. //* Return: (BOOL) TRUE if successful *
  3015. //* FALSE if an error occurs *
  3016. //* *
  3017. //***************************************************************************
  3018. BOOL ParseCmdLine( LPCTSTR lpszCmdLineOrg )
  3019. {
  3020. LPCTSTR pLine, pArg;
  3021. char szTmpBuf[MAX_PATH];
  3022. int i,j;
  3023. LPTSTR lpTmp;
  3024. BOOL bRet = TRUE;
  3025. BOOL bLeftQ, bRightQ;
  3026. // If we have no command line, then return. It is
  3027. // OK to have no command line. CFGTMP is created
  3028. // with standard files
  3029. if( (!lpszCmdLineOrg) || (lpszCmdLineOrg[0] == 0) )
  3030. return TRUE;
  3031. // Loop through command line
  3032. pLine = lpszCmdLineOrg;
  3033. while ( (*pLine != EOL) && bRet )
  3034. {
  3035. // Move to first non-white char.
  3036. pArg = pLine;
  3037. while ( IsSpace( (int) *pArg ) )
  3038. pArg = CharNext (pArg);
  3039. if( *pArg == EOL )
  3040. break;
  3041. // Move to next white char.
  3042. pLine = pArg;
  3043. i = 0;
  3044. bLeftQ = FALSE;
  3045. bRightQ = FALSE;
  3046. while ( (*pLine != EOL) && ( (!bLeftQ && (!IsSpace(*pLine))) || (bLeftQ && (!bRightQ) )) )
  3047. {
  3048. if ( *pLine == '"')
  3049. {
  3050. switch ( *(pLine + 1) )
  3051. {
  3052. case '"':
  3053. if(i + 1 < sizeof(szTmpBuf) / sizeof(szTmpBuf[0]))
  3054. {
  3055. szTmpBuf[i++] = *pLine++;
  3056. pLine++;
  3057. }
  3058. else
  3059. {
  3060. return FALSE;
  3061. }
  3062. break;
  3063. default:
  3064. if ( !bLeftQ )
  3065. bLeftQ = TRUE;
  3066. else
  3067. bRightQ = TRUE;
  3068. pLine++;
  3069. break;
  3070. }
  3071. }
  3072. else
  3073. {
  3074. if(i + 1 < sizeof(szTmpBuf) / sizeof(szTmpBuf[0]))
  3075. {
  3076. szTmpBuf[i++] = *pLine++;
  3077. }
  3078. else
  3079. {
  3080. return FALSE;
  3081. }
  3082. }
  3083. }
  3084. szTmpBuf[i] = '\0';
  3085. // make sure the " " are in paires
  3086. if ( (bLeftQ && bRightQ) || (!bLeftQ) && (!bRightQ) )
  3087. ;
  3088. else
  3089. {
  3090. bRet = FALSE;
  3091. break;
  3092. }
  3093. if( szTmpBuf[0] != CMD_CHAR1 && szTmpBuf[0] != CMD_CHAR2 )
  3094. {
  3095. // cmdline comand starting with either '/' or '-'
  3096. return FALSE;
  3097. }
  3098. // Look for other switches
  3099. switch( (CHAR)CharUpper((PSTR)szTmpBuf[1]) )
  3100. {
  3101. case 'Q':
  3102. if (szTmpBuf[2] == 0 )
  3103. g_CMD.wQuietMode = QUIETMODE_USER;
  3104. //g_CMD.wQuietMode = QUIETMODE_ALL;
  3105. else if ( szTmpBuf[2] == ':')
  3106. {
  3107. switch ( (CHAR)CharUpper((PSTR)szTmpBuf[3]) )
  3108. {
  3109. case 'U':
  3110. case '1':
  3111. g_CMD.wQuietMode = QUIETMODE_USER;
  3112. break;
  3113. case 'A':
  3114. g_CMD.wQuietMode = QUIETMODE_ALL;
  3115. break;
  3116. default:
  3117. bRet = FALSE;
  3118. break;
  3119. }
  3120. }
  3121. else
  3122. bRet = FALSE;
  3123. break;
  3124. case 'T':
  3125. case 'D':
  3126. if ( szTmpBuf[2] == ':' )
  3127. {
  3128. PSTR pszPath;
  3129. if ( szTmpBuf[3] == '"' )
  3130. i = 4;
  3131. else
  3132. i = 3;
  3133. if ( !lstrlen(&szTmpBuf[i]) )
  3134. {
  3135. bRet = FALSE;
  3136. break;
  3137. }
  3138. else
  3139. {
  3140. j = i;
  3141. if (!RemoveLeadTailBlanks( &szTmpBuf[i], &j ) )
  3142. {
  3143. bRet = FALSE;
  3144. break;
  3145. }
  3146. if ( (CHAR)CharUpper((PSTR)szTmpBuf[1]) == 'T' )
  3147. {
  3148. lstrcpy( g_CMD.szUserTempDir, &szTmpBuf[i+j] );
  3149. AddPath( g_CMD.szUserTempDir, "" );
  3150. pszPath = g_CMD.szUserTempDir;
  3151. }
  3152. else
  3153. {
  3154. lstrcpy( g_CMD.szRunonceDelDir, &szTmpBuf[i+j] );
  3155. AddPath( g_CMD.szRunonceDelDir, "" );
  3156. pszPath = g_CMD.szRunonceDelDir;
  3157. }
  3158. // make sure it is full path
  3159. if ( !IsFullPath(pszPath) )
  3160. return FALSE;
  3161. }
  3162. }
  3163. else
  3164. bRet = FALSE;
  3165. break;
  3166. case 'C':
  3167. if ( szTmpBuf[2] == 0 )
  3168. {
  3169. g_CMD.fUserBlankCmd = TRUE;
  3170. }
  3171. else if ( szTmpBuf[2] == ':' )
  3172. {
  3173. if ( szTmpBuf[3] == '"' )
  3174. i = 4;
  3175. else
  3176. i = 3;
  3177. if ( !lstrlen(&szTmpBuf[i]) )
  3178. {
  3179. bRet = FALSE;
  3180. break;
  3181. }
  3182. else
  3183. {
  3184. // just make sure [] paires right
  3185. //
  3186. if ( ANSIStrChr( &szTmpBuf[i], '[' ) && (!ANSIStrChr( &szTmpBuf[i], ']' )) ||
  3187. ANSIStrChr( &szTmpBuf[i], ']' ) && (!ANSIStrChr( &szTmpBuf[i], '[' )) )
  3188. {
  3189. bRet = FALSE;
  3190. break;
  3191. }
  3192. j = i;
  3193. if (!RemoveLeadTailBlanks( &szTmpBuf[i], &j ) )
  3194. {
  3195. bRet = FALSE;
  3196. break;
  3197. }
  3198. lstrcpy( g_CMD.szUserCmd, &szTmpBuf[i+j] );
  3199. }
  3200. }
  3201. else
  3202. bRet = FALSE;
  3203. break;
  3204. case 'R':
  3205. if (szTmpBuf[2] == 0 )
  3206. {
  3207. g_Sess.dwReboot = REBOOT_YES | REBOOT_ALWAYS;
  3208. g_CMD.fUserReboot = TRUE;
  3209. }
  3210. else if ( szTmpBuf[2] == ':')
  3211. {
  3212. g_Sess.dwReboot = REBOOT_YES;
  3213. i = 3;
  3214. while ( szTmpBuf[i] != 0 )
  3215. {
  3216. switch ( (CHAR)CharUpper((PSTR)szTmpBuf[i++]) )
  3217. {
  3218. case 'N':
  3219. g_Sess.dwReboot &= ~(REBOOT_YES);
  3220. g_CMD.fUserReboot = TRUE;
  3221. break;
  3222. case 'I':
  3223. g_Sess.dwReboot &= ~(REBOOT_ALWAYS);
  3224. g_CMD.fUserReboot = TRUE;
  3225. break;
  3226. case 'A':
  3227. g_Sess.dwReboot |= REBOOT_ALWAYS;
  3228. g_CMD.fUserReboot = TRUE;
  3229. break;
  3230. case 'S':
  3231. g_Sess.dwReboot |= REBOOT_SILENT;
  3232. g_CMD.fUserReboot = TRUE;
  3233. break;
  3234. case 'D':
  3235. g_CMD.dwFlags |= CMDL_DELAYREBOOT;
  3236. break;
  3237. case 'P':
  3238. g_CMD.dwFlags |= CMDL_DELAYPOSTCMD;
  3239. break;
  3240. default:
  3241. bRet = FALSE;
  3242. break;
  3243. }
  3244. }
  3245. }
  3246. else if ( !lstrcmpi( CMD_REGSERV, &szTmpBuf[1] ) )
  3247. {
  3248. break; //ignore
  3249. }
  3250. else
  3251. {
  3252. bRet = FALSE;
  3253. break;
  3254. }
  3255. break;
  3256. case 'N':
  3257. if (szTmpBuf[2] == 0 )
  3258. g_CMD.fNoExtracting = TRUE;
  3259. else if ( szTmpBuf[2] == ':')
  3260. {
  3261. i = 3;
  3262. while ( szTmpBuf[i] != 0 )
  3263. {
  3264. switch ( (CHAR)CharUpper((PSTR)szTmpBuf[i++]) )
  3265. {
  3266. case 'G':
  3267. g_CMD.fNoGrpConv = TRUE;
  3268. break;
  3269. case 'E':
  3270. g_CMD.fNoExtracting = TRUE;
  3271. break;
  3272. case 'V':
  3273. g_CMD.fNoVersionCheck = TRUE;
  3274. break;
  3275. default:
  3276. bRet = FALSE;
  3277. break;
  3278. }
  3279. }
  3280. }
  3281. else
  3282. bRet = FALSE;
  3283. break;
  3284. case '?': // Help
  3285. DisplayHelp();
  3286. if (g_hMutex)
  3287. CloseHandle(g_hMutex);
  3288. ExitProcess(0);
  3289. default:
  3290. bRet = FALSE;
  3291. break;
  3292. }
  3293. }
  3294. if ( g_CMD.fNoExtracting && (g_CMD.szUserTempDir[0]==0) )
  3295. {
  3296. if ( GetModuleFileName( g_hInst, g_CMD.szUserTempDir, (DWORD)sizeof(g_CMD.szUserTempDir) ) )
  3297. {
  3298. lpTmp= ANSIStrRChr(g_CMD.szUserTempDir, '\\') ;
  3299. *(lpTmp+1) = '\0' ;
  3300. }
  3301. else
  3302. bRet = FALSE ;
  3303. }
  3304. return bRet;
  3305. }
  3306. // check windows drive disk space
  3307. //
  3308. BOOL CheckWinDir()
  3309. {
  3310. TCHAR szWinDrv[MAX_PATH];
  3311. if ( !GetWindowsDirectory( szWinDrv, MAX_PATH ) )
  3312. {
  3313. ErrorMsg( NULL, IDS_ERR_GET_WIN_DIR );
  3314. g_dwExitCode = MyGetLastError();
  3315. return FALSE;
  3316. }
  3317. return ( IsEnoughSpace( szWinDrv, CHK_REQDSK_INST, MSG_REQDSK_WARN ) );
  3318. }
  3319. // get the last error and map it to HRESULT
  3320. //
  3321. DWORD MyGetLastError()
  3322. {
  3323. return HRESULT_FROM_WIN32( GetLastError() );
  3324. }
  3325. //***************************************************************************
  3326. //* *
  3327. //* NAME: TravelUpdatedFiles *
  3328. //* *
  3329. //* SYNOPSIS: *
  3330. //* *
  3331. //* REQUIRES: Nothing *
  3332. //* *
  3333. //* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
  3334. //* *
  3335. //***************************************************************************
  3336. BOOL TravelUpdatedFiles( pfuncPROCESS_UPDATED_FILE pProcessUpdatedFile )
  3337. {
  3338. DWORD dwFileSize = 0;
  3339. DWORD dwReserved = 0;
  3340. PSTR pszFilename = NULL;
  3341. PSTR pszFileContents = NULL;
  3342. TCHAR szResName[20];
  3343. DWORD dwResNum = 0;
  3344. HANDLE hRes = NULL;
  3345. HRSRC hRsrc = NULL;
  3346. BOOL fReturnCode = TRUE;
  3347. static const TCHAR c_szResNameTemplate[] = "UPDFILE%lu";
  3348. for ( dwResNum = 0; ; dwResNum += 1 ) {
  3349. wsprintf( szResName, c_szResNameTemplate, dwResNum );
  3350. hRsrc = FindResource( NULL, szResName, RT_RCDATA );
  3351. if ( hRsrc == NULL ) {
  3352. break;
  3353. }
  3354. hRes = LockResource( LoadResource( NULL, hRsrc ) );
  3355. if ( hRes == NULL ) {
  3356. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  3357. fReturnCode = FALSE;
  3358. goto done;
  3359. }
  3360. dwFileSize = *((PDWORD)hRes);
  3361. dwReserved = *((PDWORD)(((PDWORD)hRes)+1));
  3362. pszFilename = (PSTR) (((PSTR)hRes)+(2*sizeof(DWORD)));
  3363. pszFileContents = (PSTR) (pszFilename + lstrlen(pszFilename) + 1);
  3364. if ( !pProcessUpdatedFile( dwFileSize, dwReserved, pszFilename, pszFileContents ) )
  3365. {
  3366. // g_dwExitCode is set in pProcessUpdatedFile()
  3367. fReturnCode = FALSE;
  3368. FreeResource( hRes );
  3369. goto done;
  3370. }
  3371. FreeResource( hRes );
  3372. }
  3373. done:
  3374. return fReturnCode;
  3375. }
  3376. //***************************************************************************
  3377. //* *
  3378. //* NAME: ProcessUpdatedFile_Size *
  3379. //* *
  3380. //* SYNOPSIS: *
  3381. //* *
  3382. //* REQUIRES: Nothing *
  3383. //* *
  3384. //* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
  3385. //* *
  3386. //***************************************************************************
  3387. BOOL ProcessUpdatedFile_Size( DWORD dwFileSize, DWORD dwReserved,
  3388. PCSTR c_pszFilename, PCSTR c_pszFileContents )
  3389. {
  3390. DWORD clusterCurrSize = 0;
  3391. DWORD i = 0;
  3392. #if 0
  3393. if (g_Sess.cbPackInstSize != 0 ) {
  3394. g_Sess.cbPackInstSize += dwFileSize;
  3395. }
  3396. #endif
  3397. // calculate the file size in different cluster sizes
  3398. clusterCurrSize = CLUSTER_BASESIZE;
  3399. for ( i = 0; i < MAX_NUMCLUSTERS; i += 1 ) {
  3400. g_dwFileSizes[i] += ((dwFileSize/clusterCurrSize)*clusterCurrSize +
  3401. (dwFileSize%clusterCurrSize?clusterCurrSize : 0));
  3402. clusterCurrSize = (clusterCurrSize<<1);
  3403. }
  3404. return TRUE;
  3405. }
  3406. //***************************************************************************
  3407. //* *
  3408. //* NAME: ProcessUpdatedFile_Write *
  3409. //* *
  3410. //* SYNOPSIS: *
  3411. //* *
  3412. //* REQUIRES: Nothing *
  3413. //* *
  3414. //* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
  3415. //* *
  3416. //***************************************************************************
  3417. BOOL ProcessUpdatedFile_Write( DWORD dwFileSize, DWORD dwReserved,
  3418. PCSTR c_pszFilename, PCSTR c_pszFileContents )
  3419. {
  3420. HANDLE hFile = INVALID_HANDLE_VALUE;
  3421. BOOL fSuccess = TRUE;
  3422. DWORD dwBytesWritten = 0;
  3423. TCHAR szFullFilename[MAX_PATH];
  3424. lstrcpy( szFullFilename, g_Sess.achDestDir );
  3425. AddPath( szFullFilename, c_pszFilename );
  3426. hFile = CreateFile( szFullFilename, GENERIC_WRITE, 0, NULL,
  3427. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  3428. if ( hFile == INVALID_HANDLE_VALUE ) {
  3429. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE);
  3430. fSuccess = FALSE;
  3431. goto done;
  3432. }
  3433. if ( ! WriteFile( hFile, c_pszFileContents, dwFileSize, &dwBytesWritten, NULL )
  3434. || dwFileSize != dwBytesWritten )
  3435. {
  3436. g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE);
  3437. fSuccess = FALSE;
  3438. goto done;
  3439. }
  3440. done:
  3441. if ( hFile != INVALID_HANDLE_VALUE ) {
  3442. CloseHandle( hFile );
  3443. }
  3444. return fSuccess;
  3445. }
  3446. HINSTANCE MyLoadLibrary( LPTSTR lpFile )
  3447. {
  3448. TCHAR szPath[MAX_PATH];
  3449. DWORD dwAttr;
  3450. HINSTANCE hFile;
  3451. lstrcpy( szPath, g_Sess.achDestDir );
  3452. AddPath( szPath, lpFile );
  3453. if ( ((dwAttr=GetFileAttributes( szPath )) != -1) &&
  3454. !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) )
  3455. {
  3456. hFile = LoadLibraryEx( szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  3457. }
  3458. else
  3459. {
  3460. hFile = LoadLibrary( lpFile );
  3461. }
  3462. return hFile;
  3463. }
  3464. INT_PTR MyDialogBox( HANDLE hInst, LPCTSTR pTemplate, HWND hWnd, DLGPROC lpProc, LPARAM lpParam, INT_PTR idefRet )
  3465. {
  3466. INT_PTR iDlgRc = -1;
  3467. HRSRC hDlgRc;
  3468. HGLOBAL hMemDlg;
  3469. hDlgRc = FindResource( hInst, pTemplate, RT_DIALOG );
  3470. if ( hDlgRc )
  3471. {
  3472. hMemDlg = LoadResource( hInst, hDlgRc );
  3473. if ( hMemDlg )
  3474. {
  3475. if ( !lpParam )
  3476. iDlgRc = DialogBoxIndirect( hInst, hMemDlg, hWnd, lpProc );
  3477. else
  3478. iDlgRc = DialogBoxIndirectParam( hInst, hMemDlg, hWnd, lpProc, lpParam );
  3479. FreeResource( hMemDlg );
  3480. }
  3481. }
  3482. if ( iDlgRc == (INT_PTR)-1 )
  3483. {
  3484. ErrorMsg( NULL, IDS_ERR_DIALOGBOX );
  3485. iDlgRc = idefRet;
  3486. }
  3487. return iDlgRc;
  3488. }
  3489. /* these are here to avoid linking QDI */
  3490. void * __cdecl QDICreateDecompression(void)
  3491. {
  3492. return(NULL);
  3493. }
  3494. void __cdecl QDIDecompress(void)
  3495. {
  3496. }
  3497. void __cdecl QDIResetDecompression(void)
  3498. {
  3499. }
  3500. void __cdecl QDIDestroyDecompression(void)
  3501. {
  3502. }
  3503. /* these are here to avoid linking MDI */
  3504. void* __cdecl MDICreateDecompression(void)
  3505. {
  3506. return(NULL);
  3507. }
  3508. void __cdecl MDIDecompress(void)
  3509. {
  3510. }
  3511. void __cdecl MDIResetDecompression(void)
  3512. {
  3513. }
  3514. void __cdecl MDIDestroyDecompression(void)
  3515. {
  3516. }