|
|
//***************************************************************************
//* Copyright (c) Microsoft Corporation 1995. All rights reserved. *
//***************************************************************************
//* *
//* UTILS.C - Win32 Based Cabinet File Self-extractor and installer utils. *
//* *
//***************************************************************************
//* *
//* Originally written by Jeff Webber. *
//* *
//***************************************************************************
//***************************************************************************
//* INCLUDE FILES *
//***************************************************************************
#include "pch.h"
#pragma hdrstop
#include "wextract.h"
#include "regstr.h"
#include "global.h"
#include <commctrl.h>
static TCHAR szRegRunOnceKey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"; static TCHAR szNT4XDelayUntilReboot[] = "System\\CurrentControlSet\\Control\\Session Manager"; static TCHAR szNT4XPendingValue[] = "PendingFileRenameOperations"; static TCHAR szNT3XDelayUntilReboot[] = "System\\CurrentControlSet\\Control\\Session Manager\\FileRenameOperations"; static TCHAR szRegValNameTemplate[] = "wextract_cleanup%d"; static TCHAR szRegValTemplate[] = "%s /D:%s"; static TCHAR szRegValAdvpackTemplate[] = "rundll32.exe %sadvpack.dll,DelNodeRunDLL32 \"%s\""; static TCHAR szBATCommand[] = "Command.com /c %s";
// store the RunOnce Clean-up reg keyname for this instance
//
TCHAR g_szRegValName[SMALL_BUF_LEN] = { 0 }; BOOL g_bConvertRunOnce = FALSE;
//***************************************************************************
//* Functions *
//***************************************************************************
typedef HRESULT (*CHECKTOKENMEMBERSHIP)(HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember);
BOOL CheckToken(BOOL *pfIsAdmin) { BOOL bNewNT5check = FALSE; HINSTANCE hAdvapi32 = NULL; CHECKTOKENMEMBERSHIP pf; PSID AdministratorsGroup; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
hAdvapi32 = LoadLibrary("advapi32.dll"); if (hAdvapi32) { pf = (CHECKTOKENMEMBERSHIP)GetProcAddress(hAdvapi32, "CheckTokenMembership"); if (pf) { bNewNT5check = TRUE; *pfIsAdmin = FALSE; if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) ) { pf(NULL, AdministratorsGroup, pfIsAdmin); FreeSid(AdministratorsGroup); } } FreeLibrary(hAdvapi32); } return bNewNT5check; }
// IsNTAdmin();
// Returns true if our process has admin priviliges.
// Returns false otherwise.
BOOL IsNTAdmin() { static int fIsAdmin = 2; HANDLE hAccessToken; PTOKEN_GROUPS ptgGroups; DWORD dwReqSize; UINT i; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AdministratorsGroup; BOOL bRet;
//
// If we have cached a value, return the cached value. Note I never
// set the cached value to false as I want to retry each time in
// case a previous failure was just a temp. problem (ie net access down)
//
bRet = FALSE; ptgGroups = NULL;
if( fIsAdmin != 2 ) return (BOOL)fIsAdmin;
if (!CheckToken(&bRet)) { if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hAccessToken ) ) return FALSE;
// See how big of a buffer we need for the token information
if(!GetTokenInformation( hAccessToken, TokenGroups, NULL, 0, &dwReqSize)) { // GetTokenInfo should the buffer size we need - Alloc a buffer
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) ptgGroups = (PTOKEN_GROUPS) LocalAlloc(LMEM_FIXED, dwReqSize); } // ptgGroups could be NULL for a coupla reasons here:
// 1. The alloc above failed
// 2. GetTokenInformation actually managed to succeed the first time (possible?)
// 3. GetTokenInfo failed for a reason other than insufficient buffer
// Any of these seem justification for bailing.
// So, make sure it isn't null, then get the token info
if(ptgGroups && GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, dwReqSize, &dwReqSize)) { if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup) ) { // Search thru all the groups this process belongs to looking for the
// Admistrators Group.
for( i=0; i < ptgGroups->GroupCount; i++ ) { if( EqualSid(ptgGroups->Groups[i].Sid, AdministratorsGroup) ) { // Yea! This guy looks like an admin
fIsAdmin = TRUE; bRet = TRUE; break; } } FreeSid(AdministratorsGroup); } } if(ptgGroups) LocalFree(ptgGroups);
// BUGBUG: Close handle here? doc's aren't clear whether this is needed.
CloseHandle(hAccessToken); } else if (bRet) fIsAdmin = TRUE;
return bRet; }
//**************************************************************************
//
// WarningDlgProc()
//
// Dialog proc for handling a continue/Exit dialog.
//
//**************************************************************************
INT_PTR CALLBACK WarningDlgProc( HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam) { char szMsg[MAX_STRING];
switch( msg ) { case WM_INITDIALOG: CenterWindow( hwnd, GetDesktopWindow() ); *szMsg = 0; LoadString(g_hInst, (UINT)lParam, szMsg, sizeof(szMsg)); SetDlgItemText(hwnd, IDC_WARN_TEXT, szMsg); MessageBeep((UINT)-1); return( TRUE ); // Let default control be chosen.
case WM_COMMAND: switch( wParam ) { case IDC_EXIT: case IDC_CONTINUE: EndDialog( hwnd, wParam ); break;
default: return FALSE; } return TRUE;
default: break; } return( FALSE ); // Let default dialog processing do all.
}
// returns start of next field (or null if null), sets start to begining of the first field,
// with fields separated by separaters and nulls first separater after the first field
TCHAR* ExtractField( TCHAR **pstart, TCHAR * separaters) { LPTSTR start = *pstart; int x = 0;
while(ANSIStrChr(separaters, *start)) { if(*start == 0) return(NULL); start++; }
*pstart = start;
while(!ANSIStrChr(separaters, start[x]) && (start[x] != 0)) x++;
if(start[x] == 0) return(start + x);
start[x] = 0; return(start + x + 1); }
BOOL AnalyzeCmd( LPTSTR szOrigiCommand, LPTSTR *lplpCommand, BOOL *pfInfCmd ) { TCHAR szTmp[MAX_PATH]; TCHAR szINFFile[MAX_PATH]; LPTSTR szNextField, szCurrField, szExt; UINT secLength; LPTSTR lpTempCmd, pszINFEngine;
lstrcpy( szTmp, szOrigiCommand );
// check if the command is LFN name
if ( szTmp[0] == '"' ) { szCurrField = &szTmp[1]; szNextField = ExtractField( &szCurrField, "\"" ); } else { szCurrField = szTmp; szNextField = ExtractField( &szCurrField, " " ); }
if ( !IsRootPath( szCurrField ) ) { // BUGBUG: when IsRootPath Failed, we did not check if the givn
// szCurrField is valid name or not. If it is not valid, the result
// of the AddPath will produce invalid file path. The error will come out at
// either SETUP engine or CreateProcess
//
lstrcpy( szINFFile, g_Sess.achDestDir ); AddPath( szINFFile, szCurrField ); } else lstrcpy( szINFFile, szCurrField );
// check if this is a INF file command
if ( ((szExt = ANSIStrRChr( szCurrField, '.' )) != NULL) && !lstrcmpi( szExt, ".INF" ) ) { // check to see if this valid command
if ( !FileExists( szINFFile ) ) { ErrorMsg1Param( NULL, IDS_ERR_FILENOTEXIST, szINFFile ); return FALSE; }
// check if there is INF section install, and get the sec start point
szCurrField = szNextField; szNextField = ExtractField( &szCurrField, "[" ); // skip things between .INF and [ section beginning
secLength = lstrlen( achDefaultSection );
if ( szNextField ) { // in the case of: .INF<single-blank>[abc]
// the szNextField is "" while in the case of: .INF<multiple-blanks>[abc]
// szNextField points to "abc]". Therefore, the conditional pointer switch added here
//
if ( *szNextField ) { szCurrField = szNextField; }
szNextField = ExtractField( &szCurrField, "]" ); // get INF InstallSection name
if ( *szCurrField ) { secLength = lstrlen( szCurrField ); } }
lpTempCmd = (LPSTR) LocalAlloc( LPTR, 512);
if ( ! lpTempCmd ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); return FALSE; }
// store INF name for reboot checking use
g_uInfRebootOn = GetPrivateProfileInt( *szCurrField ? szCurrField : achDefaultSection, "Reboot", 0, szINFFile ); *pfInfCmd = TRUE; // no RunOnce entry needed
// check if we need use Advanced INF dll handling
if ( GetPrivateProfileString( SEC_VERSION, KEY_ADVINF, "", lpTempCmd, 8, szINFFile ) > 0 ) { g_Sess.uExtractOpt |= EXTRACTOPT_ADVDLL;
// re-use the buf here
lstrcpy( szOrigiCommand, *szCurrField ? szCurrField : achDefaultSection ); lstrcpy( lpTempCmd, szINFFile ); } else { g_Sess.uExtractOpt &= ~(EXTRACTOPT_ADVDLL);
if (g_wOSVer == _OSVER_WIN9X) { pszINFEngine = "setupx.dll"; GetShortPathName( szINFFile, szINFFile, sizeof(szINFFile) ); } else pszINFEngine = "setupapi.dll";
wsprintf( lpTempCmd, achSETUPDLL, pszINFEngine, *szCurrField ? szCurrField : achDefaultSection, szINFFile ); } } else if ( ((szExt = ANSIStrRChr( szCurrField, '.' )) != NULL) && !lstrcmpi( szExt, ".BAT" ) ) { lpTempCmd = (LPSTR) LocalAlloc( LPTR, lstrlen( szBATCommand ) + lstrlen( szINFFile ) + 8 ); if ( ! lpTempCmd ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); return FALSE; }
wsprintf( lpTempCmd, szBATCommand, szINFFile ); } else { // assume EXE command
// you are here, the szINFFile contains the command with fully qualified pathname enterred either
// by User or appended by wextract.exe to Temp extracting file location.
DWORD dwAttr; CHAR szCmd[2*MAX_STRING]; lpTempCmd = (LPSTR) LocalAlloc( LPTR, 2*MAX_STRING ); // 1K buf
if ( ! lpTempCmd ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); return FALSE; }
dwAttr = GetFileAttributes( szINFFile ); if ( (dwAttr == -1) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) { // file is not found as it IS. Run it as it WAS!
// IS and WAS may be the same if user enterred fully qaulified name. CreateProcess will buff it.
lstrcpy( szCmd, szOrigiCommand ); } else { // found it. Run it as it IS. Need to append switches if there is any.
lstrcpy( szCmd, szINFFile ); if ( szNextField && *szNextField ) { lstrcat( szCmd, " " ); lstrcat( szCmd, szNextField ); } } // replace the #D with the directory this module is loaded or
// #E with the fullpath of the running EXE
ExpandCmdParams( szCmd, lpTempCmd );
}
*lplpCommand = lpTempCmd;
return TRUE; }
void DisplayHelp() { MsgBox1Param( NULL, IDS_HELPMSG, "", MB_ICONINFORMATION, MB_OK ); }
DWORD CheckReboot( VOID ) { DWORD dwReturn = 0xFFFFFFFF;
if ( !g_uInfRebootOn ) { if (NeedReboot(g_dwRebootCheck, g_wOSVer)) dwReturn = EWX_REBOOT;
} else dwReturn = EWX_REBOOT; // reboot = 1 in inf file
return dwReturn;
}
// NT reboot
//
BOOL MyNTReboot() { HANDLE hToken; TOKEN_PRIVILEGES tkp;
// get a token from this process
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) { ErrorMsg( NULL, IDS_ERR_OPENPROCTK ); return FALSE; }
// get the LUID for the shutdown privilege
LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid );
tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//get the shutdown privilege for this proces
if ( !AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0 ) ) { ErrorMsg( NULL, IDS_ERR_ADJTKPRIV ); return FALSE; }
// shutdown the system and force all applications to close
if (!ExitWindowsEx( EWX_REBOOT, 0 ) ) { ErrorMsg( NULL, IDS_ERR_EXITWINEX ); return FALSE; }
return TRUE; }
// Display a dialog asking the user to restart Windows, with a button that
// will do it for them if possible.
//
void MyRestartDialog( DWORD dwRebootMode ) { UINT id = IDCANCEL; DWORD dwReturn;
// only if you checked and REBOOT_YES is true, you are here
if ( dwRebootMode & REBOOT_ALWAYS ) { dwReturn = EWX_REBOOT; } else { dwReturn = CheckReboot(); }
if ( dwReturn == EWX_REBOOT ) { if ( dwRebootMode & REBOOT_SILENT ) id = IDYES; else { id = MsgBox1Param( NULL, IDS_RESTARTYESNO, "", MB_ICONINFORMATION, MB_YESNO ); }
if ( id == IDYES ) { if ( dwReturn == EWX_REBOOT ) { if ( g_wOSVer == _OSVER_WIN9X ) { // By default (all platforms), we assume powerdown is possible
id = ExitWindowsEx( EWX_REBOOT, 0 ); } else { MyNTReboot(); } }
} } return; }
// CleanRegRunOnce()
//
void CleanRegRunOnce() { HKEY hKey;
if ( g_szRegValName[0] == 0 ) { return; }
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS ) { RegDeleteValue( hKey, g_szRegValName ); RegCloseKey( hKey ); } return; }
void AddRegRunOnce() { HKEY hKey; DWORD dwDisposition; LPSTR szRegEntry; TCHAR szBuf[MAX_PATH] = ""; TCHAR szAdvpack[MAX_PATH] = ""; int i; DWORD dwTmp; HANDLE hSetupLibrary; BOOL fUseAdvpack = FALSE;
// prepare backup registry
if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) { // reg problem, but not block the process
return; }
// Check if key already exists -- if so, go with next number.
//
for (i=0; i<200; i++) { wsprintf( g_szRegValName, szRegValNameTemplate, i );
if ( RegQueryValueEx( hKey, g_szRegValName, 0, NULL, NULL, &dwTmp ) != ERROR_SUCCESS ) { // g_szRegValName now has the key name we need for this instance
break; } }
if ( i == 200 ) { // something is wrong, there are at lease 200 RunOnce enteries in the Registry
// bail out, don't add any more
RegCloseKey( hKey ); g_szRegValName[0] = 0; return; }
// check if ADVPACK in the system dir exports DelNodeRunDLL32;
// if so, use szRegValAdvpackTemplate, otherwise, use szRegValTemplate
GetSystemDirectory(szAdvpack, sizeof(szAdvpack)); AddPath(szAdvpack, ADVPACKDLL); if ((hSetupLibrary = LoadLibrary(szAdvpack)) != NULL) { fUseAdvpack = GetProcAddress(hSetupLibrary, "DelNodeRunDLL32") != NULL; FreeLibrary(hSetupLibrary); }
if (fUseAdvpack) { if (GetSystemDirectory(szBuf, sizeof(szBuf))) AddPath(szBuf, ""); } else { // get current EXE filename
//
if ( !GetModuleFileName( g_hInst, szBuf, (DWORD)sizeof(szBuf) ) ) { RegCloseKey( hKey ); return; } }
// alloc mem for store reg entry values
//
szRegEntry = (LPSTR) LocalAlloc( LPTR, lstrlen(szBuf) + lstrlen(g_Sess.achDestDir) + SMALL_BUF_LEN );
if ( !szRegEntry ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); RegCloseKey( hKey ); return; }
g_bConvertRunOnce = !fUseAdvpack;
wsprintf(szRegEntry, fUseAdvpack ? szRegValAdvpackTemplate : szRegValTemplate, szBuf, g_Sess.achDestDir);
RegSetValueEx( hKey, g_szRegValName, 0, REG_SZ, (CONST BYTE*)szRegEntry, lstrlen(szRegEntry)+1);
RegCloseKey(hKey); LocalFree( szRegEntry ); return; }
// Change the RunOnce entry that cleans up extracted files to use ADVPACK instead of wextract
void ConvertRegRunOnce() { if (*g_szRegValName) { HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegRunOnceKey, 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) { TCHAR szRegEntry[2 * MAX_PATH + sizeof(szRegValAdvpackTemplate)]; DWORD dwSize = sizeof(szRegEntry);
// read the old value data that uses wextract and get the extracted files dir
if (RegQueryValueEx(hKey, g_szRegValName, NULL, NULL, (LPBYTE) szRegEntry, &dwSize) == ERROR_SUCCESS) { TCHAR szSysDir[MAX_PATH] = "";
if (GetSystemDirectory(szSysDir, sizeof(szSysDir))) AddPath(szSysDir, "");
wsprintf(szRegEntry, szRegValAdvpackTemplate, szSysDir, g_Sess.achDestDir); RegSetValueEx(hKey, g_szRegValName, 0, REG_SZ, (CONST BYTE *) szRegEntry, lstrlen(szRegEntry) + 1); }
RegCloseKey(hKey); } }
return; }
void DeleteMyDir( LPSTR lpDir ) { char szFile[MAX_PATH]; WIN32_FIND_DATA fileData; HANDLE hFindFile;
if ( lpDir == NULL || *lpDir == '\0' ) return;
lstrcpy( szFile, lpDir ); lstrcat( szFile, "*" ); hFindFile = FindFirstFile( szFile, &fileData ); if ( hFindFile == INVALID_HANDLE_VALUE ) return;
do { lstrcpy( szFile, lpDir );
if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { if ( lstrcmp( fileData.cFileName, "." ) == 0 || lstrcmp( fileData.cFileName, ".." ) == 0 ) continue;
// delete the sub-dir
lstrcat( szFile, fileData.cFileName ); AddPath( szFile, ""); DeleteMyDir( szFile ); } else { // delete the file
lstrcat( szFile, fileData.cFileName ); SetFileAttributes( szFile, FILE_ATTRIBUTE_NORMAL ); DeleteFile( szFile ); } } while ( FindNextFile( hFindFile, &fileData ) );
FindClose( hFindFile ); RemoveDirectory( lpDir ); }
#if 0
//==================================================================
// AddPath()
//
void AddPath(LPSTR szPath, LPCSTR szName ) { LPSTR szTmp;
// Find end of the string
szTmp = szPath + lstrlen(szPath);
// If no trailing backslash then add one
if ( szTmp > szPath && *(AnsiPrev( szPath, szTmp )) != '\\' ) *(szTmp++) = '\\';
// Add new name to existing path string
while ( *szName == ' ' ) szName++; lstrcpy( szTmp, szName ); }
#endif
//---------------------------------------------------------------------------
// Returns TRUE if the given string is a UNC path.
//
// check if a path is a root path
//
// returns:
// TRUE for "X:\..." "\\foo\asdf\..."
// FALSE for others
BOOL IsRootPath(LPCSTR pPath) { if ( !pPath || (lstrlen(pPath) < 3) ) { return FALSE; }
// BUGBUG: this just smell like UNC, possible invalid UNC. If so,
// user will get error when later create process
if ( ( (*(pPath+1) == ':') && (*(pPath+2) == '\\') ) || // "X:\" case
( (*pPath == '\\') && (*(pPath + 1) == '\\' ) ) ) // UNC \\.... case
return TRUE; else return FALSE; }
// BUGBUG:BUGBUG:BUGBUG:BUGBUG
// The code below is duplicated in advpack.dll. If you do changed/fixes to this code
// make sure to also change the code in advpack.dll
// Returns the size of wininit.ini in the windows directory.
// 0 if not found
DWORD GetWininitSize() { TCHAR szPath[MAX_PATH]; HFILE hFile; DWORD dwSize = (DWORD)0; if ( GetWindowsDirectory( szPath, MAX_PATH ) ) { AddPath( szPath, "wininit.ini" );
// Make sure all changes have been saved to disk for accurate size reading
WritePrivateProfileString(NULL, NULL, NULL, szPath);
if ((hFile = _lopen(szPath, OF_READ|OF_SHARE_DENY_NONE)) != HFILE_ERROR) { dwSize = _llseek(hFile, 0L, FILE_END); _lclose(hFile); } } return dwSize; }
// Returns the size of the value lpcszValue under lpcszRegKey
// 0 if the registry key or the value were not found
DWORD GetRegValueSize(LPCSTR lpcszRegKey, LPCSTR lpcszValue) { HKEY hKey; DWORD dwValueSize = (DWORD)0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpcszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { if (RegQueryValueEx(hKey, lpcszValue, NULL, NULL, NULL,&dwValueSize) != ERROR_SUCCESS) dwValueSize = (DWORD)0; RegCloseKey(hKey); } return dwValueSize; }
// Returns the number of Values in the key
// 0 if the registry key was not found or RegQueryInfoKey failed
DWORD GetNumberOfValues(LPCSTR lpcszRegKey) { HKEY hKey; DWORD dwValueSize = (DWORD)0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpcszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) dwValueSize = (DWORD)0; RegCloseKey(hKey); } return dwValueSize; }
// Returns the rebootcheck value depending on the OS we get passed in.
DWORD NeedRebootInit(WORD wOSVer) { DWORD dwReturn = (DWORD)0;
switch (wOSVer) { case _OSVER_WIN9X: dwReturn = GetWininitSize(); break;
case _OSVER_WINNT40: case _OSVER_WINNT50: dwReturn = GetRegValueSize(szNT4XDelayUntilReboot, szNT4XPendingValue); break;
case _OSVER_WINNT3X: dwReturn = GetNumberOfValues(szNT3XDelayUntilReboot); break;
} return dwReturn; }
// Checks the passed in reboot check value against the current value.
// If they are different, we need to reboot.
// The reboot check value is dependend on the OS
BOOL NeedReboot(DWORD dwRebootCheck, WORD wOSVer) { return (dwRebootCheck != NeedRebootInit(wOSVer)); }
// check if Dir does not exist, create one.
//
BOOL IfNotExistCreateDir( LPTSTR lpDir ) { DWORD attr;
if ( (attr = GetFileAttributes( lpDir )) == -1 ) { return ( CreateDirectory( lpDir, NULL ) ); }
return (attr & FILE_ATTRIBUTE_DIRECTORY); }
// check if the given dir is on Windows Drive
//
BOOL IsWindowsDrive( LPTSTR szPath ) { TCHAR szWin[MAX_PATH];
if ( !GetWindowsDirectory( szWin, MAX_PATH ) ) { ErrorMsg( NULL, IDS_ERR_GET_WIN_DIR ); ASSERT( FALSE ); }
return ( *szPath == szWin[0] ); }
PSTR MyULtoA( ULONG ulParam, PSTR pszOut ) { wsprintf( pszOut, "%lu", ulParam ); return pszOut; }
// display diskspace checking Error message
// it always return FALSE except that User answer YES on msgbox
//
BOOL DiskSpaceErrMsg( UINT msgType, ULONG ulExtractNeeded, DWORD dwInstNeeded, LPTSTR lpDrv ) { TCHAR szSize[10]; BOOL bRet = FALSE;
// all the cases except one are returning FALSE, so we set Error code here
g_dwExitCode = ERROR_DISK_FULL;
if ( msgType == MSG_REQDSK_ERROR ) { ErrorMsg1Param( NULL, IDS_ERR_NO_SPACE_ERR, MyULtoA((ulExtractNeeded+dwInstNeeded), szSize) ); } else if ( msgType == MSG_REQDSK_RETRYCANCEL ) { if ( MsgBox1Param( NULL, IDS_ERR_NO_SPACE_BOTH, MyULtoA( (ulExtractNeeded+dwInstNeeded), szSize), MB_ICONQUESTION, MB_RETRYCANCEL|MB_DEFBUTTON1 ) == IDRETRY ) bRet = TRUE; else bRet = FALSE; } else if ( msgType == MSG_REQDSK_WARN ) { // in /Q mode: MsgBox2Param return MB_OK which is not IDYES, so we fail the process.
//
if ( MsgBox2Param( NULL, IDS_ERR_NO_SPACE_INST, MyULtoA(dwInstNeeded, szSize), lpDrv, MB_ICONINFORMATION, MB_YESNO | MB_DEFBUTTON2 ) == IDYES ) { bRet = TRUE; g_dwExitCode = S_OK; } } //else ( msgType == MSG_REQDSK_NONE ) do nothing
return bRet; }
BOOL GetFileTobeChecked( LPSTR szPath, int iSize, LPCSTR szNameStr ) { char ch; BOOL bComplete = FALSE; szPath[0] = 0; if ( *szNameStr == '#' ) { ch = (CHAR)CharUpper((PSTR)*(++szNameStr)); szNameStr = CharNext( CharNext( szNameStr ) );
switch ( ch ) { case 'S': GetSystemDirectory( szPath, iSize ); break;
case 'W': GetWindowsDirectory( szPath, iSize ); break;
case 'A': default: { // look into reg AppPath
char szSubKey[MAX_PATH]; DWORD dwSize = sizeof( szSubKey ); HKEY hKey; DWORD dwType; lstrcpy( szSubKey, REGSTR_PATH_APPPATHS ); AddPath( szSubKey, szNameStr ); if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) { if ( RegQueryValueEx(hKey, "", NULL, &dwType, (LPBYTE)szPath, &dwSize) == ERROR_SUCCESS ) { if ((dwType == REG_EXPAND_SZ) && (ExpandEnvironmentStrings(szPath, szSubKey, sizeof(szSubKey)))) { lstrcpy(szPath, szSubKey); bComplete = TRUE; } else if (dwType == REG_SZ) bComplete = TRUE; }
RegCloseKey( hKey ); } } break;
} } else GetSystemDirectory( szPath, iSize );
if ( !bComplete ) AddPath( szPath, szNameStr );
return TRUE; }
BOOL CheckFileVersion( PTARGETVERINFO ptargetVers, LPSTR szPath, int isize, int *pidx ) { unsigned uiSize; DWORD dwVerInfoSize; DWORD dwHandle; VS_FIXEDFILEINFO * lpVSFixedFileInfo; void FAR *lpBuffer; HGLOBAL hgbl = NULL; BOOL bRet = FALSE; int ifrAnswer[2], itoAnswer[2], i, j; PVERCHECK pfileV;
for ( i=0; i< (int)(ptargetVers->dwNumFiles); i++ ) { pfileV = (PVERCHECK)( ptargetVers->szBuf + ptargetVers->dwFileOffs + i*sizeof(VERCHECK) ); if ( !GetFileTobeChecked( szPath, isize, (ptargetVers->szBuf + pfileV->dwNameOffs) ) ) goto EXIT;
dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle); if (dwVerInfoSize) { // Alloc the memory for the version stamping
hgbl = GlobalAlloc(GHND, dwVerInfoSize); if (hgbl == NULL) goto EXIT;
lpBuffer = GlobalLock(hgbl); if (lpBuffer == NULL) goto EXIT; // Read version stamping info
if (GetFileVersionInfo(szPath, dwHandle, dwVerInfoSize, lpBuffer)) { // Get the value for Translation
if ( VerQueryValue(lpBuffer, "\\", (void FAR*FAR*)&lpVSFixedFileInfo, &uiSize) && (uiSize) ) { for ( j=0; j<2; j++ ) { ifrAnswer[j] = CompareVersion( lpVSFixedFileInfo->dwFileVersionMS, lpVSFixedFileInfo->dwFileVersionLS, pfileV->vr[j].frVer.dwMV, pfileV->vr[j].frVer.dwLV ); itoAnswer[j] = CompareVersion( lpVSFixedFileInfo->dwFileVersionMS, lpVSFixedFileInfo->dwFileVersionLS, pfileV->vr[j].toVer.dwMV, pfileV->vr[j].toVer.dwLV ); }
if ( (ifrAnswer[0] >= 0 && itoAnswer[0] <= 0) || (ifrAnswer[1] >= 0 && itoAnswer[1] <= 0) ) ; else { GlobalUnlock(hgbl); goto EXIT; }
} } GlobalUnlock(hgbl); } else { // file not exist case, if author specify install 1st ranges from version 0 to 0. Then do it!
if ( pfileV->vr[0].frVer.dwMV || pfileV->vr[0].frVer.dwLV ) { goto EXIT; } } } bRet = TRUE;
EXIT: *pidx = i; if ( hgbl ) GlobalFree( hgbl );
return bRet; }
UINT GetMsgboxFlag( DWORD dwFlag ) { UINT uButton;
if ( dwFlag & VERCHK_YESNO ) uButton = MB_YESNO | MB_DEFBUTTON2; else if ( dwFlag & VERCHK_OKCANCEL ) uButton = MB_OKCANCEL | MB_DEFBUTTON2; else uButton = MB_OK;
return uButton; }
int CompareVersion(DWORD dwMS1, DWORD dwLS1, DWORD dwMS2, DWORD dwLS2) { if (dwMS1 < dwMS2) return -1 ;
if (dwMS1 > dwMS2) return 1 ;
if (dwLS1 < dwLS2) return -1 ;
if (dwLS1 > dwLS2) return 1 ;
return 0 ; }
void ExpandCmdParams( PCSTR pszInParam, PSTR pszOutParam ) { CHAR szModulePath[MAX_PATH]; LPSTR pszTmp;
*pszOutParam = '\0';
if ( !pszInParam || !*pszInParam ) return;
// get Module path
GetModuleFileName( g_hInst, szModulePath, (DWORD)sizeof(szModulePath) ); while ( *pszInParam != '\0' ) { if (IsDBCSLeadByte(*pszInParam)) { *pszOutParam = *pszInParam; *(pszOutParam+1) = *(pszInParam+1); } else *pszOutParam = *pszInParam;
if ( *pszInParam == '#' ) { pszInParam = CharNext(pszInParam); if ( (CHAR)CharUpper((PSTR)*pszInParam) == 'D' ) { GetParentDir( szModulePath ); pszTmp = CharPrev(szModulePath, &szModulePath[lstrlen(szModulePath)]); if (pszTmp && (*pszTmp == '\\')) *pszTmp = '\0'; lstrcpy( pszOutParam, szModulePath ); pszOutParam += lstrlen( szModulePath ); } else if ( (CHAR)CharUpper((PSTR)*pszInParam) == 'E' ) { lstrcpy( pszOutParam, szModulePath ); pszOutParam += lstrlen( szModulePath ); } else if ( *pszInParam == '#' ) pszOutParam = CharNext( pszOutParam ); } else pszOutParam = CharNext( pszOutParam );
pszInParam = CharNext(pszInParam); }
*pszOutParam = '\0'; }
|