You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4191 lines
156 KiB
4191 lines
156 KiB
//***************************************************************************
|
|
//* 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)
|
|
{
|
|
}
|