|
|
//***************************************************************************
//* Copyright (c) Microsoft Corporation 1995. All rights reserved. *
//***************************************************************************
//* *
//* WEXTRACT.C - Win32 Based Cabinet File Self-extractor and installer. *
//* *
//***************************************************************************
//***************************************************************************
//* INCLUDE FILES *
//***************************************************************************
#include "pch.h"
#pragma hdrstop
#include "wextract.h"
#include "sdsutils.h"
//***************************************************************************
//* GLOBAL VARIABLES *
//***************************************************************************
FAKEFILE g_FileTable[FILETABLESIZE]; // File Table
SESSION g_Sess; // Session
WORD g_wOSVer; BOOL g_fOSSupportsFullUI = TRUE; // Minimal UI for NT3.5
BOOL g_fOSSupportsINFInstalls = TRUE; // TRUE if INF installs are allowed
// on the target platform.
HANDLE g_hInst; LPSTR g_szLicense; HWND g_hwndExtractDlg = NULL; DWORD g_dwFileSizes[MAX_NUMCLUSTERS+1]; FARPROC g_lpfnOldMEditWndProc; UINT g_uInfRebootOn; CMDLINE_DATA g_CMD; DWORD g_dwRebootCheck; int g_dwExitCode; HANDLE g_hCancelEvent = NULL; HANDLE g_hMutex = NULL; char g_szBrowsePath[MAX_PATH];
#define CMD_REGSERV "RegServer"
#define COMPRESS_FACTOR 2
#define SIZE_100MB 102400
int _stdcall ModuleEntry(void) { int i; STARTUPINFO si; LPSTR pszCmdLine = GetCommandLine();
if ( *pszCmdLine == '\"' ) { /*
* Scan, and skip over, subsequent characters until * another double-quote or a null is encountered. */ while ( *++pszCmdLine && (*pszCmdLine != '\"') ); /*
* If we stopped on a double-quote (usual case), skip * over it. */ if ( *pszCmdLine == '\"' ) pszCmdLine++; } else { while (*pszCmdLine > ' ') pszCmdLine++; }
/*
* Skip past any white space preceeding the second token. */ while (*pszCmdLine && (*pszCmdLine <= ' ')) { pszCmdLine++; }
si.dwFlags = 0; GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine, si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT); ExitProcess(i); return i; // We never comes here.
}
//***************************************************************************
//* *
//* NAME: WinMain *
//* *
//* SYNOPSIS: Main entry point for the program. *
//* *
//* REQUIRES: hInstance: *
//* hPrevInstance: *
//* lpszCmdLine: *
//* nCmdShow: *
//* *
//* RETURNS: int: *
//* *
//***************************************************************************
INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, INT nCmdShow ) { BOOL fReturn = FALSE; // initailize to SUCCESS return
// this value is updated inside DoMain() ..
//
g_dwExitCode = S_OK; if ( Init( hInstance, lpszCmdLine, nCmdShow ) ) { fReturn = DoMain(); CleanUp(); }
if ( fReturn ) { // get reboot info
if ( !(g_CMD.szRunonceDelDir[0]) && (g_Sess.dwReboot & REBOOT_YES) ) { MyRestartDialog( g_Sess.dwReboot ); } }
// BUGBUG: ParseCommandLine() seems to use exit() directly.
// one other exit of this EXE will be at /? case in parsecmdline
// so we do close there if not NULL.
//
if (g_hMutex) CloseHandle(g_hMutex);
return g_dwExitCode; }
//***************************************************************************
//* *
//* NAME: Init *
//* *
//* SYNOPSIS: Initialization for the program is done here. *
//* *
//* REQUIRES: hInstance: *
//* hPrevInstance: *
//* lpszCmdLine: *
//* nCmdShow: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
BOOL Init( HINSTANCE hInstance, LPCTSTR lpszCmdLine, INT nCmdShow ) { DWORD dwSize; PTARGETVERINFO pTargetVer = NULL; HRSRC hRc; HGLOBAL hMemVer;
g_hInst = hInstance;
ZeroMemory( &g_Sess, sizeof(g_Sess) ); ZeroMemory( &g_CMD, sizeof(g_CMD) ); ZeroMemory( g_szBrowsePath, sizeof(g_szBrowsePath) );
// Initialize the structure
g_Sess.fAllCabinets = TRUE;
// Get Application Title Name
dwSize = GetResource( achResTitle, g_Sess.achTitle, sizeof(g_Sess.achTitle) - 1 );
if ( dwSize == 0 || dwSize > sizeof(g_Sess.achTitle) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); return FALSE; }
g_hCancelEvent = CreateEvent( NULL, TRUE, TRUE, NULL ); SetEvent( g_hCancelEvent );
if ( !GetResource( achResExtractOpt, &(g_Sess.uExtractOpt), sizeof(g_Sess.uExtractOpt) ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKPROMPT ) || ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKBLOCK ) ) { char szCookie[MAX_PATH];
if ( !GetResource( achResOneInstCheck, szCookie, sizeof(szCookie) ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
g_hMutex = CreateMutex(NULL, TRUE, szCookie ); if ((g_hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { if ( g_Sess.uExtractOpt & EXTRACTOPT_INSTCHKBLOCK ) { ErrorMsg1Param( NULL, IDS_ERR_ALREADY_RUNNING, g_Sess.achTitle ); } else if ( MsgBox1Param( NULL, IDS_MULTIINST, g_Sess.achTitle, MB_ICONQUESTION, MB_YESNO) == IDYES ) { goto CONTINUE; } CloseHandle(g_hMutex); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); return FALSE; } }
CONTINUE: g_uInfRebootOn = 0;
if ( !ParseCmdLine(lpszCmdLine) ) { ErrorMsg( NULL, IDS_ERR_BADCMDLINE ); return FALSE; }
// if this is runoncde called for cleanup only purpose, clenup and return
if ( g_CMD.szRunonceDelDir[0] ) { DeleteMyDir( g_CMD.szRunonceDelDir ); return FALSE; }
hRc = FindResource( hInstance, achResVerCheck, RT_RCDATA );
if ( hRc ) { hMemVer = LoadResource( hInstance, hRc ); pTargetVer = (PTARGETVERINFO) hMemVer; }
if ( g_fOSSupportsFullUI ) { // Allow Use of Progress Bar
InitCommonControls(); }
// if user want to extract files only with /C command switch, no further check is needed!
// If package is built for extract only, checks are needed!
if ( g_CMD.fUserBlankCmd ) { return TRUE; }
if ( !CheckOSVersion( pTargetVer ) ) { return FALSE; }
// Check for Administrator rights on NT
// Don't do the check if this is quiet mode. This
// will probably change when we add support in cabpack
// to make this check or not
if( ((g_wOSVer == _OSVER_WINNT3X) || (g_wOSVer == _OSVER_WINNT40) || (g_wOSVer == _OSVER_WINNT50)) && ( g_Sess.uExtractOpt & EXTRACTOPT_CHKADMRIGHT ) && !( g_CMD.wQuietMode & QUIETMODE_ALL ) ) { if(!IsNTAdmin()) { if(MyDialogBox(g_hInst, MAKEINTRESOURCE(IDD_WARNING), NULL, WarningDlgProc, IDS_NOTADMIN, (INT_PTR)IDC_EXIT) != (INT_PTR)IDC_CONTINUE) return FALSE; } }
return TRUE; }
//***************************************************************************
//* *
//* NAME: DoMain *
//* *
//* SYNOPSIS: This is the main function that processes the package. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
BOOL DoMain( VOID ) { typedef BOOL (WINAPI *DECRYPTFILEAPTR)(LPCSTR, DWORD); HINSTANCE hAdvapi32; DECRYPTFILEAPTR DecryptFileAPtr = NULL; char szPath[MAX_PATH + 1];
// If a prompt is defined, then pop it up in a message box
// Display License file
// if cmdline option: /Q or /Q:1 or /Q:A or /Q:U is used, batch mode is on. No UI needed
if ( !g_CMD.wQuietMode && !g_CMD.fUserBlankCmd ) { if ( !GetUsersPermission() ) { return FALSE; }
}
if ( !g_CMD.wQuietMode ) { if ( !DisplayLicense() ) { return FALSE; }
}
// get package extracting size and install size resource
//
if ( ! GetFileList() ) { return FALSE; }
// Set Directory to Extract Into
if ( ! GetTempDirectory() ) { //ErrorMsg( NULL, IDS_ERR_FIND_TEMP );
return FALSE; }
//
// Try to turn off encryption on the directory (winseraid #23464.)
//
GetSystemDirectory(szPath, sizeof(szPath)); AddPath(szPath, "advapi32.dll"); hAdvapi32 = LoadLibrary(szPath);
if ( hAdvapi32 ) { DecryptFileAPtr = (DECRYPTFILEAPTR)GetProcAddress( hAdvapi32, "DecryptFileA" );
if ( DecryptFileAPtr ) DecryptFileAPtr( g_Sess.achDestDir, 0 ); }
FreeLibrary(hAdvapi32);
// check if windows dir has enough space for install,
//
if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly && !CheckWinDir() ) { return FALSE; }
// Change to that directory
if ( ! SetCurrentDirectory( g_Sess.achDestDir ) ) { ErrorMsg( NULL, IDS_ERR_CHANGE_DIR ); g_dwExitCode = MyGetLastError(); return FALSE; }
// Extract the files
if ( !g_CMD.fNoExtracting ) { if ( ! ExtractFiles() ) { return FALSE; } }
if ( (g_CMD.dwFlags & CMDL_DELAYREBOOT) || (g_CMD.dwFlags & CMDL_DELAYPOSTCMD) ) g_dwRebootCheck = 0; else g_dwRebootCheck = NeedRebootInit(g_wOSVer); // Install using the specified installation command
// if not Command option, check if user op-out run command
if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly ) { if ( ! RunInstallCommand() ) { return FALSE; } }
// Popup a message that it has finished
if ( !g_CMD.wQuietMode && !g_CMD.fUserBlankCmd ) { FinishMessage(); }
return TRUE; }
//***************************************************************************
//* *
//* NAME: CleanUp *
//* *
//* SYNOPSIS: Any last-minute application cleanup activities. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
VOID CleanUp( VOID ) { // Delete extracted files - will do nothing if no files extracted
DeleteExtractedFiles(); }
//***************************************************************************
//* *
//* NAME: MEditSubClassWnd *
//* *
//* SYNOPSIS: Subclasses a multiline edit control so that a edit message *
//* to select the entire contents is ignored. *
//* *
//* REQUIRES: hWnd: Handle of the edit window *
//* fnNewProc: New window handler proc *
//* lpfnOldProc: (returns) Old window handler proc *
//* *
//* RETURNS: Nothing *
//* *
//* NOTE: A selected edit message is not generated when the user *
//* selects text with the keyboard or mouse. *
//* *
//***************************************************************************
VOID NEAR PASCAL MEditSubClassWnd( HWND hWnd, FARPROC fnNewProc ) { g_lpfnOldMEditWndProc = (FARPROC) GetWindowLongPtr( hWnd, GWLP_WNDPROC );
SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR) MakeProcInstance( fnNewProc, (HINSTANCE) GetWindowWord( hWnd, GWW_HINSTANCE ) ) ); }
//***************************************************************************
//* *
//* NAME: MEditSubProc *
//* *
//* SYNOPSIS: New multiline edit window procedure to ignore selection of *
//* all contents. *
//* *
//* REQUIRES: hWnd: *
//* msg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: LONG: *
//* *
//* NOTE: A selected edit message is not generated when the user *
//* selects text with the keyboard or mouse. *
//* *
//***************************************************************************
LRESULT CALLBACK MEditSubProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { if ( msg == EM_SETSEL ) { if ( wParam == 0 && lParam == -2 ) { return 0; } }
return CallWindowProc( (WNDPROC) g_lpfnOldMEditWndProc, hWnd, msg, wParam, lParam ); }
//***************************************************************************
//* *
//* NAME: LicenseDlgProc *
//* *
//* SYNOPSIS: Dialog Procedure for our license dialog window. *
//* *
//* REQUIRES: hwndDlg: *
//* uMsg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
INT_PTR CALLBACK LicenseDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static LRESULT RC; static BOOL fSetSel = FALSE; static TCHAR achMessage[MSG_MAX];
switch (uMsg) {
//*********************************************************************
case WM_INITDIALOG: //*********************************************************************
CenterWindow( hwndDlg, GetDesktopWindow() ); SetDlgItemText( hwndDlg, IDC_EDIT_LICENSE, g_szLicense ); SetWindowText( hwndDlg, g_Sess.achTitle ); SetForegroundWindow( hwndDlg );
// Subclass the multiline edit control.
MEditSubClassWnd( GetDlgItem( hwndDlg, IDC_EDIT_LICENSE ), (FARPROC) MEditSubProc );
return TRUE;
//*********************************************************************
case WM_PAINT: //*********************************************************************
// For some reason, the EM_SETSEL message doesn't work when sent
// from within WM_INITDIALOG. That's why this hack of using a
// flag and putting it in the WM_PAINT is used.
if ( ! fSetSel ) { RC = SendDlgItemMessage( hwndDlg, IDC_EDIT_LICENSE, EM_SETSEL, (WPARAM) -1, (LPARAM) 0 ); fSetSel = TRUE; }
return FALSE;
//*********************************************************************
case WM_CLOSE: //*********************************************************************
EndDialog( hwndDlg, FALSE ); return TRUE;
//*********************************************************************
case WM_COMMAND: //*********************************************************************
if (wParam == IDYES) { EndDialog( hwndDlg, TRUE ); } else if (wParam == IDNO) { EndDialog( hwndDlg, FALSE ); }
return TRUE; }
return FALSE; }
//***************************************************************************
//* *
//* NAME: IsFullPath *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// return TRUE if given path is FULL pathname
//
BOOL IsFullPath( LPSTR pszPath ) { if ( (pszPath == NULL) || (lstrlen(pszPath) < 3) ) { return FALSE; }
if ( (pszPath[1] == ':') || ((pszPath[0] == '\\') && (pszPath[1]=='\\') ) ) return TRUE; else return FALSE; }
//***************************************************************************
//* *
//* NAME: TempDirDlgProc *
//* *
//* SYNOPSIS: Dialog Procedure for our temporary dir dialog window. *
//* *
//* REQUIRES: hwndDlg: *
//* uMsg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
INT_PTR CALLBACK TempDirDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static TCHAR achDir[MAX_PATH]; static TCHAR achMsg[MSG_MAX];
switch (uMsg) {
//*********************************************************************
case WM_INITDIALOG: //*********************************************************************
{
CenterWindow( hwndDlg, GetDesktopWindow() ); SetWindowText( hwndDlg, g_Sess.achTitle );
SendDlgItemMessage( hwndDlg, IDC_EDIT_TEMPDIR, EM_SETLIMITTEXT, (sizeof(g_Sess.achDestDir)-1), 0 ); // if ( ( g_wOSVer == _OSVER_WINNT3X ) || ( g_wOSVer == _OSVER_WINNT40 ))
if ( ( g_wOSVer == _OSVER_WINNT3X ) ) { EnableWindow( GetDlgItem( hwndDlg, IDC_BUT_BROWSE ), FALSE ); } return TRUE; }
//*********************************************************************
case WM_CLOSE: //*********************************************************************
EndDialog( hwndDlg, FALSE ); return TRUE;
//*********************************************************************
case WM_COMMAND: //*********************************************************************
switch ( wParam ) {
//*************************************************************
case IDOK: //*************************************************************
{ DWORD dwAttribs = 0; UINT chkType;
if ( !GetDlgItemText( hwndDlg, IDC_EDIT_TEMPDIR, g_Sess.achDestDir, sizeof(g_Sess.achDestDir)) || !IsFullPath(g_Sess.achDestDir) ) { ErrorMsg( hwndDlg, IDS_ERR_EMPTY_DIR_FIELD ); return TRUE; }
dwAttribs = GetFileAttributes( g_Sess.achDestDir ); if ( dwAttribs == 0xFFFFFFFF ) { if ( MsgBox1Param( hwndDlg, IDS_CREATE_DIR, g_Sess.achDestDir, MB_ICONQUESTION, MB_YESNO ) == IDYES ) { if ( ! CreateDirectory( g_Sess.achDestDir, NULL ) ) { ErrorMsg1Param( hwndDlg, IDS_ERR_CREATE_DIR, g_Sess.achDestDir ); return TRUE; } } else return TRUE; } AddPath( g_Sess.achDestDir, "" );
if ( ! IsGoodTempDir( g_Sess.achDestDir ) ) { ErrorMsg( hwndDlg, IDS_ERR_INVALID_DIR ); return TRUE; }
if ( (g_Sess.achDestDir[0] == '\\') && (g_Sess.achDestDir[1] == '\\') ) chkType = CHK_REQDSK_NONE; else chkType = CHK_REQDSK_EXTRACT;
if ( ! IsEnoughSpace( g_Sess.achDestDir, chkType, MSG_REQDSK_ERROR ) ) { return TRUE; }
EndDialog( hwndDlg, TRUE ); return TRUE; }
//*************************************************************
case IDCANCEL: //*************************************************************
EndDialog( hwndDlg, FALSE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED); return TRUE;
//*************************************************************
case IDC_BUT_BROWSE: //*************************************************************
if ( LoadString( g_hInst, IDS_SELECTDIR, achMsg, sizeof(achMsg) ) == 0 ) { ErrorMsg( hwndDlg, IDS_ERR_NO_RESOURCE ); EndDialog( hwndDlg, FALSE ); return TRUE; }
if ( ! BrowseForDir( hwndDlg, achMsg, achDir ) ) { return TRUE; }
if ( ! SetDlgItemText( hwndDlg, IDC_EDIT_TEMPDIR, achDir ) ) { ErrorMsg( hwndDlg, IDS_ERR_UPDATE_DIR ); EndDialog( hwndDlg, FALSE ); return TRUE; }
return TRUE; }
return TRUE; }
return FALSE; }
//***************************************************************************
//* *
//* NAME: OverwriteDlgProc *
//* *
//* SYNOPSIS: Dialog Procedure for asking if file should be overwritten. *
//* *
//* REQUIRES: hwndDlg: *
//* uMsg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
INT_PTR CALLBACK OverwriteDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) {
//*********************************************************************
case WM_INITDIALOG: //*********************************************************************
CenterWindow( hwndDlg, GetDesktopWindow() ); SetWindowText( hwndDlg, g_Sess.achTitle ); SetDlgItemText( hwndDlg, IDC_TEXT_FILENAME,g_Sess.cszOverwriteFile ); SetForegroundWindow( hwndDlg ); return TRUE;
//*********************************************************************
case WM_CLOSE: //*********************************************************************
EndDialog( hwndDlg, IDCANCEL ); return TRUE;
//*********************************************************************
case WM_COMMAND: //*********************************************************************
switch ( wParam ) {
//*************************************************************
case IDC_BUT_YESTOALL: //*************************************************************
g_Sess.fOverwrite = TRUE;
//*************************************************************
case IDYES: case IDNO: //*************************************************************
EndDialog( hwndDlg, wParam ); return TRUE; } return TRUE; } return FALSE; }
//***************************************************************************
//* *
//* NAME: ExtractDlgProc *
//* *
//* SYNOPSIS: Dialog Procedure for our main dialog window. *
//* *
//* REQUIRES: hwndDlg: *
//* uMsg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
INT_PTR CALLBACK ExtractDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static DWORD dwThreadID; static HANDLE hExtractThread; static TCHAR achMessage[MSG_MAX];
switch (uMsg) {
//*********************************************************************
case WM_INITDIALOG: //*********************************************************************
g_hwndExtractDlg = hwndDlg;
CenterWindow( hwndDlg, GetDesktopWindow() );
if ( g_fOSSupportsFullUI ) { Animate_Open( GetDlgItem( hwndDlg, IDC_USER1 ), IDA_FILECOPY ); Animate_Play( GetDlgItem( hwndDlg, IDC_USER1 ), 0, -1, -1 ); }
SetWindowText( hwndDlg, g_Sess.achTitle );
// Launch Extraction Thread
hExtractThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) ExtractThread, NULL, 0, &dwThreadID );
if ( !hExtractThread ) { ErrorMsg( hwndDlg, IDS_ERR_CREATE_THREAD ); EndDialog( hwndDlg, FALSE ); }
return TRUE;
//*********************************************************************
case UM_EXTRACTDONE: //*********************************************************************
TerminateThread( hExtractThread, 0 ); EndDialog( hwndDlg, (BOOL) wParam ); return TRUE;
//*********************************************************************
case WM_CLOSE: //*********************************************************************
g_Sess.fCanceled = TRUE; EndDialog( hwndDlg, FALSE ); return TRUE;
//*********************************************************************
case WM_CHAR: //*********************************************************************
if ( wParam == VK_ESCAPE ) { g_Sess.fCanceled = TRUE; EndDialog( hwndDlg, FALSE ); }
return TRUE;
//*********************************************************************
case WM_COMMAND: //*********************************************************************
if ( wParam == IDCANCEL ) { int iMsgRet ;
ResetEvent( g_hCancelEvent );
iMsgRet = MsgBox1Param( g_hwndExtractDlg, IDS_ERR_USER_CANCEL, "", MB_ICONQUESTION, MB_YESNO ) ;
// We will get back IDOK if we are in /q:1 mode.
//
if ( (iMsgRet == IDYES) || (iMsgRet == IDOK) ) { g_Sess.fCanceled = TRUE; SetEvent( g_hCancelEvent ); WaitForObject( hExtractThread ); EndDialog( hwndDlg, FALSE ); return TRUE; }
SetEvent( g_hCancelEvent ); } return TRUE; }
return FALSE; }
//***************************************************************************
//* *
//* NAME: WaitForObject *
//* *
//* SYNOPSIS: Waits for an object while still dispatching messages. *
//* *
//* REQUIRES: Handle to the object. *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
VOID WaitForObject( HANDLE hObject ) { BOOL fDone = FALSE; DWORD dwRet = 0;
while ( ! fDone ) { dwRet = MsgWaitForMultipleObjects( 1, &hObject, FALSE, INFINITE, QS_ALLINPUT );
if ( dwRet == WAIT_OBJECT_0 ) { fDone = TRUE; } else { MSG msg;
// read all of the messages in this next loop
// removing each message as we read it
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { // if it's a quit message we're out of here
if ( msg.message == WM_QUIT ) { fDone = TRUE; } else { // otherwise dispatch it
DispatchMessage( &msg ); } // end of PeekMessage while loop
} } } }
//***************************************************************************
//* *
//* NAME: CheckOSVersion *
//* *
//* SYNOPSIS: Checks the OS version and sets some global variables. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
BOOL CheckOSVersion( PTARGETVERINFO ptargetVers ) { OSVERSIONINFO verinfo; // Version Check
UINT uErrid = 0; PVERCHECK pVerCheck; WORD CurrBld; int ifrAnswer[2], itoAnswer[2], i; char szPath[MAX_PATH];
// Operating System Version Check: For NT versions below 3.50 set flag to
// prevent use of common controls (progress bar and AVI) not available.
verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx( &verinfo ) == FALSE ) { uErrid = IDS_ERR_OS_VERSION; goto EXIT; }
switch( verinfo.dwPlatformId ) { case VER_PLATFORM_WIN32_WINDOWS: // Win95
// Accept for INF installs and Accept for animations
g_wOSVer = _OSVER_WIN9X; g_fOSSupportsFullUI = TRUE; g_fOSSupportsINFInstalls = TRUE; break;
case VER_PLATFORM_WIN32_NT: // Win NT
g_fOSSupportsFullUI = TRUE; g_fOSSupportsINFInstalls = TRUE; g_wOSVer = _OSVER_WINNT40;
if ( verinfo.dwMajorVersion <= 3 ) { g_wOSVer = _OSVER_WINNT3X; if ( (verinfo.dwMajorVersion < 3) || ((verinfo.dwMajorVersion == 3) && (verinfo.dwMinorVersion < 51 )) ) { // Reject for INF installs and Reject for animations
g_fOSSupportsFullUI = FALSE; g_fOSSupportsINFInstalls = FALSE; } } else if ( verinfo.dwMajorVersion >= 5 ) g_wOSVer = _OSVER_WINNT50; break;
default: uErrid = IDS_ERR_OS_UNSUPPORTED; goto EXIT; }
// check if the current OS/File versions
//
if ( !g_CMD.fNoVersionCheck && ptargetVers ) { if ( g_wOSVer == _OSVER_WIN9X ) pVerCheck = &(ptargetVers->win9xVerCheck); else pVerCheck = &(ptargetVers->ntVerCheck);
CurrBld = LOWORD( verinfo.dwBuildNumber ); for ( i=0; i<2; i++ ) { ifrAnswer[i] = CompareVersion( verinfo.dwMajorVersion, verinfo.dwMinorVersion, pVerCheck->vr[i].frVer.dwMV, pVerCheck->vr[i].frVer.dwLV ); itoAnswer[i] = CompareVersion( verinfo.dwMajorVersion, verinfo.dwMinorVersion, pVerCheck->vr[i].toVer.dwMV, pVerCheck->vr[i].toVer.dwLV ); if ( ifrAnswer[i] >= 0 && itoAnswer[i] <=0 ) { if ( (ifrAnswer[i] == 0) && (itoAnswer[i] == 0) ) { if ( CurrBld < pVerCheck->vr[i].frVer.dwBd || CurrBld > pVerCheck->vr[i].toVer.dwBd ) goto RE_TRY; } else if ( ifrAnswer[i] == 0 ) { if ( CurrBld < pVerCheck->vr[i].frVer.dwBd ) goto RE_TRY; } else if ( itoAnswer[i] == 0 ) { if ( CurrBld > pVerCheck->vr[i].toVer.dwBd ) goto RE_TRY; } // if you are here, meaning you are fine with this Version range, no more check is needed
break;
RE_TRY: if ( i == 0 ) continue;
uErrid = IDS_ERR_TARGETOS; break; } else if ( i == 1 ) // not in any of the ranges
{ uErrid = IDS_ERR_TARGETOS; break; } }
// if passed OS check, go on file check
if ( uErrid == 0 ) { if ( ptargetVers->dwNumFiles && !CheckFileVersion( ptargetVers, szPath, sizeof(szPath), &i ) ) uErrid = IDS_ERR_FILEVER; } }
EXIT: if ( (uErrid == IDS_ERR_FILEVER) || (uErrid == IDS_ERR_TARGETOS) ) { LPSTR pParam2 = NULL, pMsg; UINT uButton, id;
if ( uErrid == IDS_ERR_FILEVER ) { pVerCheck = (PVERCHECK) (ptargetVers->szBuf + ptargetVers->dwFileOffs + i*sizeof(VERCHECK) ); pParam2 = szPath; }
pMsg = ptargetVers->szBuf + pVerCheck->dwstrOffs; uButton = GetMsgboxFlag( pVerCheck->dwFlag );
if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) && *pMsg ) { MessageBeep( MB_OK ); id = MessageBox( NULL, pMsg, g_Sess.achTitle, MB_ICONEXCLAMATION | uButton | ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0)); if ( uButton & MB_YESNO ) { if ( id == IDYES ) uErrid = 0; } else if (uButton & MB_OKCANCEL ) { if ( id == IDOK ) uErrid = 0; } } else { MsgBox2Param( NULL, uErrid, g_Sess.achTitle, pParam2, MB_ICONEXCLAMATION, MB_OK); } } else if ( uErrid ) ErrorMsg( NULL, uErrid );
return ( uErrid? FALSE : TRUE ); }
//***************************************************************************
//* *
//* NAME: DisplayLicense *
//* *
//* SYNOPSIS: Displays a license file and asks if user accepts it. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if user accepts, FALSE if an error *
//* occurs or user rejects. *
//* *
//***************************************************************************
BOOL DisplayLicense( VOID ) { DWORD dwSize; INT_PTR iDlgRC;
dwSize = GetResource( achResLicense, NULL, 0 );
g_szLicense = (LPSTR) LocalAlloc( LPTR, dwSize + 1 ); if ( ! g_szLicense ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); g_dwExitCode = MyGetLastError(); return FALSE; }
if ( ! GetResource( achResLicense, g_szLicense, dwSize ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); LocalFree( g_szLicense ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( lstrcmp( g_szLicense, achResNone ) != 0 ) { iDlgRC = MyDialogBox( g_hInst, MAKEINTRESOURCE(IDD_LICENSE), NULL, LicenseDlgProc, (LPARAM)0, 0 ); LocalFree( g_szLicense );
if ( iDlgRC == 0 ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED); return FALSE; } } else { LocalFree( g_szLicense ); }
g_dwExitCode = S_OK; return TRUE; }
//***************************************************************************
//* *
//* NAME: ExtractFiles *
//* *
//* SYNOPSIS: Starts extraction of the files. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if extraction OK, FALSE on error *
//* *
//***************************************************************************
BOOL ExtractFiles( VOID ) { UINT wIndex; INT_PTR iDlgRC; BOOL extCodeThread = 0;
// FDI does all its file I/O as callbacks up to functions provided by
// this program. Each file is identified by a "handle" similar to a
// file handle. In order to support the file that is actually a
// resource in memory we implement our own file table. The offsets
// into this table are the handles that FDI uses. The table itself
// stores either a real file handle in the case of disk files or
// information (pointer to memory block, current offset) for a memory
// file. The following initializes the table.
for ( wIndex = 0; wIndex < FILETABLESIZE; wIndex++ ) { g_FileTable[wIndex].avail = TRUE; }
if ( (g_CMD.wQuietMode & QUIETMODE_ALL) || (g_Sess.uExtractOpt & EXTRACTOPT_UI_NO) ) { extCodeThread = ExtractThread();
if ( extCodeThread == 0 ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED); return FALSE; } } else {
iDlgRC = MyDialogBox( g_hInst, ( g_fOSSupportsFullUI ) ? MAKEINTRESOURCE(IDD_EXTRACT) : MAKEINTRESOURCE(IDD_EXTRACT_MIN), NULL, ExtractDlgProc, (LPARAM)0, 0 );
if ( iDlgRC == 0 ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED); return FALSE; } }
// Extract EXTRA files tagged on with updfile.exe
if ( ! TravelUpdatedFiles( ProcessUpdatedFile_Write ) ) { // g_dwExitCode is set in TravelUpdatedFiles()
return FALSE; }
g_dwExitCode = S_OK; return TRUE; }
//***************************************************************************
//* *
//* NAME: RunInstallCommand *
//* *
//* SYNOPSIS: Executes the installation command or INF file. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if installation OK, FALSE on error *
//* *
//***************************************************************************
BOOL RunInstallCommand( VOID ) { //DWORD dwExitCode; // Return Status from Setup Process
UINT bShowWindow; LPTSTR szCommand; TCHAR szResCommand[MAX_PATH]; DWORD dwSize; STARTUPINFO sti; BOOL fInfCmd = FALSE; DOINFINSTALL pfDoInfInstall = NULL; HANDLE hSetupLibrary; ADVPACKARGS AdvPackArgs; UINT i = 0; BOOL bFoundQCmd = FALSE, bRunOnceAdded = FALSE;
g_dwExitCode = S_OK;
// get reboot info
if ( !g_CMD.fUserReboot ) { // no command line, get from resource
dwSize = GetResource( achResReboot, &g_Sess.dwReboot,sizeof(g_Sess.dwReboot) ); if ( dwSize == 0 || dwSize > sizeof(g_Sess.dwReboot) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; } }
for ( i = 0; i < 2; i += 1 ) { fInfCmd = FALSE; // Default to FALSE;
memset( &sti, 0, sizeof(sti) ); sti.cb = sizeof(STARTUPINFO);
if ( !g_CMD.szUserCmd[0] ) { dwSize = GetResource( achResShowWindow, &bShowWindow, sizeof(bShowWindow) );
if ( dwSize == 0 || dwSize > sizeof(bShowWindow) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( bShowWindow == bResShowHidden ) { sti.dwFlags = STARTF_USESHOWWINDOW; sti.wShowWindow = SW_HIDE; } else if ( bShowWindow == bResShowMin ) { sti.dwFlags = STARTF_USESHOWWINDOW; sti.wShowWindow = SW_MINIMIZE; } else if ( bShowWindow == bResShowMax ) { sti.dwFlags = STARTF_USESHOWWINDOW; sti.wShowWindow = SW_MAXIMIZE; }
if ( i == 0 ) { // if user specify the quiet mode command, use it. Otherwise, assume
// quiet mode or not, they run the same command.
//
if ( g_CMD.wQuietMode ) { LPCSTR pResName; if ( g_CMD.wQuietMode & QUIETMODE_ALL ) pResName = achResAdminQCmd; else if ( g_CMD.wQuietMode & QUIETMODE_USER ) pResName = achResUserQCmd; if ( !GetResource( pResName, szResCommand, sizeof(szResCommand) ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; } if ( lstrcmpi(szResCommand, achResNone) ) { bFoundQCmd = TRUE; } } if ( !bFoundQCmd && !GetResource( achResRunProgram, szResCommand, sizeof(szResCommand) ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; } } } else { lstrcpy( szResCommand, g_CMD.szUserCmd ); }
if ( i == 1 ) { // if there is PostInstallCommand to be run
if ( ! GetResource( achResPostRunCmd, szResCommand, sizeof(szResCommand) ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( g_CMD.szUserCmd[0] || !lstrcmpi( szResCommand, achResNone ) ) { break; } }
if ( !AnalyzeCmd( szResCommand, &szCommand, &fInfCmd ) ) { return FALSE; }
// before we run the app, add runonce entry, if it return, we delete this entry
if ( !bRunOnceAdded && (g_wOSVer != _OSVER_WINNT3X) && g_CMD.fCreateTemp && !fInfCmd ) { bRunOnceAdded = TRUE; AddRegRunOnce(); }
if ( fInfCmd && ! g_fOSSupportsINFInstalls ) { ErrorMsg( NULL, IDS_ERR_NO_INF_INSTALLS ); LocalFree( szCommand ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED); return FALSE; }
if ( fInfCmd && g_Sess.uExtractOpt & EXTRACTOPT_ADVDLL ) {
hSetupLibrary = MyLoadLibrary( ADVPACKDLL );
if ( hSetupLibrary == NULL ) { ErrorMsg1Param( NULL, IDS_ERR_LOAD_DLL, ADVPACKDLL ); LocalFree( szCommand ); g_dwExitCode = MyGetLastError(); return FALSE; }
pfDoInfInstall = (DOINFINSTALL) GetProcAddress( hSetupLibrary, szDOINFINSTALL );
if ( pfDoInfInstall == NULL ) { ErrorMsg1Param( NULL, IDS_ERR_GET_PROC_ADDR, szDOINFINSTALL ); FreeLibrary( hSetupLibrary ); LocalFree( szCommand ); g_dwExitCode = MyGetLastError(); return FALSE; }
AdvPackArgs.hWnd = NULL; AdvPackArgs.lpszTitle = g_Sess.achTitle; AdvPackArgs.lpszInfFilename = szCommand; AdvPackArgs.lpszSourceDir = g_Sess.achDestDir; AdvPackArgs.lpszInstallSection = szResCommand; AdvPackArgs.wOSVer = g_wOSVer; AdvPackArgs.dwFlags = g_CMD.wQuietMode; if ( g_CMD.fNoGrpConv ) { AdvPackArgs.dwFlags |= ADVFLAGS_NGCONV; }
if ( g_Sess.uExtractOpt & EXTRACTOPT_COMPRESSED ) { AdvPackArgs.dwFlags |= ADVFLAGS_COMPRESSED; }
if ( g_Sess.uExtractOpt & EXTRACTOPT_UPDHLPDLLS ) { AdvPackArgs.dwFlags |= ADVFLAGS_UPDHLPDLLS; }
if ( g_CMD.dwFlags & CMDL_DELAYREBOOT ) { AdvPackArgs.dwFlags |= ADVFLAGS_DELAYREBOOT; }
if ( g_CMD.dwFlags & CMDL_DELAYPOSTCMD ) { AdvPackArgs.dwFlags |= ADVFLAGS_DELAYPOSTCMD; }
AdvPackArgs.dwPackInstSize = g_Sess.cbPackInstSize;
if ( FAILED(g_dwExitCode = pfDoInfInstall(&AdvPackArgs)) ) { FreeLibrary( hSetupLibrary ); LocalFree( szCommand ); return FALSE; }
FreeLibrary( hSetupLibrary ); } else { if ( !RunApps( szCommand, &sti ) ) { LocalFree( szCommand ); return FALSE; } }
LocalFree( szCommand ); } // end for
// convert the RunOnce entry added by AddRegRunOnce to use ADVPACK instead
// of wextract if g_bConvertRunOnce is TRUE
if (g_bConvertRunOnce) ConvertRegRunOnce();
return TRUE; }
//***************************************************************************
//* *
//* NAME: RunApps *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL RunApps( LPSTR lpCommand, STARTUPINFO *lpsti ) { DWORD dwExitCode; PROCESS_INFORMATION pi; // Setup Process Launch
BOOL bRet = TRUE; TCHAR achMessage[MAX_STRING]; if ( !lpCommand ) { return FALSE; }
memset( &pi, 0, sizeof(pi) ); if ( CreateProcess( NULL, lpCommand, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, lpsti, &pi ) ) { WaitForSingleObject( pi.hProcess, INFINITE ); GetExitCodeProcess( pi.hProcess, &dwExitCode );
// check if this return code is cabpack aware
// if so, use it as reboot code
if ( !g_CMD.fUserReboot && (g_Sess.dwReboot & REBOOT_YES) && !(g_Sess.dwReboot & REBOOT_ALWAYS) && ((dwExitCode & 0xFF000000) == RC_WEXTRACT_AWARE) ) { g_Sess.dwReboot = dwExitCode; }
// store app return code to system standard return code if necessary
// g_dwExitCode is set in this function, make sure it is not re-set afterward
//
savAppExitCode( dwExitCode );
CloseHandle( pi.hThread ); CloseHandle( pi.hProcess );
if ( g_Sess.uExtractOpt & EXTRACTOPT_CMDSDEPENDED ) { if ( FAILED( dwExitCode ) ) bRet = FALSE; } } else { g_dwExitCode = MyGetLastError(); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, achMessage, sizeof(achMessage), NULL ); ErrorMsg2Param( NULL, IDS_ERR_CREATE_PROCESS, lpCommand, achMessage ); bRet = FALSE; }
return bRet; }
// convert app return code to sys return code
//
void savAppExitCode( DWORD dwAppRet ) { if ( g_Sess.uExtractOpt & EXTRACTOPT_PASSINSTRETALWAYS ) { g_dwExitCode = dwAppRet; } else { // called from AdvINFInstall
if ( (CheckReboot() == EWX_REBOOT) || ( ((dwAppRet & 0xFF000000) == RC_WEXTRACT_AWARE) && (dwAppRet & REBOOT_YES)) ) { g_dwExitCode = ERROR_SUCCESS_REBOOT_REQUIRED; } else if ( g_Sess.uExtractOpt & EXTRACTOPT_PASSINSTRET ) { // if author specified, relay back whatever EXE returns
//
g_dwExitCode = dwAppRet; } } }
//***************************************************************************
//* *
//* NAME: FinishMessage *
//* *
//* SYNOPSIS: Displays the final message to the user when everything *
//* was successfull. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
VOID FinishMessage( VOID ) { LPSTR szFinishMsg; DWORD dwSize;
dwSize = GetResource( achResFinishMsg, NULL, 0 );
szFinishMsg = (LPSTR) LocalAlloc( LPTR, dwSize + 1 ); if ( ! szFinishMsg ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); return; }
if ( ! GetResource( achResFinishMsg, szFinishMsg, dwSize ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); LocalFree( szFinishMsg ); return; }
if ( lstrcmp( szFinishMsg, achResNone ) != 0 ) { MsgBox1Param( NULL, IDS_PROMPT, szFinishMsg, MB_ICONINFORMATION, MB_OK ); }
LocalFree( szFinishMsg ); }
int CALLBACK BrowseCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { switch(uMsg) { case BFFM_INITIALIZED: // lpData is the path string
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); break; } return 0; }
//***************************************************************************
//* *
//* NAME: BrowseForDir *
//* *
//* SYNOPSIS: Let user browse for a directory on their system or network. *
//* *
//* REQUIRES: hwndParent: *
//* szTitle: *
//* szResult: *
//* *
//* RETURNS: BOOL: *
//* *
//* NOTES: It would be really cool to set the status line of the *
//* browse window to display "Yes, there's enough space", or *
//* "no there is not". *
//* *
//***************************************************************************
BOOL BrowseForDir( HWND hwndParent, LPCTSTR szTitle, LPTSTR szResult ) { BROWSEINFO bi; LPITEMIDLIST pidl; HINSTANCE hShell32Lib; SHFREE pfSHFree; SHGETPATHFROMIDLIST pfSHGetPathFromIDList; SHBROWSEFORFOLDER pfSHBrowseForFolder; LPSTR lpTmp;
ASSERT( szResult );
// Load the Shell 32 Library to get the SHBrowseForFolder() features
if ( ( hShell32Lib = LoadLibrary( achShell32Lib ) ) != NULL ) {
if ( ( !( pfSHBrowseForFolder = (SHBROWSEFORFOLDER) GetProcAddress( hShell32Lib, achSHBrowseForFolder ) ) ) || ( ! ( pfSHFree = (SHFREE) GetProcAddress( hShell32Lib, MAKEINTRESOURCE(SHFREE_ORDINAL) ) ) ) || ( ! ( pfSHGetPathFromIDList = (SHGETPATHFROMIDLIST) GetProcAddress( hShell32Lib, achSHGetPathFromIDList ) ) ) ) { FreeLibrary( hShell32Lib ); ErrorMsg( hwndParent, IDS_ERR_LOADFUNCS ); return FALSE; } } else { ErrorMsg( hwndParent, IDS_ERR_LOADDLL ); return FALSE; }
if ( !g_szBrowsePath[0] ) { GetTempPath( sizeof(g_szBrowsePath), g_szBrowsePath ); // The following api does not like to have trailing '\\'
lpTmp = CharPrev( g_szBrowsePath, g_szBrowsePath + lstrlen(g_szBrowsePath) ); if ( (*lpTmp == '\\') && ( *CharPrev( g_szBrowsePath, lpTmp ) != ':' ) ) *lpTmp = '\0'; }
szResult[0] = 0; bi.hwndOwner = hwndParent; bi.pidlRoot = NULL; bi.pszDisplayName = NULL; bi.lpszTitle = szTitle; bi.ulFlags = BIF_RETURNONLYFSDIRS; bi.lpfn = BrowseCallback; bi.lParam = (LPARAM)g_szBrowsePath;
pidl = pfSHBrowseForFolder( &bi );
if ( pidl ) { pfSHGetPathFromIDList( pidl, g_szBrowsePath ); if ( g_szBrowsePath[0] ) { lstrcpy( szResult, g_szBrowsePath ); } pfSHFree( pidl ); }
FreeLibrary( hShell32Lib );
if ( szResult[0] != 0 ) { return TRUE; } else { return FALSE; } }
//***************************************************************************
//* *
//* NAME: CenterWindow *
//* *
//* SYNOPSIS: Center one window within another. *
//* *
//* REQUIRES: hwndChild: *
//* hWndParent: *
//* *
//* RETURNS: BOOL: TRUE if successful, FALSE otherwise *
//* *
//***************************************************************************
BOOL CenterWindow( HWND hwndChild, HWND hwndParent ) { RECT rChild; RECT rParent; int wChild; int hChild; int wParent; int hParent; int wScreen; int hScreen; int xNew; int yNew; HDC hdc;
// Get the Height and Width of the child window
GetWindowRect (hwndChild, &rChild); wChild = rChild.right - rChild.left; hChild = rChild.bottom - rChild.top;
// Get the Height and Width of the parent window
GetWindowRect (hwndParent, &rParent); wParent = rParent.right - rParent.left; hParent = rParent.bottom - rParent.top;
// Get the display limits
hdc = GetDC (hwndChild); wScreen = GetDeviceCaps (hdc, HORZRES); hScreen = GetDeviceCaps (hdc, VERTRES); ReleaseDC (hwndChild, hdc);
// Calculate new X position, then adjust for screen
xNew = rParent.left + ((wParent - wChild) /2); if (xNew < 0) { xNew = 0; } else if ((xNew+wChild) > wScreen) { xNew = wScreen - wChild; }
// Calculate new Y position, then adjust for screen
yNew = rParent.top + ((hParent - hChild) /2); if (yNew < 0) { yNew = 0; } else if ((yNew+hChild) > hScreen) { yNew = hScreen - hChild; }
// Set it, and return
return( SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER)); }
//***************************************************************************
//* *
//* NAME: MsgBox2Param *
//* *
//* SYNOPSIS: Displays a message box with the specified string ID using *
//* 2 string parameters. *
//* *
//* REQUIRES: hWnd: Parent window *
//* nMsgID: String resource ID *
//* szParam1: Parameter 1 (or NULL) *
//* szParam2: Parameter 2 (or NULL) *
//* uIcon: Icon to display (or 0) *
//* uButtons: Buttons to display *
//* *
//* RETURNS: INT: ID of button pressed *
//* *
//* NOTES: Macros are provided for displaying 1 parameter or 0 *
//* parameter message boxes. Also see ErrorMsg() macros. *
//* *
//***************************************************************************
INT CALLBACK MsgBox2Param( HWND hWnd, UINT nMsgID, LPCSTR szParam1, LPCSTR szParam2, UINT uIcon, UINT uButtons ) { TCHAR achMsgBuf[STRING_BUF_LEN]; LPSTR szMessage; INT nReturn; CHAR achErr[] = "LoadString() Error. Could not load string resource.";
// BUGBUG: the correct quiet mode return code should be a caller's param since the caller
// knows what expected its own case.
//
if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) ) { // BUGBUG: This section could be replaced by using FormatMessage
//
LoadSz( nMsgID, achMsgBuf, sizeof(achMsgBuf) );
if ( achMsgBuf[0] == 0 ) { MessageBox( hWnd, achErr, g_Sess.achTitle, MB_ICONSTOP | MB_OK | MB_SETFOREGROUND | ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0)); return -1; }
if ( szParam2 != NULL ) { szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf ) + lstrlen( szParam1 ) + lstrlen( szParam2 ) + 100 ); if ( ! szMessage ) { return -1; }
wsprintf( szMessage, achMsgBuf, szParam1, szParam2 ); } else if ( szParam1 != NULL ) { szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf ) + lstrlen( szParam1 ) + 100 ); if ( ! szMessage ) { return -1; }
wsprintf( szMessage, achMsgBuf, szParam1 ); } else { szMessage = (LPSTR) LocalAlloc( LPTR, lstrlen( achMsgBuf ) + 1 ); if ( ! szMessage ) return -1;
lstrcpy( szMessage, achMsgBuf ); }
MessageBeep( uIcon );
nReturn = MessageBox( hWnd, szMessage, g_Sess.achTitle, uIcon | uButtons | MB_APPLMODAL | MB_SETFOREGROUND | ((RunningOnWin95BiDiLoc() && IsBiDiLocalizedBinary(g_hInst,RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO))) ? (MB_RIGHT | MB_RTLREADING) : 0));
LocalFree( szMessage );
return nReturn; } else return IDOK; }
//***************************************************************************
//* *
//* NAME: GetResource *
//* *
//* SYNOPSIS: Loads a specified resource into a buffer. *
//* *
//* REQUIRES: szRes: Name of resource to load *
//* lpBuffer: Buffer to put the resource in *
//* dwMaxSize: Size of buffer (not including terminating *
//* NULL char, if it's needed. *
//* *
//* RETURNS: DWORD: 0 if it fails, otherwise size of resource *
//* *
//* NOTES: If the value returned is greater than dwMaxSize, then *
//* it means the buffer wasn't big enough and the calling *
//* function should allocate memory the size of the return val. *
//* *
//***************************************************************************
DWORD GetResource( LPCSTR szRes, VOID *lpBuffer, DWORD dwMaxSize ) { HANDLE hRes; DWORD dwSize;
// BUGBUG: called should not depend on this size being exact resource size.
// Resources could be padded!
//
dwSize = SizeofResource( NULL, FindResource( NULL, szRes, RT_RCDATA ) );
if ( dwSize > dwMaxSize || lpBuffer == NULL ) { return dwSize; }
if ( dwSize == 0 ) { return 0; }
hRes = LockResource( LoadResource( NULL, FindResource( NULL, szRes, RT_RCDATA ) ) );
if ( hRes == NULL ) { return 0; }
memcpy( lpBuffer, hRes, dwSize );
FreeResource( hRes );
return ( dwSize ); }
//***************************************************************************
//* *
//* NAME: LoadSz *
//* *
//* SYNOPSIS: Loads specified string resource into buffer. *
//* *
//* REQUIRES: idString: *
//* lpszBuf: *
//* cbBuf: *
//* *
//* RETURNS: LPSTR: Pointer to the passed-in buffer. *
//* *
//* NOTES: If this function fails (most likely due to low memory), the *
//* returned buffer will have a leading NULL so it is generally *
//* safe to use this without checking for failure. *
//* *
//***************************************************************************
LPSTR LoadSz( UINT idString, LPSTR lpszBuf, UINT cbBuf ) { ASSERT( lpszBuf );
// Clear the buffer and load the string
if ( lpszBuf ) { *lpszBuf = '\0'; LoadString( g_hInst, idString, lpszBuf, cbBuf ); }
return lpszBuf; }
//***************************************************************************
//* *
//* NAME: CatDirAndFile *
//* *
//* SYNOPSIS: Concatenate a directory with a filename. *
//* *
//* REQUIRES: pszResult: *
//* wSize: *
//* pszDir: *
//* pszFile: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
BOOL CatDirAndFile( LPTSTR pszResult, int wSize, LPCTSTR pszDir, LPCTSTR pszFile ) { ASSERT( lstrlen(pszDir) ); ASSERT( lstrlen(pszFile) );
if ( lstrlen(pszDir) + lstrlen(pszFile) + 1 >= wSize ) { return FALSE; }
lstrcpy( pszResult, pszDir ); if ( pszResult[lstrlen(pszResult)-1] != '\\' && pszResult[lstrlen(pszResult)-1] != '/' ) { pszResult[lstrlen(pszResult)] = '\\'; pszResult[lstrlen(pszResult)+1] = '\0'; }
lstrcat( pszResult, pszFile );
return TRUE; }
//***************************************************************************
//* *
//* NAME: FileExists *
//* *
//* SYNOPSIS: Checks if a file exists. *
//* *
//* REQUIRES: pszFilename *
//* *
//* RETURNS: BOOL: TRUE if it exists, FALSE otherwise *
//* *
//***************************************************************************
#if 0
BOOL FileExists( LPCTSTR pszFilename ) { HANDLE hFile;
ASSERT( pszFilename );
hFile = CreateFile( pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) { return( FALSE ); }
CloseHandle( hFile );
return( TRUE ); } #endif
//***************************************************************************
//* *
//* NAME: CheckOverwrite *
//* *
//* SYNOPSIS: Check for file existence and do overwrite processing. *
//* *
//* REQUIRES: pszFile: File to check *
//* *
//* RETURNS: BOOL: TRUE if file can be overwritten. *
//* FALSE if it can not be overwritten. *
//* *
//* NOTE: Should ask Yes/No/Yes-To-All instead of current Yes/No *
//* *
//***************************************************************************
BOOL CheckOverwrite( LPCTSTR cpszFile ) { BOOL fRc = TRUE;
ASSERT( cpszFile );
// If File doesn't already exist no overwrite handling
if ( ! FileExists( cpszFile ) ) { return TRUE; }
// Prompt if we're supposed to
if ( !g_Sess.fOverwrite && !(g_CMD.wQuietMode & QUIETMODE_ALL) ) {
g_Sess.cszOverwriteFile = cpszFile;
switch ( MyDialogBox( g_hInst, MAKEINTRESOURCE(IDD_OVERWRITE), g_hwndExtractDlg, OverwriteDlgProc, (LPARAM)0, (INT_PTR)IDYES ) ) { case (INT_PTR)IDYES: fRc = TRUE; break;
case (INT_PTR)IDC_BUT_YESTOALL: g_Sess.fOverwrite = TRUE; fRc = TRUE; break;
case (INT_PTR)IDNO: fRc = FALSE; break; } }
if ( fRc ) SetFileAttributes( cpszFile, FILE_ATTRIBUTE_NORMAL );
return fRc; }
//***************************************************************************
//* *
//* NAME: AddFile *
//* *
//* SYNOPSIS: Add a file to the list of files we have extracted. *
//* *
//* REQUIRES: pszName: Filename to add *
//* *
//* RETURNS: BOOL: *
//* *
//* NOTE: Singly linked list - items added at front *
//* *
//***************************************************************************
BOOL AddFile( LPCTSTR pszName ) { PFNAME NewName;
ASSERT( pszName );
// Allocate Node
NewName = (PFNAME) LocalAlloc( LPTR, sizeof(FNAME) ); if ( ! NewName ) { ErrorMsg( g_hwndExtractDlg, IDS_ERR_NO_MEMORY ); return( FALSE ); }
// Allocate String Space
NewName->pszFilename = (LPTSTR) LocalAlloc( LPTR, lstrlen(pszName) + 1 ); if ( ! NewName->pszFilename ) { ErrorMsg( g_hwndExtractDlg, IDS_ERR_NO_MEMORY ); LocalFree( NewName ); return( FALSE ); }
// Copy Filename
lstrcpy( NewName->pszFilename, pszName );
// Link into list
NewName->pNextName = g_Sess.pExtractedFiles; g_Sess.pExtractedFiles = NewName;
return( TRUE ); }
//***************************************************************************
//* *
//* NAME: Win32Open *
//* *
//* SYNOPSIS: Translate a C-Runtime _open() call into appropriate Win32 *
//* CreateFile() *
//* *
//* REQUIRES: pszName: Filename to add *
//* *
//* RETURNS: HANDLE: Handle to file on success. *
//* INVALID_HANDLE_VALUE on error. *
//* *
//* NOTE: BUGBUG: Doesn't fully implement C-Runtime _open() *
//* BUGBUG: capability but it currently supports all callbacks *
//* BUGBUG: that FDI will give us *
//* *
//***************************************************************************
HANDLE Win32Open( LPCTSTR pszFile, int oflag, int pmode ) { HANDLE FileHandle; BOOL fExists = FALSE; DWORD fAccess; DWORD fCreate;
ASSERT( pszFile );
// BUGBUG: No Append Mode Support
if (oflag & _O_APPEND) return( INVALID_HANDLE_VALUE );
// Set Read-Write Access
if ((oflag & _O_RDWR) || (oflag & _O_WRONLY)) fAccess = GENERIC_WRITE; else fAccess = GENERIC_READ;
// Set Create Flags
if (oflag & _O_CREAT) { if (oflag & _O_EXCL) fCreate = CREATE_NEW; else if (oflag & _O_TRUNC) fCreate = CREATE_ALWAYS; else fCreate = OPEN_ALWAYS; } else { if (oflag & _O_TRUNC) fCreate = TRUNCATE_EXISTING; else fCreate = OPEN_EXISTING; }
FileHandle = CreateFile( pszFile, fAccess, 0, NULL, fCreate, FILE_ATTRIBUTE_NORMAL, NULL );
if ((FileHandle == INVALID_HANDLE_VALUE) && (fCreate != OPEN_EXISTING)) { MakeDirectory( pszFile ); FileHandle = CreateFile( pszFile, fAccess, 0, NULL, fCreate, FILE_ATTRIBUTE_NORMAL, NULL ); } return( FileHandle ); }
//***************************************************************************
//* *
//* NAME: MakeDirectory *
//* *
//* SYNOPSIS: Make sure the directories along the given pathname exist. *
//* *
//* REQUIRES: pszFile: Name of the file being created. *
//* *
//* RETURNS: nothing *
//* *
//***************************************************************************
VOID MakeDirectory( LPCTSTR pszPath ) { LPTSTR pchChopper; int cExempt;
if (pszPath[0] != '\0') { cExempt = 0;
if ((pszPath[1] == ':') && (pszPath[2] == '\\')) { pchChopper = (LPTSTR) (pszPath + 3); /* skip past "C:\" */ } else if ((pszPath[0] == '\\') && (pszPath[1] == '\\')) { pchChopper = (LPTSTR) (pszPath + 2); /* skip past "\\" */
cExempt = 2; /* machine & share names exempt */ } else { pchChopper = (LPTSTR) (pszPath + 1); /* skip past potential "\" */ }
while (*pchChopper != '\0') { if ((*pchChopper == '\\') && (*(pchChopper - 1) != ':')) { if (cExempt != 0) { cExempt--; } else { *pchChopper = '\0';
CreateDirectory(pszPath,NULL);
*pchChopper = '\\'; } }
pchChopper = CharNext(pchChopper); } } }
//***************************************************************************
//* *
//* NAME: openfunc *
//* *
//* SYNOPSIS: Open File Callback from FDI *
//* *
//* REQUIRES: pszFile: *
//* oflag: *
//* pmode: *
//* *
//* RETURNS: int: Filehandle (index into file table) *
//* -1 on failure *
//* *
//***************************************************************************
//
// Sundown - 11/02/98 - if we are defining ourself as DIAMONDAPI, we need to respect
// the API types - polymorphic or not...
INT_PTR FAR DIAMONDAPI openfunc( char FAR *pszFile, int oflag, int pmode ) { INT_PTR rc; int i;
ASSERT( pszFile );
// Find Available File Handle in Fake File Table
for ( i = 0; i < FILETABLESIZE; i++ ) { if ( g_FileTable[i].avail == TRUE ) { break; } }
// Running out of file handles should never happen
if ( i == FILETABLESIZE ) { ErrorMsg( g_hwndExtractDlg, IDS_ERR_FILETABLE_FULL ); return( -1 ); }
// BUGBUG Spill File Support for Quantum?
if ((*pszFile == '*') && (*(pszFile+1) != 'M')) { // Spill File Support for Quantum Not Supported
ASSERT( TRUE ); }
// If Opening the Cabinet set up memory fake file
if ( ( lstrcmp( pszFile, achMemCab ) ) == 0 ) { if ( ( oflag & _O_CREAT ) || ( oflag & _O_APPEND ) || ( oflag & _O_WRONLY ) || ( oflag & _O_RDWR ) ) { return(-1); } g_FileTable[i].avail = FALSE; g_FileTable[i].ftype = MEMORY_FILE; g_FileTable[i].mfile.start = (void *) g_Sess.lpCabinet; g_FileTable[i].mfile.length = g_Sess.cbCabSize; g_FileTable[i].mfile.current = 0; rc = i; } else { // Else its a normal file - Open it
g_FileTable[i].hf = Win32Open(pszFile, oflag, pmode ); if ( g_FileTable[i].hf != INVALID_HANDLE_VALUE ) { g_FileTable[i].avail = FALSE; g_FileTable[i].ftype = NORMAL_FILE; rc = i; } else { rc = -1; } }
return( rc ); }
//***************************************************************************
//* *
//* NAME: readfunc *
//* *
//* SYNOPSIS: FDI read() callback *
//* *
//* REQUIRES: hf: *
//* pv: *
//* cb: *
//* *
//* RETURNS: UINT: *
//* *
//***************************************************************************
UINT FAR DIAMONDAPI readfunc( INT_PTR hf, void FAR *pv, UINT cb ) { int rc; int cbRead;
ASSERT( hf < (INT_PTR)FILETABLESIZE ); ASSERT( g_FileTable[hf].avail == FALSE ); ASSERT( pv );
// Normal File: Call Read
// Memory File: Compute read amount so as to not read
// past eof. Copy into requesters buffer
switch ( g_FileTable[hf].ftype ) {
case NORMAL_FILE: if ( ! ReadFile( g_FileTable[hf].hf, pv, cb, (DWORD *) &cb, NULL ) ) { rc = -1; } else { rc = cb; } break;
case MEMORY_FILE: // XXX BAD CAST - SIGN PROBLEM FIX THIS!
cbRead = __min( cb, (UINT) g_FileTable[hf].mfile.length - g_FileTable[hf].mfile.current );
ASSERT( cbRead >= 0 );
CopyMemory( pv, (const void *) ((char *) g_FileTable[hf].mfile.start + g_FileTable[hf].mfile.current), cbRead );
g_FileTable[hf].mfile.current += cbRead; rc = cbRead; break; }
return( rc ); }
//***************************************************************************
//* *
//* NAME: writefunc *
//* *
//* SYNOPSIS: FDI write() callback *
//* *
//* REQUIRES: hf: *
//* pv: *
//* cb: *
//* *
//* RETURNS: UINT: *
//* *
//***************************************************************************
UINT FAR DIAMONDAPI writefunc( INT_PTR hf, void FAR *pv, UINT cb ) { int rc;
ASSERT( hf < (INT_PTR)FILETABLESIZE ); ASSERT( g_FileTable[hf].avail == FALSE ); ASSERT( pv ); ASSERT( g_FileTable[hf].ftype != MEMORY_FILE );
WaitForObject( g_hCancelEvent );
// If Cancel has been pressed, let's fake a write error so that diamond
// will immediately send us a close for the file currently being written
// to so that we can kill our process.
//
if ( g_Sess.fCanceled ) { return (UINT) -1 ; }
if ( ! WriteFile( g_FileTable[hf].hf, pv, cb, (DWORD *) &cb, NULL ) ) { rc = -1; } else { rc = cb; }
// Progress Bar: Keep count of bytes written and adjust progbar
if ( rc != -1 ) { // Update count of bytes written
g_Sess.cbWritten += rc;
// Update the Progress Bar
if ( g_fOSSupportsFullUI && g_hwndExtractDlg ) { SendDlgItemMessage( g_hwndExtractDlg, IDC_GENERIC1, PBM_SETPOS, (WPARAM) g_Sess.cbWritten * 100 / g_Sess.cbTotal, (LPARAM) 0 ); } }
return( rc ); }
//***************************************************************************
//* *
//* NAME: closefunc *
//* *
//* SYNOPSIS: FDI close file callback *
//* *
//* REQUIRES: hf: *
//* *
//* RETURNS: int: *
//* *
//***************************************************************************
int FAR DIAMONDAPI closefunc( INT_PTR hf ) { int rc;
ASSERT(hf < (INT_PTR)FILETABLESIZE); ASSERT(g_FileTable[hf].avail == FALSE);
// If memory file reset values else close the file
if ( g_FileTable[hf].ftype == MEMORY_FILE ) { g_FileTable[hf].avail = TRUE; g_FileTable[hf].mfile.start = 0; g_FileTable[hf].mfile.length = 0; g_FileTable[hf].mfile.current = 0; rc = 0; } else { if ( CloseHandle( g_FileTable[hf].hf ) ) { rc = 0; g_FileTable[hf].avail = TRUE; } else { rc = -1; } }
return( rc ); }
//***************************************************************************
//* *
//* NAME: seekfunc *
//* *
//* SYNOPSIS: FDI Seek callback *
//* *
//* REQUIRES: hf: *
//* dist: *
//* seektype: *
//* *
//* RETURNS: long: *
//* *
//***************************************************************************
long FAR DIAMONDAPI seekfunc( INT_PTR hf, long dist, int seektype ) { long rc; DWORD W32seektype;
ASSERT(hf < (INT_PTR)FILETABLESIZE); ASSERT(g_FileTable[hf].avail == FALSE);
// If memory file just change indexes else call SetFilePointer()
if (g_FileTable[hf].ftype == MEMORY_FILE) { switch (seektype) { case SEEK_SET: g_FileTable[hf].mfile.current = dist; break; case SEEK_CUR: g_FileTable[hf].mfile.current += dist; break; case SEEK_END: g_FileTable[hf].mfile.current = g_FileTable[hf].mfile.length + dist; // XXX is a -1 necessary
break; default: return(-1); } rc = g_FileTable[hf].mfile.current; } else { // Must be Win32 File so translate to Win32 Seek type and seek
switch (seektype) { case SEEK_SET: W32seektype = FILE_BEGIN; break; case SEEK_CUR: W32seektype = FILE_CURRENT; break; case SEEK_END: W32seektype = FILE_END; break; } rc = SetFilePointer(g_FileTable[hf].hf, dist, NULL, W32seektype); if (rc == 0xffffffff) rc = -1; }
return( rc ); }
//***************************************************************************
//* *
//* NAME: AdjustFileTime *
//* *
//* SYNOPSIS: Change the time info for a file *
//* *
//* REQUIRES: hf: *
//* date: *
//* time: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
BOOL AdjustFileTime( INT_PTR hf, USHORT date, USHORT time ) { FILETIME ft; FILETIME ftUTC;
ASSERT( hf < (INT_PTR)FILETABLESIZE ); ASSERT( g_FileTable[hf].avail == FALSE ); ASSERT( g_FileTable[hf].ftype != MEMORY_FILE );
// THIS IS A DUPLICATE OF THE ASSERTION!!!!!!
// Memory File? -- Bogus
if ( g_FileTable[hf].ftype == MEMORY_FILE ) { return( FALSE ); }
if ( ! DosDateTimeToFileTime( date, time, &ft ) ) { return( FALSE ); }
if ( ! LocalFileTimeToFileTime( &ft, &ftUTC ) ) { return( FALSE ); }
if ( ! SetFileTime( g_FileTable[hf].hf, &ftUTC, &ftUTC, &ftUTC ) ) { return( FALSE ); }
return( TRUE ); }
//***************************************************************************
//* *
//* NAME: Attr32FromAttrFAT *
//* *
//* SYNOPSIS: Translate FAT attributes to Win32 Attributes *
//* *
//* REQUIRES: attrMSDOS: *
//* *
//* RETURNS: DWORD: *
//* *
//***************************************************************************
DWORD Attr32FromAttrFAT( WORD attrMSDOS ) { //** Quick out for normal file special case
if (attrMSDOS == _A_NORMAL) { return FILE_ATTRIBUTE_NORMAL; }
//** Otherwise, mask off read-only, hidden, system, and archive bits
// NOTE: These bits are in the same places in MS-DOS and Win32!
return attrMSDOS & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH); }
//***************************************************************************
//* *
//* NAME: allocfunc *
//* *
//* SYNOPSIS: FDI Memory Allocation Callback *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
FNALLOC( allocfunc ) { void *pv;
pv = (void *) GlobalAlloc( GMEM_FIXED, cb ); return( pv ); }
//***************************************************************************
//* *
//* NAME: freefunc *
//* *
//* SYNOPSIS: FDI Memory Deallocation Callback *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
FNFREE( freefunc ) { ASSERT(pv);
GlobalFree( pv ); }
//***************************************************************************
//* *
//* NAME: doGetNextCab *
//* *
//* SYNOPSIS: Get Next Cabinet in chain *
//* *
//* REQUIRES: *
//* *
//* RETURNS: -1 *
//* *
//* NOTES: BUGBUG: CLEANUP: STUB THIS OUT *
//* BUGBUG: STUBBED OUT IN WEXTRACT - CHAINED CABINETS NOT *
//* BUGBUG: SUPPORTED *
//* *
//***************************************************************************
FNFDINOTIFY( doGetNextCab ) { return( -1 ); }
//***************************************************************************
//* *
//* NAME: fdiNotifyExtract *
//* *
//* SYNOPSIS: Principle FDI Callback in file extraction *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
FNFDINOTIFY( fdiNotifyExtract ) { INT_PTR fh; TCHAR achFile[MAX_PATH]; // Current File
// User Hit Cancel Button? Cleanup.
if ( g_Sess.fCanceled ) {
if ( fdint == fdintCLOSE_FILE_INFO ) { // close the file (as below)
closefunc( pfdin->hf ); }
return( -1 ); }
switch ( fdint ) {
//*******************************************************************
case fdintCABINET_INFO: return UpdateCabinetInfo( pfdin );
//*******************************************************************
case fdintCOPY_FILE: if ( g_hwndExtractDlg ) SetDlgItemText( g_hwndExtractDlg, IDC_FILENAME, pfdin->psz1 );
if ( ! CatDirAndFile( achFile, sizeof( achFile ), g_Sess.achDestDir, pfdin->psz1 ) ) { return -1; // Abort with error
}
if ( ! CheckOverwrite( achFile ) ) { return (INT_PTR)NULL; }
fh = openfunc( achFile, _O_BINARY | _O_TRUNC | _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE );
if ( fh == -1 ) { return( -1 ); }
if ( ! AddFile( achFile ) ) { return( -1 ); }
g_Sess.cFiles++;
return(fh);
//*******************************************************************
case fdintCLOSE_FILE_INFO: if ( ! CatDirAndFile( achFile, sizeof(achFile), g_Sess.achDestDir, pfdin->psz1 ) ) { return -1; // Abort with error;
}
if ( ! AdjustFileTime( pfdin->hf, pfdin->date, pfdin->time ) ) { return( -1 ); }
closefunc( pfdin->hf );
if ( ! SetFileAttributes( achFile, Attr32FromAttrFAT( pfdin->attribs ) ) ) { return( -1 ); }
return(TRUE);
//*******************************************************************
case fdintPARTIAL_FILE: return( 0 );
//*******************************************************************
case fdintNEXT_CABINET: return doGetNextCab( fdint, pfdin );
//*******************************************************************
default: break; } return( 0 ); }
//***************************************************************************
//* *
//* NAME: UpdateCabinetInfo *
//* *
//* SYNOPSIS: update history of cabinets seen *
//* *
//* REQUIRES: pfdin: FDI info structure *
//* *
//* RETURNS: 0 *
//* *
//***************************************************************************
int UpdateCabinetInfo( PFDINOTIFICATION pfdin ) { //** Save older cabinet info
g_Sess.acab[0] = g_Sess.acab[1];
//** Save new cabinet info
lstrcpy( g_Sess.acab[1].achCabPath , pfdin->psz3 ); lstrcpy( g_Sess.acab[1].achCabFilename, pfdin->psz1 ); lstrcpy( g_Sess.acab[1].achDiskName , pfdin->psz2 ); g_Sess.acab[1].setID = pfdin->setID; g_Sess.acab[1].iCabinet = pfdin->iCabinet;
return 0; }
//***************************************************************************
//* *
//* NAME: VerifyCabinet *
//* *
//* SYNOPSIS: Check that cabinet is properly formed *
//* *
//* REQUIRES: HGLOBAL: *
//* *
//* RETURNS: BOOL: TRUE if Cabinet OK, FALSE if Cabinet invalid*
//* *
//***************************************************************************
BOOL VerifyCabinet( VOID *lpCabinet ) { HFDI hfdi; ERF erf; FDICABINETINFO cabinfo; INT_PTR fh;
/* zero structure before use. FDIIsCabinet not fill in hasnext/hasprev on NT */ memset( &cabinfo, 0, sizeof(cabinfo) );
hfdi = FDICreate(allocfunc,freefunc,openfunc,readfunc,writefunc,closefunc,seekfunc,cpu80386,&erf); if ( hfdi == NULL ) { // BUGBUG Error Handling?
return( FALSE ); }
fh = openfunc( achMemCab, _O_BINARY | _O_RDONLY, _S_IREAD | _S_IWRITE ); if (fh == -1) { return( FALSE ); }
if (FDIIsCabinet(hfdi, fh, &cabinfo ) == FALSE) { return( FALSE ); }
if (cabinfo.cbCabinet != (long) g_Sess.cbCabSize) { return( FALSE ); }
if (cabinfo.hasprev || cabinfo.hasnext) { return( FALSE ); }
if (closefunc( fh ) == -1) { return( FALSE ); }
if (FDIDestroy(hfdi) == FALSE) { return( FALSE ); }
return( TRUE ); }
//***************************************************************************
//* *
//* NAME: ExtractThread *
//* *
//* SYNOPSIS: Main Body of Extract Thread *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
BOOL ExtractThread( VOID ) { HFDI hfdi; BOOL fExtractResult = TRUE;
if ( ! GetCabinet() ) { return FALSE; }
if ( g_hwndExtractDlg ) { ShowWindow( GetDlgItem( g_hwndExtractDlg, IDC_EXTRACT_WAIT ), SW_HIDE ) ; ShowWindow( GetDlgItem( g_hwndExtractDlg, IDC_EXTRACTINGFILE ), SW_SHOW ) ; }
if ( ! VerifyCabinet( g_Sess.lpCabinet ) ) { ErrorMsg( g_hwndExtractDlg, IDS_ERR_INVALID_CABINET ); fExtractResult = FALSE; goto done; }
// Extract the files
hfdi = FDICreate( allocfunc, freefunc, openfunc, readfunc, writefunc, closefunc, seekfunc, cpu80386, &(g_Sess.erf) );
if ( hfdi == NULL ) { ErrorMsg( g_hwndExtractDlg, g_Sess.erf.erfOper + IDS_ERR_FDI_BASE ); fExtractResult = FALSE; goto done; }
fExtractResult = FDICopy( hfdi, achMemCab, "", 0, fdiNotifyExtract, NULL, (void *) &g_Sess );
if ( fExtractResult == FALSE ) { goto done; }
if ( FDIDestroy( hfdi ) == FALSE ) { ErrorMsg( g_hwndExtractDlg, g_Sess.erf.erfOper + IDS_ERR_FDI_BASE ); fExtractResult = FALSE; goto done; }
done: if ( g_Sess.lpCabinet ) { FreeResource( g_Sess.lpCabinet ); g_Sess.lpCabinet = NULL; }
if ( (fExtractResult == FALSE) && !g_Sess.fCanceled ) { ErrorMsg( NULL, IDS_ERR_LOWSWAPSPACE ); }
if ( !(g_CMD.wQuietMode & QUIETMODE_ALL) && !(g_Sess.uExtractOpt & EXTRACTOPT_UI_NO) ) { SendMessage( g_hwndExtractDlg, UM_EXTRACTDONE, (WPARAM) fExtractResult, (LPARAM) 0 );
} return fExtractResult; }
//***************************************************************************
//* *
//* NAME: GetCabinet *
//* *
//* SYNOPSIS: Gets the cabinet from a resource. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
//* *
//***************************************************************************
BOOL GetCabinet( VOID ) { g_Sess.cbCabSize = GetResource( achResCabinet, NULL, 0 );
//g_Sess.lpCabinet = (VOID *) LocalAlloc( LPTR, g_Sess.cbCabSize + 1 );
//if ( ! g_Sess.lpCabinet ) {
// ErrorMsg( NULL, IDS_ERR_NO_MEMORY );
// return FALSE;
//}
g_Sess.lpCabinet = LockResource( LoadResource( NULL, FindResource( NULL, achResCabinet, RT_RCDATA ) ) );
if ( g_Sess.lpCabinet == NULL ) { return 0; }
return TRUE; }
//***************************************************************************
//* *
//* NAME: GetFileList *
//* *
//* SYNOPSIS: Gets the file list from resources. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
//* *
//***************************************************************************
BOOL GetFileList( VOID ) { DWORD dwSize;
dwSize = GetResource( achResSize, g_dwFileSizes, sizeof(g_dwFileSizes) );
if ( dwSize != sizeof(g_dwFileSizes) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
// total files sizes not considering the cluster size
g_Sess.cbTotal = g_dwFileSizes[MAX_NUMCLUSTERS];
if ( g_Sess.cbTotal == 0 ) { ErrorMsg( NULL, IDS_ERR_RESOURCEBAD ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
// get install disk space requirement
// if there is no such resource, the value shoud be remain 0 as default
GetResource( achResPackInstSpace, &(g_Sess.cbPackInstSize), sizeof(g_Sess.cbPackInstSize) );
// Get disk space required for Extra files (files tagged onto package with Updfile.exe)
if ( ! TravelUpdatedFiles( ProcessUpdatedFile_Size ) ) { ErrorMsg( NULL, IDS_ERR_RESOURCEBAD ); // g_dwExitCode is set in TravelUpdatedFiles()
return FALSE; }
return TRUE;
}
//***************************************************************************
//* *
//* NAME: GetUsersPermission *
//* *
//* SYNOPSIS: Ask user if (s)he wants to perform this extraction before *
//* proceeding. If no IDS_UD_PROMPT string resource exists *
//* then we skip the prompting and just extract. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: BOOL: TRUE to proceed with extraction *
//* FALSE to abort extraction *
//* *
//***************************************************************************
BOOL GetUsersPermission( VOID ) { int ret; LPSTR szPrompt; DWORD dwSize;
// Get Prompt String
dwSize = GetResource( achResUPrompt, NULL, 0 );
szPrompt = (LPSTR) LocalAlloc( LPTR, dwSize + 1 ); if ( ! szPrompt ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); g_dwExitCode = MyGetLastError(); return FALSE; }
if ( ! GetResource( achResUPrompt, szPrompt, dwSize ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); LocalFree( szPrompt ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( lstrcmp( szPrompt, achResNone ) == 0 ) { LocalFree( szPrompt ); return( TRUE ); }
ret = MsgBox1Param( NULL, IDS_PROMPT, szPrompt, MB_ICONQUESTION, MB_YESNO );
LocalFree( szPrompt );
if ( ret == IDYES ) { g_dwExitCode = S_OK; return( TRUE ); } else { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANCELLED); return( FALSE ); } }
//***************************************************************************
//* *
//* NAME: DeleteExtractedFiles *
//* *
//* SYNOPSIS: Delete the files that were extracted into the temporary *
//* directory. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: Nothing *
//* *
//***************************************************************************
VOID DeleteExtractedFiles( VOID ) { PFNAME rover; PFNAME temp;
rover = g_Sess.pExtractedFiles; temp = rover;
while ( rover != NULL ) { if ( !g_CMD.fUserBlankCmd && !g_Sess.uExtractOnly ) { SetFileAttributes( rover->pszFilename, FILE_ATTRIBUTE_NORMAL ); DeleteFile( rover->pszFilename ); } rover = rover->pNextName;
LocalFree( temp->pszFilename ); LocalFree( temp );
temp = rover; }
if ( g_CMD.fCreateTemp && (!g_CMD.fUserBlankCmd) && (!g_Sess.uExtractOnly) ) { char szFolder[MAX_PATH];
lstrcpy( szFolder, g_Sess.achDestDir ); if (g_Sess.uExtractOpt & EXTRACTOPT_PLATFORM_DIR) { // potential we have create 2 level temp dir temp\platform
// if they are empty clean up
GetParentDir( szFolder ); }
SetCurrentDirectory( ".." ); DeleteMyDir( szFolder ); }
// delete the runonce reg entry if it is there since we do the cleanup ourself
if ( (g_wOSVer != _OSVER_WINNT3X) && (g_CMD.fCreateTemp) ) CleanRegRunOnce();
g_CMD.fCreateTemp = FALSE; }
BOOL GetNewTempDir( LPCSTR lpParent, LPSTR lpFullPath ) { int index = 0; char szPath[MAX_PATH]; BOOL bFound = FALSE;
while ( index < 400 ) { wsprintf(szPath, TEMP_TEMPLATE, index++); lstrcpy( lpFullPath, lpParent ); AddPath( lpFullPath, szPath );
// if there is an empty dir, remove it first
RemoveDirectory( lpFullPath );
if ( GetFileAttributes( lpFullPath ) == -1 ) { if ( CreateDirectory( lpFullPath , NULL ) ) { g_CMD.fCreateTemp = TRUE; bFound = TRUE; } else bFound = FALSE; break; } }
if ( !bFound && GetTempFileName( lpParent, TEMPPREFIX, 0, lpFullPath ) ) { bFound = TRUE; DeleteFile( lpFullPath ); // if file doesn't exist, fail it. who cares.
CreateDirectory( lpFullPath, NULL ); } return bFound; }
//***************************************************************************
//* *
//* NAME: CreateAndValidateSubdir *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL CreateAndValidateSubdir( LPCTSTR lpPath, BOOL bCreateUnique, UINT chkType ) { TCHAR szTemp[MAX_PATH];
if ( bCreateUnique ) { if ( GetNewTempDir( lpPath, szTemp ) ) { lstrcpy( g_Sess.achDestDir, szTemp ); if (g_Sess.uExtractOpt & EXTRACTOPT_PLATFORM_DIR) { SYSTEM_INFO SystemInfo; GetSystemInfo( &SystemInfo ); switch (SystemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: AddPath( g_Sess.achDestDir, "i386" ); break;
case PROCESSOR_ARCHITECTURE_MIPS: AddPath( g_Sess.achDestDir, "mips" ); break;
case PROCESSOR_ARCHITECTURE_ALPHA: AddPath( g_Sess.achDestDir, "alpha" ); break;
case PROCESSOR_ARCHITECTURE_PPC: AddPath( g_Sess.achDestDir, "ppc" ); break; } } AddPath( g_Sess.achDestDir, "" ); } else return FALSE; } else lstrcpy( g_Sess.achDestDir, lpPath );
// if not there, create dir
if ( !IsGoodTempDir( g_Sess.achDestDir ) ) { if ( CreateDirectory( g_Sess.achDestDir, NULL ) ) { g_CMD.fCreateTemp = TRUE; } else { g_dwExitCode = MyGetLastError(); return FALSE; } }
if ( IsEnoughSpace(g_Sess.achDestDir, chkType, MSG_REQDSK_NONE ) ) { g_dwExitCode = S_OK; return TRUE; }
if ( g_CMD.fCreateTemp ) { g_CMD.fCreateTemp = FALSE; RemoveDirectory(g_Sess.achDestDir); }
return FALSE; }
//***************************************************************************
//* *
//* NAME: GetTempDirectory *
//* *
//* SYNOPSIS: Get a temporary Directory for extraction that is on a drive *
//* with enough disk space available. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: BOOL: TRUE if successful, FALSE on error *
//* *
//***************************************************************************
BOOL GetTempDirectory( VOID ) { INT_PTR iDlgRC; int len; DWORD dwSize; LPTSTR szCommand; char szRoot[MAX_PATH];
// Try system TEMP path first, if that isn't any good then
// we'll try the EXE directory. If both fail, ask user
// to pick a temp dir.
// check if user has empty command
dwSize = GetResource( achResRunProgram, NULL, 0 );
szCommand = (LPSTR) LocalAlloc( LPTR, dwSize + 1 ); if ( ! szCommand ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); g_dwExitCode = MyGetLastError(); return FALSE; }
if ( ! GetResource( achResRunProgram, szCommand, dwSize ) ) { ErrorMsg( NULL, IDS_ERR_NO_RESOURCE ); LocalFree( szCommand ); g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); return FALSE; }
if ( !lstrcmp( szCommand, achResNone ) ) { // only extract files, no run command
g_Sess.uExtractOnly = 1; }
LocalFree( szCommand );
// if user use /T: option, we wont try any others
if ( g_CMD.szUserTempDir[0] ) { UINT chkType;
if ( (g_CMD.szUserTempDir[0] == '\\') && (g_CMD.szUserTempDir[1] == '\\') ) chkType = CHK_REQDSK_NONE; else chkType = CHK_REQDSK_EXTRACT;
if ( CreateAndValidateSubdir( g_CMD.szUserTempDir, FALSE, chkType ) ) return TRUE; else { ErrorMsg( NULL, IDS_ERR_INVALID_DIR ); return FALSE; } } else { if ( g_CMD.fUserBlankCmd || g_Sess.uExtractOnly ) { // ask user where files are stored
iDlgRC = MyDialogBox( g_hInst, MAKEINTRESOURCE(IDD_TEMPDIR), NULL, TempDirDlgProc, (LPARAM)0, 0 ); //fDlgRC = UserDirPrompt( NULL, IDS_TEMP_EXTRACT, "", g_Sess.achDestDir, sizeof(g_Sess.achDestDir) );
return ( iDlgRC != 0 ) ; }
// First - try TMP, TEMP, and current
if ( GetTempPath( sizeof(g_Sess.achDestDir), g_Sess.achDestDir ) ) { if ( CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, (CHK_REQDSK_EXTRACT | CHK_REQDSK_INST) ) ) return TRUE;
if ( !IsWindowsDrive( g_Sess.achDestDir ) && CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, CHK_REQDSK_EXTRACT ) ) return TRUE; }
// temp dir failed, try EXE dir
// Second - try running EXE Directory
// Too much grief, lets take this thing out
#if 0
if ( GetModuleFileName( g_hInst, g_Sess.achDestDir, (DWORD)sizeof(g_Sess.achDestDir) ) && (g_Sess.achDestDir[1] != '\\') ) { len = lstrlen( g_Sess.achDestDir )-1; while ( g_Sess.achDestDir[len] != '\\' ) len--; g_Sess.achDestDir[len+1] = '\0';
if ( CreateAndValidateSubdir ( g_Sess.achDestDir, TRUE, (CHK_REQDSK_EXTRACT | CHK_REQDSK_INST) ) ) return TRUE;
if ( !IsWindowsDrive( g_Sess.achDestDir ) && CreateAndValidateSubdir( g_Sess.achDestDir, TRUE, CHK_REQDSK_EXTRACT ) ) return TRUE; } #endif
// you are here--means that tmp dir and exe dir are both failed EITHER because of not enough space for
// both install and extracting and they reside the same dir as Windows OR it is non-windir but not enough space
// even for extracting itself.
// 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:
// 1) big enough for both install and extract space;
// 2) 1st Non-Windows drive which has enough space for extracting
//
do { lstrcpy( szRoot, "A:\\" ); while ( szRoot[0] <= 'Z' ) { UINT uType; DWORD dwFreeBytes = 0;
uType = GetDriveType(szRoot);
// even the drive type is OK, verify the drive has valid connection
//
if ( ( ( uType != DRIVE_RAMDISK) && (uType != DRIVE_FIXED) ) || ( GetFileAttributes( szRoot ) == -1) ) { if ( (uType != DRIVE_REMOVABLE ) || (szRoot[0] == 'A') || ( szRoot[0] == 'B') || !(dwFreeBytes = GetSpace(szRoot))) { szRoot[0]++; continue; }
if ( dwFreeBytes < SIZE_100MB ) { szRoot[0]++; continue; } }
// fixed drive:
if ( !IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT | CHK_REQDSK_INST, MSG_REQDSK_NONE ) ) { if ( IsWindowsDrive(szRoot) || !IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT, MSG_REQDSK_NONE ) ) { szRoot[0]++; continue; } }
// find the suitable drive
// create \msdownld.tmp dir as place for extracting location
//
if ( IsWindowsDrive(szRoot) ) { GetWindowsDirectory( szRoot, sizeof(szRoot) ); } AddPath( szRoot, DIR_MSDOWNLD ); if ( !IfNotExistCreateDir( szRoot ) ) { szRoot[0]++; szRoot[3] = '\0'; continue; } SetFileAttributes( szRoot, FILE_ATTRIBUTE_HIDDEN );
lstrcpy( g_Sess.achDestDir, szRoot ); if ( CreateAndValidateSubdir ( g_Sess.achDestDir, TRUE, CHK_REQDSK_NONE ) ) return TRUE;
}
GetWindowsDirectory( szRoot, MAX_PATH); // just post message; use Windows Drive clustor size as rough estimate
//
} while ( IsEnoughSpace( szRoot, CHK_REQDSK_EXTRACT | CHK_REQDSK_INST, MSG_REQDSK_RETRYCANCEL ) ); }
return( FALSE ); }
//***************************************************************************
//* *
//* NAME: IsGoodTempDir *
//* *
//* SYNOPSIS: Find out if it's a good temporary directory or not. *
//* *
//* REQUIRES: szPath: *
//* *
//* RETURNS: BOOL: TRUE if good, FALSE if nogood *
//* *
//***************************************************************************
BOOL IsGoodTempDir( LPCTSTR szPath ) { DWORD dwAttribs; HANDLE hFile; LPSTR szTestFile;
ASSERT( szPath );
szTestFile = (LPSTR) LocalAlloc( LPTR, lstrlen( szPath ) + 20 ); if ( ! szTestFile ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); g_dwExitCode = MyGetLastError(); return( FALSE ); }
lstrcpy( szTestFile, szPath ); AddPath( szTestFile, "TMP4351$.TMP" ); hFile = CreateFile( szTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL );
LocalFree( szTestFile );
if ( hFile == INVALID_HANDLE_VALUE ) { g_dwExitCode = MyGetLastError(); return( FALSE ); }
CloseHandle( hFile );
dwAttribs = GetFileAttributes( szPath );
if ( ( dwAttribs != 0xFFFFFFFF ) && ( dwAttribs & FILE_ATTRIBUTE_DIRECTORY ) ) { g_dwExitCode = S_OK; return( TRUE ); }
g_dwExitCode = MyGetLastError(); return( FALSE ); }
//***************************************************************************
//* *
//* NAME: IsEnoughSpace *
//* *
//* SYNOPSIS: Check to make sure that enough space is available in the *
//* directory specified. *
//* *
//* REQUIRES: szPath: *
//* *
//* RETURNS: BOOL: TRUE if enough space is available *
//* FALSE if not enough space *
//* *
//***************************************************************************
BOOL IsEnoughSpace( LPCTSTR szPath, UINT chkType, UINT msgType ) { DWORD dwClusterSize = 0; DWORD dwFreeBytes = 0; ULONG ulBytesNeeded; ULONG ulInstallNeeded; TCHAR achOldPath[MAX_PATH]; WORD idxSize; DWORD idxdwClusterSize = 0; TCHAR szDrv[6]; DWORD dwMaxCompLen; DWORD dwVolFlags;
ASSERT( szPath );
if ( chkType == CHK_REQDSK_NONE ) return TRUE;
GetCurrentDirectory( sizeof(achOldPath), achOldPath ); if ( ! SetCurrentDirectory( szPath ) ) { ErrorMsg( NULL, IDS_ERR_CHANGE_DIR ); g_dwExitCode = MyGetLastError(); return FALSE; } if ((dwFreeBytes=GetDrvFreeSpaceAndClusterSize(NULL, &dwClusterSize)) == 0) { TCHAR szMsg[MAX_STRING]={0};
g_dwExitCode = MyGetLastError(); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, szMsg, sizeof(szMsg), NULL ); ErrorMsg2Param( NULL, IDS_ERR_GET_DISKSPACE, szPath, szMsg ); SetCurrentDirectory( achOldPath ); return( FALSE ); }
// find out if the drive is compressed
if ( !GetVolumeInformation( NULL, NULL, 0, NULL, &dwMaxCompLen, &dwVolFlags, NULL, 0 ) ) { TCHAR szMsg[MAX_STRING]={0};
g_dwExitCode = MyGetLastError(); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, szMsg, sizeof(szMsg), NULL ); ErrorMsg2Param( NULL, IDS_ERR_GETVOLINFOR, szPath, szMsg ); SetCurrentDirectory( achOldPath ); return( FALSE );
}
SetCurrentDirectory( achOldPath ); lstrcpyn( szDrv, szPath, 3 );
ulBytesNeeded = 0; idxdwClusterSize = CLUSTER_BASESIZE;
for ( idxSize=0; idxSize<MAX_NUMCLUSTERS; idxSize++ ) { if ( dwClusterSize == idxdwClusterSize ) { break; } idxdwClusterSize = idxdwClusterSize<<1; }
if ( idxSize == MAX_NUMCLUSTERS ) { ErrorMsg( NULL, IDS_ERR_UNKNOWN_CLUSTER ); return( FALSE ); }
if ( (g_Sess.uExtractOpt & EXTRACTOPT_COMPRESSED) && ( dwVolFlags & FS_VOL_IS_COMPRESSED ) ) { ulBytesNeeded = (ULONG)(g_dwFileSizes[idxSize]*COMPRESS_FACTOR); ulInstallNeeded = (ULONG)(g_Sess.cbPackInstSize + g_Sess.cbPackInstSize/4); } else { ulBytesNeeded = (ULONG)g_dwFileSizes[idxSize]; ulInstallNeeded = (ULONG)g_Sess.cbPackInstSize; }
if ( (chkType & CHK_REQDSK_EXTRACT) && (chkType & CHK_REQDSK_INST) ) { if ( (ulBytesNeeded + ulInstallNeeded) > (ULONG) dwFreeBytes ) { return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) ); } } else if ( chkType & CHK_REQDSK_EXTRACT ) { if ( ulBytesNeeded > (ULONG) dwFreeBytes ) { return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) ); }
} else { if ( ulInstallNeeded > (ULONG)dwFreeBytes ) { return ( DiskSpaceErrMsg( msgType, ulBytesNeeded, ulInstallNeeded, szDrv ) ); }
}
// PATH GOOD AND SPACE AVAILABLE!
g_dwExitCode = S_OK; return TRUE; }
BOOL RemoveLeadTailBlanks( LPSTR szBuf, int *startIdx ) { int i=0, j=0;
while ( (szBuf[i] != 0) && IsSpace(szBuf[i]) ) i++;
if ( szBuf[i] == 0 ) { return FALSE; }
j = lstrlen(&szBuf[i]) - 1; while ( j>=0 && IsSpace( szBuf[j+i] ) ) j--;
szBuf[j+i+1] = '\0';
*startIdx = i; return TRUE; }
//***************************************************************************
//* *
//* ParseCmdLine() *
//* *
//* Purpose: Parses the command line looking for switches *
//* *
//* Parameters: LPSTR lpszCmdLineOrg - Original command line *
//* *
//* *
//* Return: (BOOL) TRUE if successful *
//* FALSE if an error occurs *
//* *
//***************************************************************************
BOOL ParseCmdLine( LPCTSTR lpszCmdLineOrg ) { LPCTSTR pLine, pArg; char szTmpBuf[MAX_PATH]; int i,j; LPTSTR lpTmp; BOOL bRet = TRUE; BOOL bLeftQ, bRightQ;
// If we have no command line, then return. It is
// OK to have no command line. CFGTMP is created
// with standard files
if( (!lpszCmdLineOrg) || (lpszCmdLineOrg[0] == 0) ) return TRUE;
// Loop through command line
pLine = lpszCmdLineOrg; while ( (*pLine != EOL) && bRet ) { // Move to first non-white char.
pArg = pLine; while ( IsSpace( (int) *pArg ) ) pArg = CharNext (pArg);
if( *pArg == EOL ) break;
// Move to next white char.
pLine = pArg; i = 0; bLeftQ = FALSE; bRightQ = FALSE; while ( (*pLine != EOL) && ( (!bLeftQ && (!IsSpace(*pLine))) || (bLeftQ && (!bRightQ) )) ) { if ( *pLine == '"') { switch ( *(pLine + 1) ) { case '"': if(i + 1 < sizeof(szTmpBuf) / sizeof(szTmpBuf[0])) { szTmpBuf[i++] = *pLine++; pLine++; } else { return FALSE; }
break;
default: if ( !bLeftQ ) bLeftQ = TRUE; else bRightQ = TRUE; pLine++; break; } } else { if(i + 1 < sizeof(szTmpBuf) / sizeof(szTmpBuf[0])) { szTmpBuf[i++] = *pLine++; } else { return FALSE; } } }
szTmpBuf[i] = '\0';
// make sure the " " are in paires
if ( (bLeftQ && bRightQ) || (!bLeftQ) && (!bRightQ) ) ; else { bRet = FALSE; break; }
if( szTmpBuf[0] != CMD_CHAR1 && szTmpBuf[0] != CMD_CHAR2 ) { // cmdline comand starting with either '/' or '-'
return FALSE; }
// Look for other switches
switch( (CHAR)CharUpper((PSTR)szTmpBuf[1]) ) { case 'Q': if (szTmpBuf[2] == 0 ) g_CMD.wQuietMode = QUIETMODE_USER; //g_CMD.wQuietMode = QUIETMODE_ALL;
else if ( szTmpBuf[2] == ':') { switch ( (CHAR)CharUpper((PSTR)szTmpBuf[3]) ) { case 'U': case '1': g_CMD.wQuietMode = QUIETMODE_USER; break;
case 'A': g_CMD.wQuietMode = QUIETMODE_ALL; break;
default: bRet = FALSE; break; } } else bRet = FALSE; break;
case 'T': case 'D': if ( szTmpBuf[2] == ':' ) { PSTR pszPath;
if ( szTmpBuf[3] == '"' ) i = 4; else i = 3;
if ( !lstrlen(&szTmpBuf[i]) ) { bRet = FALSE; break; } else { j = i; if (!RemoveLeadTailBlanks( &szTmpBuf[i], &j ) ) { bRet = FALSE; break; } if ( (CHAR)CharUpper((PSTR)szTmpBuf[1]) == 'T' ) { lstrcpy( g_CMD.szUserTempDir, &szTmpBuf[i+j] ); AddPath( g_CMD.szUserTempDir, "" ); pszPath = g_CMD.szUserTempDir; } else { lstrcpy( g_CMD.szRunonceDelDir, &szTmpBuf[i+j] ); AddPath( g_CMD.szRunonceDelDir, "" ); pszPath = g_CMD.szRunonceDelDir; }
// make sure it is full path
if ( !IsFullPath(pszPath) ) return FALSE;
} } else bRet = FALSE; break;
case 'C': if ( szTmpBuf[2] == 0 ) { g_CMD.fUserBlankCmd = TRUE; } else if ( szTmpBuf[2] == ':' ) { if ( szTmpBuf[3] == '"' ) i = 4; else i = 3;
if ( !lstrlen(&szTmpBuf[i]) ) { bRet = FALSE; break; } else { // just make sure [] paires right
//
if ( ANSIStrChr( &szTmpBuf[i], '[' ) && (!ANSIStrChr( &szTmpBuf[i], ']' )) || ANSIStrChr( &szTmpBuf[i], ']' ) && (!ANSIStrChr( &szTmpBuf[i], '[' )) ) { bRet = FALSE; break; } j = i; if (!RemoveLeadTailBlanks( &szTmpBuf[i], &j ) ) { bRet = FALSE; break; } lstrcpy( g_CMD.szUserCmd, &szTmpBuf[i+j] ); } } else bRet = FALSE; break;
case 'R': if (szTmpBuf[2] == 0 ) { g_Sess.dwReboot = REBOOT_YES | REBOOT_ALWAYS; g_CMD.fUserReboot = TRUE; } else if ( szTmpBuf[2] == ':') { g_Sess.dwReboot = REBOOT_YES;
i = 3; while ( szTmpBuf[i] != 0 ) { switch ( (CHAR)CharUpper((PSTR)szTmpBuf[i++]) ) { case 'N': g_Sess.dwReboot &= ~(REBOOT_YES); g_CMD.fUserReboot = TRUE; break; case 'I': g_Sess.dwReboot &= ~(REBOOT_ALWAYS); g_CMD.fUserReboot = TRUE; break; case 'A': g_Sess.dwReboot |= REBOOT_ALWAYS; g_CMD.fUserReboot = TRUE; break; case 'S': g_Sess.dwReboot |= REBOOT_SILENT; g_CMD.fUserReboot = TRUE; break; case 'D': g_CMD.dwFlags |= CMDL_DELAYREBOOT; break; case 'P': g_CMD.dwFlags |= CMDL_DELAYPOSTCMD; break;
default: bRet = FALSE; break; } } } else if ( !lstrcmpi( CMD_REGSERV, &szTmpBuf[1] ) ) { break; //ignore
} else { bRet = FALSE; break; } break;
case 'N': if (szTmpBuf[2] == 0 ) g_CMD.fNoExtracting = TRUE; else if ( szTmpBuf[2] == ':') { i = 3; while ( szTmpBuf[i] != 0 ) { switch ( (CHAR)CharUpper((PSTR)szTmpBuf[i++]) ) { case 'G': g_CMD.fNoGrpConv = TRUE; break;
case 'E': g_CMD.fNoExtracting = TRUE; break;
case 'V': g_CMD.fNoVersionCheck = TRUE; break;
default: bRet = FALSE; break; } }
} else bRet = FALSE; break;
case '?': // Help
DisplayHelp(); if (g_hMutex) CloseHandle(g_hMutex); ExitProcess(0);
default: bRet = FALSE; break; } }
if ( g_CMD.fNoExtracting && (g_CMD.szUserTempDir[0]==0) ) { if ( GetModuleFileName( g_hInst, g_CMD.szUserTempDir, (DWORD)sizeof(g_CMD.szUserTempDir) ) ) { lpTmp= ANSIStrRChr(g_CMD.szUserTempDir, '\\') ; *(lpTmp+1) = '\0' ; } else bRet = FALSE ; } return bRet; }
// check windows drive disk space
//
BOOL CheckWinDir() { TCHAR szWinDrv[MAX_PATH];
if ( !GetWindowsDirectory( szWinDrv, MAX_PATH ) ) { ErrorMsg( NULL, IDS_ERR_GET_WIN_DIR ); g_dwExitCode = MyGetLastError(); return FALSE; } return ( IsEnoughSpace( szWinDrv, CHK_REQDSK_INST, MSG_REQDSK_WARN ) ); }
// get the last error and map it to HRESULT
//
DWORD MyGetLastError() { return HRESULT_FROM_WIN32( GetLastError() ); }
//***************************************************************************
//* *
//* NAME: TravelUpdatedFiles *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
//* *
//***************************************************************************
BOOL TravelUpdatedFiles( pfuncPROCESS_UPDATED_FILE pProcessUpdatedFile ) { DWORD dwFileSize = 0; DWORD dwReserved = 0; PSTR pszFilename = NULL; PSTR pszFileContents = NULL; TCHAR szResName[20]; DWORD dwResNum = 0; HANDLE hRes = NULL; HRSRC hRsrc = NULL; BOOL fReturnCode = TRUE; static const TCHAR c_szResNameTemplate[] = "UPDFILE%lu";
for ( dwResNum = 0; ; dwResNum += 1 ) { wsprintf( szResName, c_szResNameTemplate, dwResNum );
hRsrc = FindResource( NULL, szResName, RT_RCDATA ); if ( hRsrc == NULL ) { break; }
hRes = LockResource( LoadResource( NULL, hRsrc ) ); if ( hRes == NULL ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); fReturnCode = FALSE; goto done; }
dwFileSize = *((PDWORD)hRes); dwReserved = *((PDWORD)(((PDWORD)hRes)+1)); pszFilename = (PSTR) (((PSTR)hRes)+(2*sizeof(DWORD))); pszFileContents = (PSTR) (pszFilename + lstrlen(pszFilename) + 1);
if ( !pProcessUpdatedFile( dwFileSize, dwReserved, pszFilename, pszFileContents ) ) { // g_dwExitCode is set in pProcessUpdatedFile()
fReturnCode = FALSE; FreeResource( hRes ); goto done; }
FreeResource( hRes ); }
done:
return fReturnCode; }
//***************************************************************************
//* *
//* NAME: ProcessUpdatedFile_Size *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
//* *
//***************************************************************************
BOOL ProcessUpdatedFile_Size( DWORD dwFileSize, DWORD dwReserved, PCSTR c_pszFilename, PCSTR c_pszFileContents ) { DWORD clusterCurrSize = 0; DWORD i = 0;
#if 0
if (g_Sess.cbPackInstSize != 0 ) { g_Sess.cbPackInstSize += dwFileSize; } #endif
// calculate the file size in different cluster sizes
clusterCurrSize = CLUSTER_BASESIZE; for ( i = 0; i < MAX_NUMCLUSTERS; i += 1 ) { g_dwFileSizes[i] += ((dwFileSize/clusterCurrSize)*clusterCurrSize + (dwFileSize%clusterCurrSize?clusterCurrSize : 0)); clusterCurrSize = (clusterCurrSize<<1); }
return TRUE; }
//***************************************************************************
//* *
//* NAME: ProcessUpdatedFile_Write *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successfull, FALSE otherwise *
//* *
//***************************************************************************
BOOL ProcessUpdatedFile_Write( DWORD dwFileSize, DWORD dwReserved, PCSTR c_pszFilename, PCSTR c_pszFileContents ) { HANDLE hFile = INVALID_HANDLE_VALUE; BOOL fSuccess = TRUE; DWORD dwBytesWritten = 0; TCHAR szFullFilename[MAX_PATH];
lstrcpy( szFullFilename, g_Sess.achDestDir ); AddPath( szFullFilename, c_pszFilename );
hFile = CreateFile( szFullFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE); fSuccess = FALSE; goto done; }
if ( ! WriteFile( hFile, c_pszFileContents, dwFileSize, &dwBytesWritten, NULL ) || dwFileSize != dwBytesWritten ) { g_dwExitCode = HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE); fSuccess = FALSE; goto done; }
done:
if ( hFile != INVALID_HANDLE_VALUE ) { CloseHandle( hFile ); }
return fSuccess; }
HINSTANCE MyLoadLibrary( LPTSTR lpFile ) { TCHAR szPath[MAX_PATH]; DWORD dwAttr; HINSTANCE hFile;
lstrcpy( szPath, g_Sess.achDestDir ); AddPath( szPath, lpFile );
if ( ((dwAttr=GetFileAttributes( szPath )) != -1) && !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) { hFile = LoadLibraryEx( szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); } else { hFile = LoadLibrary( lpFile ); }
return hFile;
}
INT_PTR MyDialogBox( HANDLE hInst, LPCTSTR pTemplate, HWND hWnd, DLGPROC lpProc, LPARAM lpParam, INT_PTR idefRet ) { INT_PTR iDlgRc = -1; HRSRC hDlgRc; HGLOBAL hMemDlg;
hDlgRc = FindResource( hInst, pTemplate, RT_DIALOG );
if ( hDlgRc ) { hMemDlg = LoadResource( hInst, hDlgRc ); if ( hMemDlg ) { if ( !lpParam ) iDlgRc = DialogBoxIndirect( hInst, hMemDlg, hWnd, lpProc ); else iDlgRc = DialogBoxIndirectParam( hInst, hMemDlg, hWnd, lpProc, lpParam );
FreeResource( hMemDlg ); } }
if ( iDlgRc == (INT_PTR)-1 ) { ErrorMsg( NULL, IDS_ERR_DIALOGBOX ); iDlgRc = idefRet; }
return iDlgRc; }
/* these are here to avoid linking QDI */
void * __cdecl QDICreateDecompression(void) { return(NULL); }
void __cdecl QDIDecompress(void) { }
void __cdecl QDIResetDecompression(void) { }
void __cdecl QDIDestroyDecompression(void) { }
/* these are here to avoid linking MDI */
void* __cdecl MDICreateDecompression(void) { return(NULL); }
void __cdecl MDIDecompress(void) { }
void __cdecl MDIResetDecompression(void) { }
void __cdecl MDIDestroyDecompression(void) { }
|