|
|
//***************************************************************************
//* Copyright (c) Microsoft Corporation 1995-1996. All rights reserved. *
//***************************************************************************
//* *
//* ADVPACK.C - Advanced helper-dll for WExtract. *
//* *
//***************************************************************************
//***************************************************************************
//* INCLUDE FILES *
//***************************************************************************
#include <io.h>
#include <windows.h>
#include <winerror.h>
#include <ole2.h>
#include "resource.h"
#include "cpldebug.h"
#include "ntapi.h"
#include "advpub.h"
#include "w95pub32.h"
#include "advpack.h"
#include "regstr.h"
#include "globals.h"
#include "sfp.h"
//***************************************************************************
//* GLOBAL VARIABLES *
//***************************************************************************
GETSETUPXERRORTEXT32 pfGetSETUPXErrorText32 = NULL; CTLSETLDDPATH32 pfCtlSetLddPath32 = NULL; GENINSTALL32 pfGenInstall32 = NULL; GENFORMSTRWITHOUTPLACEHOLDERS32 pfGenFormStrWithoutPlaceHolders32 = NULL;
typedef HRESULT (*DLLINSTALL)(BOOL bInstall, LPCWSTR pszCmdLine);
HFONT g_hFont = NULL;
LPCSTR c_szAdvDlls[3] = { "advpack.dll", "w95inf16.dll", "w95inf32.dll", };
LPCSTR c_szSetupAPIDlls[2] = { "setupapi.dll", "cfgmgr32.dll" };
LPCSTR c_szSetupXDlls[1] = { "setupx.dll" };
#define UPDHLPDLLS_FORCED 0x00000001
#define UPDHLPDLLS_ALERTREBOOT 0x00000002
#define MAX_NUM_DRIVES 26
const CHAR c_szQRunPreSetupCommands[] = "QRunPreSetupCommands"; const CHAR c_szQRunPostSetupCommands[] = "QRunPostSetupCommands"; const CHAR c_szRunPreSetupCommands[] = "RunPreSetupCommands"; const CHAR c_szRunPostSetupCommands[] = "RunPostSetupCommands";
BOOL IsDrvChecked( char chDrv ); void SetControlFont(); void SetFontForControl(HWND hwnd, UINT uiID); void MyGetPlatformSection(LPCSTR lpSec, LPCSTR lpInfFile, LPSTR szNewSection);
//***************************************************************************
//* *
//* NAME: DllMain *
//* *
//* SYNOPSIS: Main entry point for the DLL. *
//* *
//* REQUIRES: hInst: Handle to the DLL instance. *
//* dwReason: Reason for calling this entry point. *
//* dwReserved: Nothing *
//* *
//* RETURNS: BOOL: TRUE if DLL loaded OK, FALSE otherwise. *
//* *
//***************************************************************************
BOOL WINAPI DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID dwReserved ) { switch (dwReason) { case DLL_PROCESS_ATTACH: // The DLL is being loaded for the first time by a given process.
// Perform per-process initialization here. If the initialization
// is successful, return TRUE; if unsuccessful, return FALSE.
//Initialize the global variable holding the hinstance:
g_hInst = hInst;
// check if need to start the logging file.
if ( g_hAdvLogFile == INVALID_HANDLE_VALUE) { AdvStartLogging(); } AdvWriteToLog("-------------------- advpack.dll is loaded or Attached ------------------------------\r\n"); AdvLogDateAndTime();
break;
case DLL_PROCESS_DETACH: // The DLL is being unloaded by a given process. Do any
// per-process clean up here, such as undoing what was done in
// DLL_PROCESS_ATTACH. The return value is ignored.
// if logging is turned on, close here.
AdvWriteToLog("-------------------- advpack.dll is unloaded or Detached ----------------------------\r\n"); AdvStopLogging();
break ;
case DLL_THREAD_ATTACH: // A thread is being created in a process that has already loaded
// this DLL. Perform any per-thread initialization here. The
// return value is ignored.
//Initialize the global variable holding the hinstance --
//NOTE: this is probably taken care of already by DLL_PROCESS_ATTACH.
break;
case DLL_THREAD_DETACH: // A thread is exiting cleanly in a process that has already
// loaded this DLL. Perform any per-thread clean up here. The
// return value is ignored.
break; } return TRUE; }
//***************************************************************************
//* *
//* NAME: DoInfInstall *
//* *
//* SYNOPSIS: Installs an (advanced) INF file on Win95 or WinNT. *
//* *
//* REQUIRES: AdvPackArgs: Structure containing required info. See *
//* AdvPack.H. *
//* *
//* RETURNS: BOOL: TRUE if successful, FALSE otherwise. *
//* *
//***************************************************************************
HRESULT WINAPI DoInfInstall( ADVPACKARGS *AdvPackArgs ) { BOOL fSavedContext = FALSE; HRESULT hr = E_FAIL; DWORD dwFlags;
AdvWriteToLog("DoInfInstall: InfFile=%1\r\n", AdvPackArgs->lpszInfFilename); if (!SaveGlobalContext()) { hr = E_OUTOFMEMORY; goto done; } fSavedContext = TRUE;
ctx.hWnd = AdvPackArgs->hWnd; ctx.lpszTitle = AdvPackArgs->lpszTitle; ctx.wOSVer = AdvPackArgs->wOSVer; ctx.wQuietMode = (WORD) (0xFFFF & AdvPackArgs->dwFlags); ctx.bCompressed = (AdvPackArgs->dwFlags & ADVFLAGS_COMPRESSED ) ? TRUE : FALSE; ctx.bUpdHlpDlls = (AdvPackArgs->dwFlags & ADVFLAGS_UPDHLPDLLS) ? TRUE : FALSE;
dwFlags = (AdvPackArgs->dwFlags & ADVFLAGS_NGCONV) ? 0 : COREINSTALL_GRPCONV; dwFlags |= (AdvPackArgs->dwFlags & ADVFLAGS_DELAYREBOOT) ? COREINSTALL_DELAYREBOOT : 0; dwFlags |= (AdvPackArgs->dwFlags & ADVFLAGS_DELAYPOSTCMD) ? COREINSTALL_DELAYPOSTCMD : 0;
hr = CoreInstall( AdvPackArgs->lpszInfFilename, AdvPackArgs->lpszInstallSection, AdvPackArgs->lpszSourceDir, AdvPackArgs->dwPackInstSize, dwFlags, NULL ); done: if (fSavedContext) { RestoreGlobalContext(); } AdvWriteToLog("DoInfInstall: %1 End hr=0x%2!x!\r\n", AdvPackArgs->lpszInfFilename, hr); return hr; }
//***************************************************************************
//* *
//* NAME: LaunchINFSection *
//* *
//* SYNOPSIS: Entry point for RunDLL. Takes string parameter and parses *
//* it, then performs GenInstall. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
INT WINAPI LaunchINFSection( HWND hwndOwner, HINSTANCE hInstance, PSTR pszParms, INT nShow ) { CHAR szTitle[256] = "Advanced INF Install"; PSTR pszInfFilename = NULL; PSTR pszSection = NULL; PSTR pszFlags = NULL; PSTR pszSmartReboot = NULL; DWORD dwFlags = 0; LPSTR pszTemp = NULL; CHAR chTempChar = '\0'; CHAR szSourceDir[MAX_PATH]; CHAR szFilename[MAX_PATH]; UINT uiErrid = 0; PSTR pszErrParm1 = NULL; int iRet = 1; // meaningless return
BOOL fSavedContext = FALSE;
AdvWriteToLog("LaunchINFSection: Param=%1\r\n", pszParms); if (!SaveGlobalContext()) { goto done; }
fSavedContext = TRUE;
ctx.lpszTitle = szTitle;
// Parse the arguments, the last param to GetStringField to ask what quote char to check
pszInfFilename = GetStringField( &pszParms, ",", '\"', TRUE ); pszSection = GetStringField( &pszParms, ",", '\"', TRUE ); pszFlags = GetStringField( &pszParms, ",", '\"', TRUE ); pszSmartReboot = GetStringField( &pszParms, ",", '\"', TRUE );
if ( pszFlags != NULL ) { dwFlags = My_atol(pszFlags); }
if ( dwFlags & LIS_QUIET ) { ctx.wQuietMode = QUIETMODE_ALL; }
if ( pszInfFilename == NULL || *pszInfFilename == '\0' ) { uiErrid = IDS_ERR_BAD_SYNTAX; goto done; }
if ( ! GetFullPathName( pszInfFilename, sizeof(szFilename), szFilename, &pszTemp ) ) { uiErrid = IDS_ERR_GET_PATH; pszErrParm1 = pszInfFilename; goto done; }
if ( GetFileAttributes( szFilename ) == 0xFFFFFFFF ) { // If the file doesn't exist in the current directory, check the
// Windows\inf directory
if ( !GetWindowsDirectory( szFilename, sizeof( szFilename ) ) ) { uiErrid = IDS_ERR_GET_WIN_DIR; goto done; }
AddPath( szFilename, "inf" ); lstrcpy( szSourceDir, szFilename );
if ( (lstrlen(szFilename)+lstrlen(pszInfFilename)+2) > MAX_PATH ) { uiErrid = IDS_ERR_CANT_FIND_FILE; pszErrParm1 = pszInfFilename; goto done; }
AddPath( szFilename, pszInfFilename );
if ( GetFileAttributes( szFilename ) == 0xFFFFFFFF ) { uiErrid = IDS_ERR_CANT_FIND_FILE; pszErrParm1 = pszInfFilename; goto done; } } else { // Generate the source directory from the inf path.
chTempChar = *pszTemp; *pszTemp = '\0'; lstrcpy( szSourceDir, szFilename ); *pszTemp = chTempChar; }
if ( !FAILED( CoreInstall( szFilename, pszSection, szSourceDir, 0, COREINSTALL_PROMPT | ((dwFlags & LIS_NOGRPCONV)?0:COREINSTALL_GRPCONV) | COREINSTALL_SMARTREBOOT, pszSmartReboot ) ) ) { if (fSavedContext) { RestoreGlobalContext(); } AdvWriteToLog("LaunchINFSection: %1 End Succeed\r\n", szFilename); return 0; }
done:
if ( uiErrid != 0 ) ErrorMsg1Param( ctx.hWnd, uiErrid, pszErrParm1 );
if (fSavedContext) { RestoreGlobalContext(); } AdvWriteToLog("LaunchINFSection: %1 End Failed\r\n", szFilename); return 1; }
//***************************************************************************
//* *
//* NAME: RunSetupCommand *
//* *
//* SYNOPSIS: Download Component entry point. Runs a setup command. *
//* *
//* REQUIRES: hWnd: Handle to parent window. *
//* szCmdName: Name of command to run (INF or EXE) *
//* szInfSection: INF section to install with. NULL=default *
//* szDir: Directory containing source files *
//* lpszTitle: Name to attach to windows. *
//* phEXE: Handle of EXE to wait on. *
//* dwFlags: Various flags to control behavior (advpub.h)*
//* pvReserved: Reserved for future use. *
//* *
//* RETURNS: HRESULT: See advpub.h *
//* *
//***************************************************************************
HRESULT WINAPI RunSetupCommand( HWND hWnd, LPCSTR szCmdName, LPCSTR szInfSection, LPCSTR szDir, LPCSTR lpszTitle, HANDLE *phEXE, DWORD dwFlags, LPVOID pvReserved ) { HRESULT hReturnCode = S_OK; DWORD dwRebootCheck = 0; DWORD dwCoreInstallFlags = 0; BOOL fSavedContext = FALSE;
AdvWriteToLog("RunSetupCommand:"); if (!SaveGlobalContext()) { hReturnCode = E_OUTOFMEMORY; goto done; }
fSavedContext = TRUE;
// Validate parameters:
if ( szCmdName == NULL || szDir == NULL ) { return E_INVALIDARG; }
AdvWriteToLog(" Cmd=%1\r\n", szCmdName); ctx.hWnd = hWnd; ctx.lpszTitle = (LPSTR) lpszTitle;
// If caller passes invalid HWND, we will silently turn off UI.
// NULL uses Desktop as window and passing INVALID_HANDLE sets quiet mode.
if ( hWnd && !IsWindow(hWnd) ) { dwFlags |= RSC_FLAG_QUIET; hWnd = NULL; }
if ( dwFlags & RSC_FLAG_QUIET ) { ctx.wQuietMode = QUIETMODE_ALL; } else { ctx.wQuietMode = 0; }
ctx.bUpdHlpDlls = ( dwFlags & RSC_FLAG_UPDHLPDLLS ) ? TRUE : FALSE;
// Check flags to see if it's an INF command
if ( dwFlags & RSC_FLAG_INF ) { if(!(dwFlags & RSC_FLAG_NGCONV)) dwCoreInstallFlags |= COREINSTALL_GRPCONV;
if (dwFlags & RSC_FLAG_DELAYREGISTEROCX) dwCoreInstallFlags |= COREINSTALL_DELAYREGISTEROCX;
if (dwFlags & RSC_FLAG_SETUPAPI ) dwCoreInstallFlags |= COREINSTALL_SETUPAPI;
hReturnCode = CoreInstall( (PSTR) szCmdName, szInfSection, (PSTR) szDir, 0, dwCoreInstallFlags, NULL );
if ( FAILED( hReturnCode ) ) { goto done; } } else { if ( ! CheckOSVersion() ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); goto done; }
dwRebootCheck = InternalNeedRebootInit( ctx.wOSVer );
hReturnCode = LaunchAndWait( (LPSTR)szCmdName, (LPSTR)szDir, phEXE, INFINITE, 0 ); if ( hReturnCode == S_OK ) { if ( phEXE ) hReturnCode = S_ASYNCHRONOUS; } else { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
if ( hReturnCode == S_OK && InternalNeedReboot( dwRebootCheck, ctx.wOSVer ) ) { hReturnCode = ERROR_SUCCESS_REBOOT_REQUIRED; } }
done:
if (fSavedContext) { RestoreGlobalContext(); } AdvWriteToLog("RunSetupCommand: Cmd=%1 End hr=0x%2!x!\r\n", szCmdName, hReturnCode); return hReturnCode; }
//***************************************************************************
//* *
//* NAME: GetInfInstallSectionName *
//* *
//* SYNOPSIS: Gets the name of the section to install with. *
//* *
//* REQUIRES: szInfFilename: Name of INF to find install section in. *
//* szInfSection: Name of INF section to install with. If *
//* NULL, then return required size of string. *
//* If "\0", use DefaultInstall. If *
//* "DefaultInstall" and running NT, then check *
//* for "DefaultInstall.NT section. Anything *
//* else will leave the section name alone. *
//* dwSize: Size of szInfSection buffer. If not big *
//* enough to hold string, then required size *
//* is returned. *
//* *
//* RETURNS: DWORD: 0 if error, otherwise size of section name. *
//* *
//***************************************************************************
DWORD WINAPI GetInfInstallSectionName( LPCSTR pszInfFilename, LPSTR pszInfSection, DWORD dwSize ) { CHAR achTemp[5]; char szGivenInfSection[MAX_PATH]; char szNewInfSection[MAX_PATH]; DWORD dwStringLength; DWORD dwRequiredSize; static const CHAR achDefaultInstall[] = "DefaultInstall"; //static const CHAR achDefaultInstallNT[] = "DefaultInstall.NT";
// On NTx86:
//(1) if [<Sec>.NTx86] present, this section get GenInstall, exit.
//(2) if (1) is not present, [<sec>.NT] present and get GenInstal, exitl;
//(3) if both [<sec>.NTx86] and [<Sec>.NT] not present, [<Sec>] section get GenInstall;
//(4) if none of the sections in (1), (2), (3) exist, do nothing.
// the same logic apply to NTAlpha as well.
// On win9x:
//(1) if [<sec>.Win] present, GetInstall it.
//(2) if (1) is not present, GenInstall [<Sec>]
// otherwise, do nothing.
if ( ! CheckOSVersion() ) { return 0; }
// If we were passed a NULL for the install section, then assume
// they want the "DefaultInstall" section.
if ( pszInfSection == NULL || (*pszInfSection) == '\0' ) lstrcpy(szGivenInfSection, achDefaultInstall); else lstrcpy(szGivenInfSection, pszInfSection);
MyGetPlatformSection(szGivenInfSection, pszInfFilename, szNewInfSection);
dwRequiredSize = lstrlen( szNewInfSection ) + 1; if ( pszInfSection != NULL && (dwRequiredSize <= dwSize) ) { lstrcpy( pszInfSection, szNewInfSection ); }
return dwRequiredSize; }
//***************************************************************************
//* *
//* NAME: NeedRebootInit *
//* *
//* SYNOPSIS: Self-registers the OCX. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
DWORD WINAPI NeedRebootInit( VOID ) { if ( ! CheckOSVersion() ) { return 0; }
return InternalNeedRebootInit( ctx.wOSVer ); }
//***************************************************************************
//* *
//* NAME: NeedReboot *
//* *
//* SYNOPSIS: Self-registers the OCX. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL WINAPI NeedReboot( DWORD dwRebootCheck ) { if ( ! CheckOSVersion() ) { return 0; }
return InternalNeedReboot( dwRebootCheck, ctx.wOSVer ); }
//***************************************************************************
//* *
//* NAME: TranslateInfString *
//* *
//* SYNOPSIS: Translates a string in an Advanced inf file -- replaces *
//* LDIDs with the directory. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT WINAPI TranslateInfString( PCSTR pszInfFilename, PCSTR pszInstallSection, PCSTR pszTranslateSection, PCSTR pszTranslateKey, PSTR pszBuffer, DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved ) { HRESULT hReturnCode = S_OK; CHAR szRealInstallSection[256]; BOOL fSavedContext = FALSE; DWORD dwFlags = 0;
AdvWriteToLog("TranslateInfString:" ); if (!SaveGlobalContext()) { hReturnCode = E_OUTOFMEMORY; goto done; } fSavedContext = TRUE;
ctx.wQuietMode = QUIETMODE_ALL;
// Validate parameters
if ( pszInfFilename == NULL || pszTranslateSection == NULL || pszTranslateKey == NULL || pdwRequiredSize == NULL ) { hReturnCode = E_INVALIDARG; goto done; }
AdvWriteToLog("Inf=%1 Sec=%2 Key=%3\r\n", pszInfFilename, pszTranslateSection, pszTranslateKey);
if ((ULONG_PTR)pvReserved & (ULONG_PTR)RSC_FLAG_SETUPAPI ) dwFlags |= COREINSTALL_SETUPAPI;
hReturnCode = CommonInstallInit( pszInfFilename, pszInstallSection, szRealInstallSection, sizeof(szRealInstallSection), NULL, FALSE, dwFlags ); if ( FAILED( hReturnCode ) ) { goto done; }
hReturnCode = SetLDIDs( (LPSTR) pszInfFilename, szRealInstallSection, 0, NULL ); if ( FAILED( hReturnCode ) ) { goto done; }
hReturnCode = GetTranslatedString( pszInfFilename, pszTranslateSection, pszTranslateKey, pszBuffer, dwBufferSize, pdwRequiredSize ); if ( FAILED( hReturnCode ) ) { goto done; }
done:
CommonInstallCleanup(); if (fSavedContext) { RestoreGlobalContext(); } AdvWriteToLog("TranslateInfString: End hr=0x%1!x!\r\n",hReturnCode); return hReturnCode; }
//***************************************************************************
//* *
//* NAME: RegisterOCX *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
INT WINAPI RegisterOCX( HWND hwndOwner, HINSTANCE hInstance, PSTR pszParms, INT nShow ) { CHAR szTitle[] = "Advpack RegisterOCX()"; BOOL fOleInitialized = TRUE; INT nReturnCode = 0; REGOCXDATA RegOCX = { 0 };
AdvWriteToLog("RegisterOCX: Param=%1\r\n", pszParms); ctx.lpszTitle = szTitle;
// Parse the arguments, SETUP engine has processed \" so we only need to check on \'
RegOCX.pszOCX = GetStringField( &pszParms, ",", '\"', TRUE ); RegOCX.pszSwitch = GetStringField( &pszParms, ",", '\"', TRUE ); RegOCX.pszParam = GetStringField( &pszParms, ",", '\"', TRUE );
if ( RegOCX.pszOCX == NULL || *(RegOCX.pszOCX) == '\0' ) { ErrorMsg( ctx.hWnd, IDS_ERR_BAD_SYNTAX2 ); nReturnCode = 1; goto done; }
if ( FAILED( OleInitialize( NULL ) ) ) { fOleInitialized = FALSE; }
// single OCX register, use 0, 0 for last params
//
if ( ! InstallOCX( &RegOCX, TRUE, TRUE, 0 ) ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_REG_OCX, RegOCX.pszOCX ); nReturnCode = 1; }
done:
if ( fOleInitialized ) { OleUninitialize(); } AdvWriteToLog("RegisterOCX: Param=%1 End status=%2\r\n", RegOCX.pszOCX, (nReturnCode==0)?"Succeed":"Failed"); return nReturnCode; }
//***************************************************************************
//* *
//* NAME: CommonInstallInit *
//* *
//* SYNOPSIS: *
//* *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT CommonInstallInit( PCSTR c_pszInfFilename, PCSTR c_pszSection, PSTR pszRealSection, DWORD dwRealSectionSize, PCSTR c_pszSourceDir, BOOL fUpdDlls, DWORD dwFlags ) { HRESULT hReturnCode = S_OK; DWORD dwSize = 0;
if ( ! CheckOSVersion() ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); goto done; }
if ( ! ctx.fOSSupportsINFInstalls ) { ErrorMsg( ctx.hWnd, IDS_ERR_NO_INF_INSTALLS ); hReturnCode = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); goto done; }
if ( c_pszSection == NULL ) { *pszRealSection = '\0'; } else { lstrcpy( pszRealSection, c_pszSection ); }
dwSize = GetInfInstallSectionName( c_pszInfFilename, pszRealSection, dwRealSectionSize ); if ( dwSize == 0 || dwSize > dwRealSectionSize ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto done; }
if ( ! LoadSetupLib( c_pszInfFilename, pszRealSection, fUpdDlls, dwFlags ) ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
if ( ctx.dwSetupEngine == ENGINE_SETUPAPI ) { if ( FAILED(hReturnCode = MySetupOpenInfFile( c_pszInfFilename)) ) goto done; }
if ( c_pszSourceDir != NULL ) { hReturnCode = SetLDIDs( c_pszInfFilename, pszRealSection, 0, c_pszSourceDir ); if ( FAILED(hReturnCode) ) { goto done; } }
if ( ! IsGoodAdvancedInfVersion( c_pszInfFilename ) ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); goto done; }
done:
return hReturnCode; }
//***************************************************************************
//* *
//* NAME: CommonInstallCleanup *
//* *
//* SYNOPSIS: *
//* *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
VOID CommonInstallCleanup( VOID ) { if ( ctx.dwSetupEngine == ENGINE_SETUPAPI ) { MySetupCloseInfFile(); }
UnloadSetupLib(); }
//***************************************************************************
//* *
//* NAME: CoreInstall *
//* *
//* SYNOPSIS: Installs an (advanced) INF file on Win95 or WinNT. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT CoreInstall( PCSTR c_pszInfFilename, PCSTR c_pszSection, PCSTR c_pszSourceDir, DWORD dwInstallSize, DWORD dwFlags, PCSTR pcszSmartRebootOverride ) { static const CHAR c_szSmartReboot[] = "SmartReboot"; static const CHAR c_szSmartRebootDefault[] = "I"; HRESULT hReturnCode = S_OK; DWORD dwRebootCheck = 0; BOOL fNeedReboot = FALSE; HKEY hkey = NULL; CHAR szInstallSection[256]; CHAR szTitle[256]; PSTR pszOldTitle = NULL; UINT id = IDCANCEL; BOOL fRebootCheck = TRUE; CHAR szSmartRebootValue[4]; // Allocate 4 chars for SmartReboot value
BOOL fRealNeedReboot = FALSE; CHAR szCatalogName[512] = "";
#define GRPCONV "grpconv.exe -o"
AdvWriteToLog("CoreInstall: InfFile=%1 ", c_pszInfFilename); lstrcpy( szSmartRebootValue, c_szSmartRebootDefault );
hReturnCode = CommonInstallInit( c_pszInfFilename, c_pszSection, szInstallSection, sizeof(szInstallSection), c_pszSourceDir, TRUE, dwFlags ); if ( FAILED( hReturnCode ) ) { goto done; } AdvWriteToLog("InstallSection=%1\r\n", szInstallSection); // check Admin right if INF specified
if (GetTranslatedInt(c_pszInfFilename, szInstallSection, ADVINF_CHKADMIN, 0)) { if ( (ctx.wOSVer != _OSVER_WIN95) && !IsNTAdmin( 0, NULL) ) { WORD wSav = ctx.wQuietMode;
ctx.wQuietMode |= QUIETMODE_SHOWMSG; hReturnCode = E_ABORT; ErrorMsg( ctx.hWnd, IDS_ERR_NONTADMIN ); ctx.wQuietMode = wSav; goto done; } }
if ( (dwFlags & COREINSTALL_PROMPT) && !(dwFlags & COREINSTALL_ROLLBACK) ) { pszOldTitle = ctx.lpszTitle; if ( BeginPrompt( c_pszInfFilename, szInstallSection, szTitle, sizeof(szTitle) ) == IDCANCEL ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_CANCELLED); goto done; } }
if ( !(dwFlags & COREINSTALL_DELAYREBOOT) ) dwRebootCheck = InternalNeedRebootInit( ctx.wOSVer );
// the flag is so far used to control the post setup commands, so pre setup command pass flag 0, NeedReboot FALSE
hReturnCode = RunCommandsSections( c_pszInfFilename, szInstallSection, c_szRunPreSetupCommands, c_pszSourceDir, 0, FALSE ); if ( FAILED( hReturnCode ) ) goto done;
// first set LDID, then all the INF processing can use LDIDs
hReturnCode = SetLDIDs( (PSTR) c_pszInfFilename, szInstallSection, dwInstallSize, NULL ); if ( FAILED( hReturnCode ) ) { goto done; }
hReturnCode = RunPatchingCommands( c_pszInfFilename, szInstallSection, c_pszSourceDir); if ( FAILED( hReturnCode ) ) { goto done; }
// Remove Old backup if needed; based on the ComponentVersion stamp in INF install section
//
if (!(dwFlags & COREINSTALL_ROLLBACK) ) RemoveBackupBaseOnVer( c_pszInfFilename, szInstallSection );
// get the catalog name, if specified
// BUGBUG: (pritobla): if not on Millen, where should we copy the catalog for migration scenario?
ZeroMemory(szCatalogName, sizeof(szCatalogName));
// if ROLLBKDOALL is specified, try to get the catalog name from the registry;
// if not found, get it from the inf
if (dwFlags & COREINSTALL_ROLLBKDOALL) { CHAR szModule[MAX_PATH];
*szModule = '\0'; GetTranslatedString(c_pszInfFilename, szInstallSection, ADVINF_MODNAME, szModule, sizeof(szModule), NULL); if (*szModule) { CHAR szKey[MAX_PATH]; HKEY hkCatalogKey;
lstrcpy(szKey, REGKEY_SAVERESTORE); AddPath(szKey, szModule); AddPath(szKey, REGSUBK_CATALOGS);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkCatalogKey) == ERROR_SUCCESS) { PSTR pszCatalog; DWORD dwIndex, dwSize; DWORD dwSizeSoFar;
dwSizeSoFar = 0;
// build the list of catalogs
pszCatalog = szCatalogName; dwIndex = 0; dwSize = sizeof(szCatalogName) - 1; while (RegEnumValue(hkCatalogKey, dwIndex, pszCatalog, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { dwSizeSoFar += dwSize + 1;
pszCatalog += dwSize + 1; dwIndex++; dwSize = sizeof(szCatalogName) - 1 - dwSizeSoFar; }
RegCloseKey(hkCatalogKey); } } }
if (*szCatalogName == '\0') GetTranslatedString(c_pszInfFilename, szInstallSection, ADVINF_CATALOG_NAME, szCatalogName, sizeof(szCatalogName), NULL);
if (*szCatalogName) { // load sfc.dll and the relevant proc's
if (!LoadSfcDLL()) { // couldn't load -- so empty out CatalogName
*szCatalogName = '\0'; } }
// before we start doing any work, we need to know if this is backup install mode. If it is,
// we will have to backup the Reg data and file data before continuing.
if ( (dwFlags & COREINSTALL_BKINSTALL) || ( dwFlags & COREINSTALL_ROLLBACK ) ) { // if it is rollback case, we don't need to do real GenInstall. We need to unregister the previous
// register section first
//
if ( dwFlags & COREINSTALL_ROLLBACK ) { RegisterOCXs( (PSTR) c_pszInfFilename, szInstallSection, FALSE, FALSE, dwFlags ); }
hReturnCode = SaveRestoreInfo( c_pszInfFilename, szInstallSection, c_pszSourceDir, szCatalogName, dwFlags ); if ( FAILED( hReturnCode ) ) goto done;
// if it is rollback case, we don't need to do real GenInstall. All needed are registering OCXs
if ( dwFlags & COREINSTALL_ROLLBACK ) { // here is very tricky, if the reboot needed and old file can not be registerred,
// if we just add entries blindly to the RunOnce(ex), it will cause the fault at reboot
// time. So we have to make sure if we need to do this re-register thing or just use
// DelReg and AddReg take care it. Need revisit here!!!
//
fRealNeedReboot = InternalNeedReboot( dwRebootCheck, ctx.wOSVer ); RegisterOCXs( (PSTR) c_pszInfFilename, szInstallSection, fRealNeedReboot, TRUE, dwFlags ); if ( fRealNeedReboot ) { hReturnCode = ERROR_SUCCESS_REBOOT_REQUIRED; } // process DelDirs INF line
DelDirs( c_pszInfFilename, szInstallSection ); goto done; } }
// No error handling because it's an uninstall. If unregistering fails, we
// should continue with the uninstall.
// BUGBUG: if it is COREINSTALL_BKINSTALL case, do we need to unregister the Existing OCXs
// get ready for registering the new once. Maybe have foll. call do it based on flags
//
if ( ctx.wOSVer != _OSVER_WINNT3X ) RegisterOCXs( (PSTR) c_pszInfFilename, szInstallSection, FALSE, FALSE, dwFlags );
// if a catalog is specified, try to install it before calling GenInstall()
if (*szCatalogName) { DWORD dwRet; CHAR szFullCatalogName[MAX_PATH];
lstrcpy(szFullCatalogName, c_pszSourceDir); AddPath(szFullCatalogName, szCatalogName);
dwRet = g_pfSfpInstallCatalog(szFullCatalogName, NULL); AdvWriteToLog("CoreInstall: SfpInstallCatalog returned=%1!lu!\r\n", dwRet);
UnloadSfcDLL();
if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND) { // if SfpInstallCatalog return already an HRESULT, use it.
// otherwise convert to na HRESULT.
if (dwRet & 0x80000000) hReturnCode = dwRet; else hReturnCode = HRESULT_FROM_WIN32(dwRet); goto done; }
if (dwRet == ERROR_FILE_NOT_FOUND) *szCatalogName = '\0'; }
AdvWriteToLog("GenInstall: Sec=%1\r\n", szInstallSection); hReturnCode = GenInstall( (PSTR) c_pszInfFilename, szInstallSection, (PSTR) c_pszSourceDir ); AdvWriteToLog("GenInstall return: Sec=%1 hr=0x%2!x!\r\n", szInstallSection, hReturnCode); if ( FAILED( hReturnCode ) ) goto done;
fRealNeedReboot = InternalNeedReboot( dwRebootCheck, ctx.wOSVer ); fNeedReboot = fRealNeedReboot;
// Process SmartReboot key
if ( dwFlags & COREINSTALL_SMARTREBOOT ) { if ( pcszSmartRebootOverride != NULL && *pcszSmartRebootOverride != '\0' ) { lstrcpy( szSmartRebootValue, pcszSmartRebootOverride ); } else { if ( FAILED( GetTranslatedString( c_pszInfFilename, szInstallSection, c_szSmartReboot, szSmartRebootValue, sizeof(szSmartRebootValue), NULL) ) ) { lstrcpy( szSmartRebootValue, c_szSmartRebootDefault ); } }
switch ( szSmartRebootValue[0] ) { case 'a': case 'A': fNeedReboot = TRUE; break;
case 'N': case 'n': fNeedReboot = FALSE; break;
case '\0': lstrcpy( szSmartRebootValue, c_szSmartRebootDefault ); break; } }
if ( ctx.wOSVer != _OSVER_WINNT3X ) { if ( ! RegisterOCXs( (PSTR) c_pszInfFilename, szInstallSection, (fNeedReboot || fRealNeedReboot), TRUE, dwFlags ) ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; } }
// The reason we pass in the reboot flag is to be consistent with register OCX
hReturnCode = RunCommandsSections( c_pszInfFilename, szInstallSection, c_szRunPostSetupCommands, c_pszSourceDir, dwFlags, (fNeedReboot || fRealNeedReboot) ); if ( FAILED( hReturnCode ) ) goto done;
// process PerUserInstall section
hReturnCode = ProcessPerUserSec( c_pszInfFilename, szInstallSection ); if ( FAILED( hReturnCode ) ) goto done;
// if /R:P is passed in, check absolute reboot condition rather than delta
if ( (dwFlags & COREINSTALL_DELAYPOSTCMD) || (hReturnCode == ERROR_SUCCESS_REBOOT_REQUIRED) ) dwRebootCheck = 0;
// Do we need a reboot now? Lets find out...
fRealNeedReboot = InternalNeedReboot( dwRebootCheck, ctx.wOSVer ); if (GetTranslatedInt(c_pszInfFilename, szInstallSection, "Reboot", 0)) { fRealNeedReboot = TRUE; }
if ( fRealNeedReboot ) { hReturnCode = ERROR_SUCCESS_REBOOT_REQUIRED; }
// Process SmartReboot key
if ( szSmartRebootValue[0] == 'i' || szSmartRebootValue[0] == 'I' ) { fNeedReboot = fRealNeedReboot; }
if ( ctx.wOSVer != _OSVER_WINNT3X ) { if ( NeedToRunGrpconv() ) { if ( (dwFlags & COREINSTALL_GRPCONV) && !fNeedReboot && !fRealNeedReboot ) { char szDir[MAX_PATH];
GetWindowsDirectory( szDir, sizeof(szDir) ); // only wait this unmoral member 30 secs
LaunchAndWait( GRPCONV, szDir, NULL, 30000, (ctx.wQuietMode & QUIETMODE_ALL)? RUNCMDS_QUIET : 0 ); } else { if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS ) { RegSetValueEx( hkey, "GrpConv", 0, REG_SZ, (LPBYTE) GRPCONV, lstrlen(GRPCONV) + 1 ); RegCloseKey(hkey); } } } }
// process DelDirs INF line
DelDirs( c_pszInfFilename, szInstallSection );
if ( dwFlags & COREINSTALL_PROMPT ) { EndPrompt( c_pszInfFilename, szInstallSection ); }
// process Cleanup INF line
DoCleanup( c_pszInfFilename, szInstallSection );
if ( fNeedReboot && (dwFlags & COREINSTALL_SMARTREBOOT) ) { if ( szSmartRebootValue[1] == 's' || szSmartRebootValue[1] == 'S' ) { id = IDYES; } else { id = MsgBox( ctx.hWnd, IDS_RESTARTYESNO, MB_ICONINFORMATION, MB_YESNO ); }
if ( id == IDYES ) { if ( ctx.wOSVer == _OSVER_WIN95 ) { // By default (all platforms), we assume powerdown is possible
id = ExitWindowsEx( EWX_REBOOT, 0 ); } else { MyNTReboot(); } } }
done:
if ( dwFlags & COREINSTALL_PROMPT ) { ctx.lpszTitle = pszOldTitle; }
if (*szCatalogName) UnloadSfcDLL();
CommonInstallCleanup();
AdvWriteToLog("CoreInstall: End InfFile=%1 hr=0x%2!x!\r\n", c_pszInfFilename, hReturnCode); return hReturnCode; }
//***************************************************************************
//* *
//* NAME: RunCommandsSections *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT RunCommandsSections( PCSTR pcszInf, PCSTR pcszSection, PCSTR c_pszKey, PCSTR c_pszSourceDir, DWORD dwFlags, BOOL bNeedReboot ) { HRESULT hRet = S_OK; char szBuf[MAX_INFLINE]; LPSTR pszOneSec, pszStr, pszFlag; DWORD dwCmdsFlags;
szBuf[0] = 0; pszStr = szBuf;
if ( FAILED(GetTranslatedString( pcszInf, pcszSection, c_pszKey, szBuf, sizeof(szBuf), NULL))) szBuf[0] = 0;
// Parse the arguments, SETUP engine is not called to process this line. So we check on \".
pszOneSec = GetStringField( &pszStr, ",", '\"', TRUE ); while ( (hRet == S_OK) && pszOneSec && *pszOneSec ) { dwCmdsFlags = 0; pszFlag = ANSIStrChr( pszOneSec, ':' ); if ( pszFlag && (*pszFlag == ':') ) { pszFlag = CharNext(pszFlag); *CharPrev(pszOneSec, pszFlag) = '\0'; dwCmdsFlags = AtoL(pszFlag); }
if ( (dwFlags & COREINSTALL_DELAYPOSTCMD) && (!lstrcmpi(c_pszKey, c_szRunPostSetupCommands)) ) { dwCmdsFlags |= RUNCMDS_DELAYPOSTCMD; }
hRet = RunCommands( pcszInf, pszOneSec, c_pszSourceDir, dwCmdsFlags, bNeedReboot );
pszOneSec = GetStringField( &pszStr, ",", '\"', TRUE ); }
return hRet; }
//***************************************************************************
//* *
//* NAME: RunCommands *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT RunCommands( PCSTR pcszInfFilename, PCSTR pcszSection, PCSTR c_pszSourceDir, DWORD dwCmdsFlags, BOOL bNeedReboot ) { HRESULT hReturnCode = S_OK; DWORD i = 0; PSTR pszCommand = NULL, pszNewCommand; CHAR szMessage[BIG_STRING];
AdvWriteToLog("RunCommands: Sec=%1\r\n", pcszSection); pszNewCommand = (LPSTR) LocalAlloc( LPTR, BUF_1K ); if ( !pszNewCommand ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
for ( i = 0; ; i += 1 ) { if ( FAILED( GetTranslatedLine( pcszInfFilename, pcszSection, i, &pszCommand, NULL ) ) || !pszCommand ) { break; }
// check if this command need to be delayed
// if there is reboot condition regardless who cause it, delay.
if ( (dwCmdsFlags & RUNCMDS_DELAYPOSTCMD) && (InternalNeedReboot( 0, ctx.wOSVer ) || bNeedReboot ) ) { static int iSubKeyNum = 989; static int iLine = 0; static BOOL bRunOnceEx = FALSE; HKEY hKey, hSubKey; LPSTR lpRegTmp;
if ( iSubKeyNum == 989 ) { if ( UseRunOnceEx() ) { bRunOnceEx = TRUE; } }
// decide to add the entry to RunOnce or RunOnceEx
if ( !bRunOnceEx ) { // no ierunonce.dll, use RunOnce key rather than RunOnceEx key
lpRegTmp = REGSTR_PATH_RUNONCE; } else { lpRegTmp = REGSTR_PATH_RUNONCEEX; }
// open RunOnce or RunOnceEx key here
if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, lpRegTmp, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, NULL ) == ERROR_SUCCESS ) { // SubKey "990" is the one used in one GenInstall section to
// store all the delayed post cmds.
if ( bRunOnceEx ) { if ( iSubKeyNum == 989 ) GetNextRunOnceExSubKey( hKey, szMessage, &iSubKeyNum ); else wsprintf( szMessage, "%d", iSubKeyNum );
// Generate the Value Name and ValueData.
//
if ( RegCreateKeyEx( hKey, szMessage, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hSubKey, NULL ) == ERROR_SUCCESS ) { GetNextRunOnceValName( hSubKey, "%03d", szMessage, iLine++ ); RegSetValueEx( hSubKey, szMessage, 0, REG_SZ, (LPBYTE)pszCommand, lstrlen(pszCommand)+1 ); AdvWriteToLog("RunOnceEx Entry: %1\r\n", pszCommand); RegCloseKey( hSubKey ); } } else { GetNextRunOnceValName( hKey, achIEXREG, szMessage, iLine++ ); RegSetValueEx( hKey, szMessage, 0, REG_SZ, (LPBYTE)pszCommand, lstrlen(pszCommand)+1 ); AdvWriteToLog("RunOnce Entry: %1\r\n", pszCommand); }
RegCloseKey( hKey );
// if we delay the commands, should trig the reboot.
hReturnCode = ERROR_SUCCESS_REBOOT_REQUIRED; } } else { if ( ! IsFullPath( pszCommand ) ) { lstrcpy( pszNewCommand, c_pszSourceDir ); AddPath( pszNewCommand, pszCommand ); }
if ( ( *pszNewCommand == 0 ) || ( LaunchAndWait( pszNewCommand, NULL, NULL, INFINITE, dwCmdsFlags ) == E_FAIL ) ) { if ( LaunchAndWait( pszCommand, NULL, NULL, INFINITE, dwCmdsFlags ) == E_FAIL ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, szMessage, sizeof(szMessage), NULL ); ErrorMsg2Param( ctx.hWnd, IDS_ERR_CREATE_PROCESS, pszCommand, szMessage ); break; } } }
// release the buffer allocated by GetTranslatedLine
LocalFree( pszCommand ); pszCommand = NULL; *pszNewCommand = 0; }
// release the local buffer
if ( pszNewCommand ) LocalFree( pszNewCommand );
// release the buffer allocated by GetTranslatedLine
if ( pszCommand ) LocalFree( pszCommand );
done: AdvWriteToLog("RunCommands: Sec=%1 End hr=0x%2!x!\r\n", pcszSection, hReturnCode); return hReturnCode; } //***************************************************************************
//* *
//* NAME: GetTranslatedInt *
//* *
//* SYNOPSIS: Translates a string in an INF file. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
DWORD GetTranslatedInt( PCSTR pszInfFilename, PCSTR pszTranslateSection, PCSTR pszTranslateKey, DWORD dwDefault ) { CHAR szBuf[100]; //BOOL bLocalInitSetupapi = FALSE;
BOOL bLocalAssignSetupEng = FALSE; DWORD dwResult, dwRequiredSize; DWORD dwSaveSetupEngine;
dwResult = dwDefault; // since we are no using GetPrivateProfileString anymore if setupapi present
// there are times this function called and setupapi.dll is not loaded yet.
// so we need to check on in and initalize it if it is necessary
if (ctx.hSetupLibrary==NULL) { if (CheckOSVersion() && (ctx.wOSVer != _OSVER_WIN95)) { //dwSaveSetupEngine = ctx.dwSetupEngine;
ctx.dwSetupEngine = ENGINE_SETUPAPI; //bLocalAssignSetupEng = TRUE;
if (InitializeSetupAPI()) { // To avoid multiple times load and unload the NT setupapi DLLs
// On NT, we are not unload the setuplib unless the INF engine need to be
// updated.
//
if (FAILED(MySetupOpenInfFile(pszInfFilename))) { // UnloadSetupLib();
goto done; } //bLocalInitSetupapi = TRUE;
} else { goto done; } } else { // if setupx lib is not initialized yet, just use GetPrivateProfileString
dwSaveSetupEngine = ctx.dwSetupEngine; ctx.dwSetupEngine = ENGINE_SETUPX; bLocalAssignSetupEng = TRUE;
} }
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { dwResult = (DWORD)GetPrivateProfileInt(pszTranslateSection, pszTranslateKey, dwDefault, pszInfFilename); } else { szBuf[0] = '\0'; if ( FAILED(MySetupGetLineText( pszTranslateSection, pszTranslateKey, szBuf, sizeof(szBuf), &dwRequiredSize ))) { goto done; } // convert the string to DWORD
if (szBuf[0] != '\0') dwResult = (DWORD)AtoL(szBuf); else dwResult = dwDefault; }
done: //if (bLocalInitSetupapi)
//{
// uninitialize setupapi
//CommonInstallCleanup();
//}
if (bLocalAssignSetupEng) ctx.dwSetupEngine = dwSaveSetupEngine;
return dwResult; }
//***************************************************************************
//* *
//* NAME: GetTranslatedString *
//* *
//* SYNOPSIS: Translates a string in an INF file. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT GetTranslatedString( PCSTR pszInfFilename, PCSTR pszTranslateSection, PCSTR pszTranslateKey, PSTR pszBuffer, DWORD dwBufferSize, PDWORD pdwRequiredSize ) { HRESULT hReturnCode = S_OK; PSTR pszPreTranslated = NULL; PSTR pszPostTranslated = NULL; DWORD dwSizePreTranslated = 2048; DWORD dwSizePostTranslated = 4096; DWORD dwRequiredSize = 0; //BOOL bLocalInitSetupapi = FALSE;
BOOL bLocalAssignSetupEng = FALSE; DWORD dwSaveSetupEngine;
// since we are no using GetPrivateProfileString anymore if setupapi present
// there are times this function called and setupapi.dll is not loaded yet.
// so we need to check on in and initalize it if it is necessary
if (ctx.hSetupLibrary==NULL) { if (CheckOSVersion() && (ctx.wOSVer != _OSVER_WIN95)) { // To avoid multiple times load and unload the NT setupapi DLLs
// On NT, we are not unload the setuplib unless the INF engine need to be
// updated.
//
//dwSaveSetupEngine = ctx.dwSetupEngine;
ctx.dwSetupEngine = ENGINE_SETUPAPI; //bLocalAssignSetupEng = TRUE;
if (InitializeSetupAPI()) { hReturnCode = MySetupOpenInfFile(pszInfFilename); if (FAILED(hReturnCode)) { //UnloadSetupLib();
goto done; } //bLocalInitSetupapi = TRUE;
} else { hReturnCode = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto done; } } else { // if setupx lib is not initialized yet, just use GetPrivateProfileString
dwSaveSetupEngine = ctx.dwSetupEngine; ctx.dwSetupEngine = ENGINE_SETUPX; bLocalAssignSetupEng = TRUE; } }
// NOTE: There should never be a value in an INF greater than 2k
// and translated strings shouldn't exceed 4k.
pszPreTranslated = (PSTR) LocalAlloc( LPTR, dwSizePreTranslated ); pszPostTranslated = (PSTR) LocalAlloc( LPTR, dwSizePostTranslated );
if ( ! pszPreTranslated || ! pszPostTranslated ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { if ( ! MyGetPrivateProfileString( pszInfFilename, pszTranslateSection, pszTranslateKey, pszPreTranslated, dwSizePreTranslated ) ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto done; }
if ( ctx.hSetupLibrary ) { if (!pfGenFormStrWithoutPlaceHolders32( pszPostTranslated, pszPreTranslated, (LPSTR) pszInfFilename ) ) { hReturnCode = E_UNEXPECTED; goto done; } } else FormStrWithoutPlaceHolders( pszPreTranslated, pszPostTranslated, dwSizePostTranslated, pszInfFilename );
dwRequiredSize = lstrlen( pszPostTranslated ) + 1; } else { hReturnCode = MySetupGetLineText( pszTranslateSection, pszTranslateKey, pszPostTranslated, dwSizePostTranslated, &dwRequiredSize );
if (FAILED(hReturnCode) && HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hReturnCode) { // resize buffer and retry.
LocalFree(pszPostTranslated); pszPostTranslated = LocalAlloc(LPTR, dwRequiredSize); dwSizePostTranslated = dwRequiredSize; if ( !pszPostTranslated ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
hReturnCode = MySetupGetLineText( pszTranslateSection, pszTranslateKey, pszPostTranslated, dwSizePostTranslated, &dwRequiredSize ); }
if ( FAILED(hReturnCode) ) { goto done; } }
if ( pszBuffer == NULL ) { hReturnCode = S_OK; goto done; }
if ( dwRequiredSize > dwBufferSize ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto done; }
lstrcpy( pszBuffer, pszPostTranslated );
done: //if (bLocalInitSetupapi)
//{
// uninitialize setupapi
//CommonInstallCleanup();
//}
if (bLocalAssignSetupEng) ctx.dwSetupEngine = dwSaveSetupEngine;
if ( pdwRequiredSize ) { *pdwRequiredSize = dwRequiredSize; }
if ( pszPreTranslated != NULL ) { LocalFree( pszPreTranslated ); }
if ( pszPostTranslated != NULL ) { LocalFree( pszPostTranslated ); }
return hReturnCode; }
//***************************************************************************
//* *
//* NAME: GetTranslatedLine *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT GetTranslatedLine( PCSTR c_pszInfFilename, PCSTR c_pszTranslateSection, DWORD dwIndex, PSTR *ppszBuffer, PDWORD pdwRequiredSize ) { HRESULT hReturnCode = S_OK; PSTR pszPreTranslated = NULL; PSTR pszPostTranslated = NULL; DWORD dwPreTranslatedSize = 8192; DWORD dwPostTranslatedSize = 4096; DWORD dwRequiredSize = 0; DWORD i = 0; PSTR pszPoint = NULL; //BOOL bLocalInitSetupapi = FALSE;
BOOL bLocalAssignSetupEng = FALSE; DWORD dwSaveSetupEngine;
// since we are no using GetPrivateProfileString anymore if setupapi present
// there are times this function called and setupapi.dll is not loaded yet.
// so we need to check on in and initalize it if it is necessary
if (ctx.hSetupLibrary==NULL) { if (CheckOSVersion() && (ctx.wOSVer != _OSVER_WIN95)) { // To avoid multiple times load and unload the NT setupapi DLLs
// On NT, we are not unload the setuplib unless the INF engine need to be
// updated.
//
//dwSaveSetupEngine = ctx.dwSetupEngine;
ctx.dwSetupEngine = ENGINE_SETUPAPI; //bLocalAssignSetupEng = TRUE;
if (InitializeSetupAPI()) { hReturnCode = MySetupOpenInfFile(c_pszInfFilename); if (FAILED(hReturnCode)) { //UnloadSetupLib();
goto done; } //bLocalInitSetupapi = TRUE;
} else { hReturnCode = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto done; } } else { // if setupx lib is not initialized yet, just use GetPrivateProfileString
dwSaveSetupEngine = ctx.dwSetupEngine; ctx.dwSetupEngine = ENGINE_SETUPX; bLocalAssignSetupEng = TRUE; } }
// initial to NULL in the case of error, otherwise
if ( ppszBuffer ) *ppszBuffer = NULL;
pszPreTranslated = (PSTR) LocalAlloc( LPTR, dwPreTranslatedSize ); pszPostTranslated = (PSTR) LocalAlloc( LPTR, dwPostTranslatedSize );
if ( !pszPreTranslated || !pszPostTranslated ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { // BUGBUG: Should automagically change buffer size until we get a big
// enough buffer to hold the full section.
// BUGBUG: For setupx engine, we don't support the multiple-inf line reading for the new
// advance INF options. In most case, there is no need for that. If really need, set
// RequireEngine=SETUPAPI,"string"
dwRequiredSize = RO_GetPrivateProfileSection( c_pszTranslateSection, pszPreTranslated, dwPreTranslatedSize, c_pszInfFilename );
if ( dwRequiredSize == dwPreTranslatedSize - 2 ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, c_pszTranslateSection ); hReturnCode = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto done; }
pszPoint = pszPreTranslated;
while ( *pszPoint == ';' ) { pszPoint += lstrlen(pszPoint) + 1; }
for ( i = 0; i < dwIndex; i += 1 ) { pszPoint += lstrlen(pszPoint) + 1;
if ( *pszPoint == '\0' ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); goto done; }
while ( *pszPoint == ';' ) { pszPoint += lstrlen(pszPoint) + 1; } }
if ( *pszPoint == '\0' ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); goto done; }
if ( ctx.hSetupLibrary ) { if ( ! pfGenFormStrWithoutPlaceHolders32( pszPostTranslated, pszPoint, (PSTR) c_pszInfFilename ) ) { hReturnCode = E_UNEXPECTED; goto done; } } else FormStrWithoutPlaceHolders( pszPoint, pszPostTranslated, dwPostTranslatedSize, (PSTR) c_pszInfFilename );
// strip out the double quotes
pszPoint = pszPostTranslated; pszPostTranslated = GetStringField( &pszPoint, "\0", '\"', TRUE ); dwRequiredSize = lstrlen( pszPostTranslated ) + 1; } else { hReturnCode = MySetupGetLineByIndex( c_pszTranslateSection, dwIndex, pszPostTranslated, dwPostTranslatedSize, &dwRequiredSize ); if (FAILED(hReturnCode) && HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hReturnCode) { // resize buffer and retry.
LocalFree(pszPostTranslated); pszPostTranslated = LocalAlloc(LPTR, dwRequiredSize); dwPostTranslatedSize = dwRequiredSize; if ( !pszPostTranslated ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); goto done; }
hReturnCode = MySetupGetLineByIndex( c_pszTranslateSection, dwIndex, pszPostTranslated, dwPostTranslatedSize, &dwRequiredSize ); }
if ( FAILED(hReturnCode) ) { goto done; } }
// if NULL, return only size
//
if ( !ppszBuffer ) { LocalFree( pszPostTranslated ); } else { // this buffer has to be released by the caller!!
//
*ppszBuffer = (LPSTR)LocalReAlloc( pszPostTranslated, (lstrlen(pszPostTranslated)+1), LMEM_MOVEABLE ); if ( !*ppszBuffer ) *ppszBuffer = pszPostTranslated; }
done: //if (bLocalInitSetupapi)
//{
// uninitialize setupapi
//CommonInstallCleanup();
//}
if (bLocalAssignSetupEng) ctx.dwSetupEngine = dwSaveSetupEngine;
if ( pdwRequiredSize ) { *pdwRequiredSize = dwRequiredSize; }
if ( pszPreTranslated != NULL ) { LocalFree( pszPreTranslated ); }
if ( FAILED(hReturnCode) && (pszPostTranslated != NULL) ) { if (ppszBuffer) *ppszBuffer = NULL; LocalFree( pszPostTranslated ); }
return hReturnCode; }
//***************************************************************************
//* *
//* NAME: GetTranslatedSection *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
DWORD GetTranslatedSection(PCSTR c_pszInfFilename, PCSTR c_pszTranslateSection, PSTR pszBuffer, DWORD dwBufSize ) { CHAR szPreTranslated[MAX_INFLINE]; DWORD dwSize = 0; //BOOL bLocalInitSetupapi = FALSE,
BOOL bLocalAssignSetupEng = FALSE; DWORD dwSaveSetupEngine;
// since we are no using GetPrivateProfileString anymore if setupapi present
// there are times this function called and setupapi.dll is not loaded yet.
// so we need to check on in and initalize it if it is necessary
if (ctx.hSetupLibrary==NULL) { if (CheckOSVersion() && (ctx.wOSVer != _OSVER_WIN95)) { // To avoid multiple times load and unload the NT setupapi DLLs
// On NT, we are not unload the setuplib unless the INF engine need to be
// updated.
//
//dwSaveSetupEngine = ctx.dwSetupEngine;
ctx.dwSetupEngine = ENGINE_SETUPAPI; //bLocalAssignSetupEng = TRUE;
if (InitializeSetupAPI()) { if (FAILED(MySetupOpenInfFile(c_pszInfFilename))) { //UnloadSetupLib();
goto done; } //bLocalInitSetupapi = TRUE;
} else { goto done; } } else { // if setupx lib is not initialized yet, just use GetPrivateProfileString
dwSaveSetupEngine = ctx.dwSetupEngine; ctx.dwSetupEngine = ENGINE_SETUPX; bLocalAssignSetupEng = TRUE; } }
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { dwSize = RO_GetPrivateProfileSection( c_pszTranslateSection, pszBuffer, dwBufSize, c_pszInfFilename );
if ( dwSize == dwBufSize - 2 ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, c_pszTranslateSection ); goto done; } } else { int i, len; LPSTR pszTmp, pszStart; DWORD dwReqSize; char szBuf[MAX_INFLINE];
pszStart = pszBuffer; *pszStart = '\0';
for (i=0; ; i++) { // if key does not contain ',', setupapi's SetupGetLineText only return the value part
// we need to get the corespondent key part to makeup the whole line text
dwReqSize = 0; if (SUCCEEDED(MySetupGetStringField(c_pszTranslateSection, i, 0, szBuf, sizeof(szBuf), &dwReqSize)) && dwReqSize) { dwReqSize = 0; if ( SUCCEEDED(MySetupGetLineText( c_pszTranslateSection, szBuf, szPreTranslated, sizeof(szPreTranslated), &dwReqSize )) && dwReqSize) { // got the key, so the line must be in the form A=B or Just A forms, no comma.
lstrcat(szBuf, "="); lstrcat(szBuf, szPreTranslated); } } else { // expect the line in the forms of A,B,C=B or just A,B,C
if ( FAILED(MySetupGetLineByIndex(c_pszTranslateSection, i, szPreTranslated, sizeof(szPreTranslated), &dwReqSize ))) { // should not be here since you are here, the line must have commas or no '='
break; }
lstrcpy(szBuf, szPreTranslated); }
len = lstrlen(szBuf)+1; if ((dwSize + len) < dwBufSize) { lstrcpy(pszStart, szBuf); pszStart += len; dwSize += len; } else { dwSize = dwBufSize - 2; break; } }
if (pszStart > pszBuffer) *pszStart = '\0'; else if (pszStart == pszBuffer) *(pszStart+1) = '\0'; }
done: //if (bLocalInitSetupapi)
//{
// uninitialize setupapi
//CommonInstallCleanup();
//}
if (bLocalAssignSetupEng) ctx.dwSetupEngine = dwSaveSetupEngine;
return dwSize; }
//***************************************************************************
//* *
//* NAME: MyNTReboot *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL MyNTReboot( VOID ) { 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; }
//***************************************************************************
//* *
//* NAME: GetStringField *
//* *
//* SYNOPSIS: Gets a field (separated with certain characters). *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
PSTR GetStringField( PSTR *ppszString, PCSTR c_pszSeparators, CHAR chQuoteToCheck, BOOL bStripWhiteSpace) { PSTR pszInternalString; PSTR pszPoint = NULL; BOOL fWithinQuotes = FALSE; CHAR ch1, chQuote = 0; PSTR pszTmp;
pszInternalString = *ppszString;
if ( pszInternalString == NULL ) { return NULL; }
pszPoint = pszInternalString; while ( 1 ) { ch1 = *pszInternalString;
if ( ch1 == chQuoteToCheck ) { pszTmp = CharNext( pszInternalString ); if ( chQuote == 0 ) { // the first one
chQuote = ch1; fWithinQuotes = !(fWithinQuotes); // strip out this quote
MoveMemory( pszInternalString, pszTmp, lstrlen(pszTmp)+1 ); if ( *pszInternalString == chQuote ) continue; } else if ( chQuote == ch1 ) { if ( *pszTmp == ch1 ) { PSTR ptmp = CharNext( pszTmp ); // dest, src, count include terminate null char.
MoveMemory( pszTmp, ptmp, lstrlen(ptmp)+1 ); } else { fWithinQuotes = !(fWithinQuotes); chQuote = 0; MoveMemory( pszInternalString, pszTmp, lstrlen(pszTmp)+1 ); } } }
if ( *pszInternalString == '\0' ) { break; }
if ( !fWithinQuotes && IsSeparator( *pszInternalString, (PSTR) c_pszSeparators ) ) { break; } pszInternalString = CharNext(pszInternalString); }
if ( *pszInternalString == '\0' ) { pszInternalString = NULL; } else { *pszInternalString = '\0'; pszInternalString += 1; }
if ( bStripWhiteSpace ) pszPoint = StripWhitespace( pszPoint );
*ppszString = pszInternalString; return pszPoint; }
//***************************************************************************
//* *
//* NAME: GetStringFieldNoQuote *
//* *
//* SYNOPSIS: Gets a field (separated with certain characters). *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
LPSTR GetStringFieldNoQuote( PSTR *ppszString, PCSTR c_pszSeparators, BOOL bStripWhiteSpace) { LPSTR pszInternalString; LPSTR pszPoint = NULL;
pszInternalString = *ppszString; if ( pszInternalString == NULL ) { return NULL; }
pszPoint = pszInternalString; while ( *pszInternalString ) { if ( IsSeparator( *pszInternalString, c_pszSeparators ) ) { break; } pszInternalString = CharNext(pszInternalString); }
if ( *pszInternalString == '\0' ) { pszInternalString = NULL; } else { *pszInternalString = '\0'; pszInternalString += 1; }
if ( bStripWhiteSpace ) pszPoint = StripWhitespace( pszPoint );
*ppszString = pszInternalString; return pszPoint; }
//***************************************************************************
//* *
//* NAME: IsSeparator *
//* *
//* SYNOPSIS: Returns TRUE if the character is in the string. Else FALSE. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL IsSeparator( CHAR chChar, PCSTR pszSeparators ) { if ( chChar == '\0' || pszSeparators == NULL ) { return FALSE; }
while ( *pszSeparators != chChar ) { if ( *pszSeparators == '\0' ) { return FALSE; }
pszSeparators += 1; }
return TRUE; }
//***************************************************************************
//* *
//* NAME: StripWhitespace *
//* *
//* SYNOPSIS: Strips spaces and tabs from both sides of given string. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
PSTR StripWhitespace( PSTR pszString ) { PSTR pszTemp = NULL;
if ( pszString == NULL ) { return NULL; }
while ( *pszString == ' ' || *pszString == '\t' ) { pszString += 1; }
// Catch case where string consists entirely of whitespace or empty string.
if ( *pszString == '\0' ) { return pszString; }
pszTemp = pszString;
pszString += lstrlen(pszString) - 1;
while ( *pszString == ' ' || *pszString == '\t' ) { *pszString = '\0'; pszString -= 1; }
return pszTemp; }
//***************************************************************************
//* *
//* NAME: StripQuotes *
//* *
//* SYNOPSIS: Strips quotes from both sides of given string. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
#if 0
PSTR StripQuotes( PSTR pszString ) { PSTR pszTemp = NULL; CHAR chQuote;
if ( pszString == NULL ) { return NULL; }
ch = *pszString; if ( ch == '"' || ch == '\'' ) { pszTemp = pszString + 1; } else { return pszString; }
pszString += lstrlen(pszString) - 1;
if ( *pszString == ch ) { *pszString = '\0'; } else { pszTemp--; }
return pszTemp; }
#endif
//***************************************************************************
//* *
//* NAME: IsGoodAdvancedInfVersion *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL IsGoodAdvancedInfVersion( PCSTR c_pszInfFilename ) { static const CHAR c_szSection[] = "Version"; static const CHAR c_szKey[] = "AdvancedINF"; PSTR pszVersionData = NULL; PSTR pszMajorVersion = NULL; PSTR pszMinorVersion = NULL; DWORD dwRequiredSize; DWORD dwSize; PSTR pszVersion = NULL; PSTR pszErrorMsg = NULL; DWORD dwVersion = 0; BOOL fSuccess = TRUE; PSTR pszTmp;
if ( FAILED( GetTranslatedString( c_pszInfFilename, c_szSection, c_szKey, pszVersionData, 0, &dwRequiredSize ) ) ) { // We return TRUE because even though they didn't specify a version, I still
// want to process the INF file.
fSuccess = TRUE; goto done; }
pszVersionData = (PSTR) LocalAlloc( LPTR, dwRequiredSize ); if ( !pszVersionData ) { ErrorMsg( ctx.hWnd, IDS_ERR_NO_MEMORY ); fSuccess = FALSE; goto done; }
if ( FAILED( GetTranslatedString( c_pszInfFilename, c_szSection, c_szKey, pszVersionData, dwRequiredSize, &dwSize ) ) ) { // This guy should never fail because the call above didn't fail.
fSuccess = FALSE; goto done; }
pszTmp = pszVersionData; // Parse the arguments, SETUP engine has processed \" so we only need to check on \'
pszVersion = GetStringField( &pszTmp, ",", '\'', TRUE ); pszErrorMsg = GetStringField( &pszTmp, ",", '\'', TRUE );
if ( pszVersion == NULL || *pszVersion == '\0' ) { // If they don't specify a version, process the INF file anyway
fSuccess = TRUE; goto done; }
// Parse the arguments, SETUP engine has processed \" so we only need to check on \'
pszTmp = pszVersion; pszMajorVersion = GetStringField( &pszTmp, ".", '\'', TRUE ); pszMinorVersion = GetStringField( &pszTmp, ".", '\'', TRUE );
if ( pszMajorVersion == NULL || pszMajorVersion == '\0' ) { fSuccess = TRUE; goto done; }
dwVersion = ((DWORD) My_atol(pszMajorVersion)) * 100;
if ( pszMinorVersion != NULL ) { dwVersion += (DWORD) My_atol(pszMinorVersion); }
if ( dwVersion > ADVPACK_VERSION ) { fSuccess = FALSE; if ( pszErrorMsg != NULL && *pszErrorMsg != '\0' ) { ErrorMsg1Param( ctx.hWnd, IDS_PROMPT, pszErrorMsg ); AdvWriteToLog("Advpack.dll Version check failed! InfFile=%1\r\n", c_pszInfFilename);
} goto done; }
done:
if ( pszVersionData ) { LocalFree( pszVersionData ); }
return fSuccess; }
//***************************************************************************
//* *
//* NAME: SelectSetupEngine *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL SelectSetupEngine( PCSTR c_pszInfFilename, PCSTR c_pszSection, DWORD dwFlags ) { static const CHAR c_szKey[] = "RequiredEngine"; static const CHAR c_szSetupX[] = "SETUPX"; static const CHAR c_szSetupAPI[] = "SETUPAPI"; PSTR pszEngine = NULL; PSTR pszErrorMsg = NULL; BOOL fSuccess = TRUE; PSTR pszDll = NULL; PSTR pszFilePart = NULL; CHAR szBuffer[MAX_PATH]; CHAR szEngineData[2048]; PSTR pszStr; BOOL bMustSetupapi = FALSE;
if ( (dwFlags & COREINSTALL_BKINSTALL) || (dwFlags & COREINSTALL_ROLLBACK) || (dwFlags & COREINSTALL_REBOOTCHECKONINSTALL) || (dwFlags & COREINSTALL_SETUPAPI)||(ctx.wOSVer != _OSVER_WIN95)) { ctx.dwSetupEngine = ENGINE_SETUPAPI; bMustSetupapi = TRUE; if (ctx.wOSVer != _OSVER_WIN95) goto done; } else { ctx.dwSetupEngine = ENGINE_SETUPX; }
if (FAILED(GetTranslatedString(c_pszInfFilename, c_pszSection, c_szKey, szEngineData, sizeof(szEngineData), NULL))) { fSuccess = TRUE; goto done; }
// Parse the arguments, SETUP engine is NOT called. So we need to check on \"
pszStr = szEngineData; pszEngine = GetStringField( &pszStr, ",", '\"', TRUE ); pszErrorMsg = GetStringField( &pszStr, ",", '\"', TRUE );
if ( pszEngine == NULL || *pszEngine == '\0' ) { // If they don't specify an engine, process the INF file anyway
fSuccess = TRUE; goto done; }
if ( !bMustSetupapi && (lstrcmpi( pszEngine, c_szSetupX ) == 0) ) { pszDll = W95INF32DLL; ctx.dwSetupEngine = ENGINE_SETUPX; } else { pszDll = SETUPAPIDLL; ctx.dwSetupEngine = ENGINE_SETUPAPI; }
// only if you don't have the INF engine file and you don't have the UpdateINFEngine On, error out
if (!SearchPath( NULL, pszDll, NULL, sizeof(szBuffer), szBuffer, &pszFilePart ) && (GetTranslatedInt(c_pszInfFilename, c_pszSection, ADVINF_UPDINFENG, 0)==0)) { fSuccess = FALSE; if ( pszErrorMsg != NULL && *pszErrorMsg != '\0' ) { ErrorMsg1Param( ctx.hWnd, IDS_PROMPT, pszErrorMsg ); } else ErrorMsg1Param( NULL, IDS_ERR_LOAD_DLL, SETUPAPIDLL ); }
done:
return fSuccess; }
//***************************************************************************
//* *
//* NAME: BeginPrompt *
//* *
//* SYNOPSIS: Displays beginning (confirmation) prompt. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
INT BeginPrompt( PCSTR c_pszInfFilename, PCSTR c_pszSection, PSTR pszTitle, DWORD dwTitleSize ) { static const CHAR c_szBeginPromptKey[] = "BeginPrompt"; static const CHAR c_szPromptKey[] = "Prompt"; static const CHAR c_szButtonTypeKey[] = "ButtonType"; static const CHAR c_szTitleKey[] = "Title"; static const CHAR c_szButtonYesNo[] = "YESNO"; CHAR szBeginPromptSection[256]; PSTR pszPrompt = NULL; DWORD dwPromptSize = 2048; INT nReturnCode = 0; CHAR szButtonType[128]; UINT nButtons = 0; DWORD dwSize;
if ( FAILED( GetTranslatedString( c_pszInfFilename, c_pszSection, c_szBeginPromptKey, szBeginPromptSection, sizeof(szBeginPromptSection), &dwSize ) ) ) { nReturnCode = IDOK; goto done; }
if ( ! FAILED( GetTranslatedString( c_pszInfFilename, szBeginPromptSection, c_szTitleKey, pszTitle, dwTitleSize, &dwSize ) ) ) { ctx.lpszTitle = pszTitle; }
pszPrompt = (PSTR) LocalAlloc( LPTR, dwPromptSize ); if ( ! pszPrompt ) { ErrorMsg( ctx.hWnd, IDS_ERR_NO_MEMORY ); nReturnCode = IDCANCEL; goto done; }
if ( FAILED( GetTranslatedString( c_pszInfFilename, szBeginPromptSection, c_szPromptKey, pszPrompt, dwPromptSize, &dwSize ) ) ) { nReturnCode = IDOK; goto done; }
GetTranslatedString( c_pszInfFilename, szBeginPromptSection, c_szButtonTypeKey, szButtonType, sizeof(szButtonType), &dwSize );
if ( lstrcmpi( szButtonType, c_szButtonYesNo ) == 0 ) { nButtons = MB_YESNO; } else { nButtons = MB_OKCANCEL; }
nReturnCode = MsgBox1Param( ctx.hWnd, IDS_PROMPT, pszPrompt, MB_ICONQUESTION, nButtons | MB_DEFBUTTON2 ); if ( nReturnCode == 0 ) { ErrorMsg( ctx.hWnd, IDS_ERR_NO_MEMORY ); nReturnCode = IDCANCEL; goto done; }
done:
if ( pszPrompt ) { LocalFree( pszPrompt ); }
// Map all cancel buttons to IDCANCEL
if ( nReturnCode == IDNO ) { nReturnCode = IDCANCEL; }
return nReturnCode; }
//***************************************************************************
//* *
//* NAME: EndPrompt *
//* *
//* SYNOPSIS: Displays end prompt. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
VOID EndPrompt( PCSTR c_pszInfFilename, PCSTR c_pszSection ) { static const CHAR c_szEndPromptKey[] = "EndPrompt"; static const CHAR c_szPromptKey[] = "Prompt"; CHAR szEndPromptSection[256]; PSTR pszPrompt = NULL; DWORD dwPromptSize = 2048; DWORD dwSize = 0;
if ( FAILED( GetTranslatedString( c_pszInfFilename, c_pszSection, c_szEndPromptKey, szEndPromptSection, sizeof(szEndPromptSection), &dwSize ) ) ) { goto done; }
pszPrompt = (PSTR) LocalAlloc( LPTR, dwPromptSize ); if ( ! pszPrompt ) { goto done; }
if ( FAILED( GetTranslatedString( c_pszInfFilename, szEndPromptSection, c_szPromptKey, pszPrompt, dwPromptSize, &dwSize ) ) ) { goto done; }
MsgBox1Param( ctx.hWnd, IDS_PROMPT, pszPrompt, MB_ICONINFORMATION, MB_OK );
done:
if ( pszPrompt ) { LocalFree( pszPrompt ); }
return; }
//***************************************************************************
//* *
//* NAME: MyGetPrivateProfileString *
//* *
//* SYNOPSIS: Gets string from INF file. TRUE if success, else FALSE. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL MyGetPrivateProfileString( PCSTR c_pszInfFilename, PCSTR c_pszSection, PCSTR c_pszKey, PSTR pszBuffer, DWORD dwBufferSize ) { DWORD dwSize = 0; static const CHAR c_szDefault[] = "ZzZzZzZz";
dwSize = GetPrivateProfileString( c_pszSection, c_pszKey, c_szDefault, pszBuffer, dwBufferSize, c_pszInfFilename ); if ( dwSize == (dwBufferSize - 1) || lstrcmp( pszBuffer, c_szDefault ) == 0 ) { return FALSE; }
return TRUE; }
//***************************************************************************
//* *
//* NAME: InitializeSetupAPI *
//* *
//* SYNOPSIS: Load the proper setup library and functions (for Win95) *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL InitializeSetupAPI() { if ( ctx.hSetupLibrary == NULL ) { ctx.hSetupLibrary = MyLoadLibrary( SETUPAPIDLL ); if ( ctx.hSetupLibrary == NULL ) { ErrorMsg1Param( NULL, IDS_ERR_LOAD_DLL, SETUPAPIDLL ); return FALSE; }
if ( ! LoadSetupAPIFuncs() ) { ErrorMsg( NULL, IDS_ERR_GET_PROC_ADDR ); FreeLibrary( ctx.hSetupLibrary ); ctx.hSetupLibrary = NULL; return FALSE; } } return TRUE; }
//***************************************************************************
//* *
//* NAME: LoadSetupLib *
//* *
//* SYNOPSIS: Load the proper setup library and functions (for Win95) *
//* *
//* REQUIRES: CheckOSV *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL LoadSetupLib( PCSTR c_pszInfFilename, PCSTR c_pszSection, BOOL fUpdDlls, DWORD dwFlags ) { MSG tmpmsg;
if ( ! SelectSetupEngine( c_pszInfFilename, c_pszSection, dwFlags) ) { return FALSE; }
// update the advpack.dll etc if needed
if ( fUpdDlls && (ctx.wOSVer < _OSVER_WINNT50) && !RunningOnMillennium()) { if (!UpdateHelpDlls( c_szAdvDlls, ((ctx.wOSVer ==_OSVER_WIN95)?3:1), NULL, "Advpack", (ctx.bUpdHlpDlls?UPDHLPDLLS_FORCED:0) ) ) { return FALSE; } }
// update INF Engine dlls if needed
if ( GetTranslatedInt(c_pszInfFilename, c_pszSection, ADVINF_UPDINFENG, 0) ) { char szSrcPath[MAX_PATH];
lstrcpy(szSrcPath, c_pszInfFilename); GetParentDir(szSrcPath); if (ctx.dwSetupEngine == ENGINE_SETUPAPI) { // setupapi.dll may be loaded. So free it up before update
//
CommonInstallCleanup(); if (!UpdateHelpDlls(c_szSetupAPIDlls, 2, szSrcPath, "SetupAPI", UPDHLPDLLS_FORCED|UPDHLPDLLS_ALERTREBOOT) ) { return FALSE; } } else { if (!UpdateHelpDlls(c_szSetupXDlls, 1, szSrcPath, "SetupX", UPDHLPDLLS_FORCED|UPDHLPDLLS_ALERTREBOOT) ) { return FALSE; } } }
// Under Win95 load W95INF32.DLL to thunk down to 16-bit land.
// Under WinNT load SETUPAPI.DLL and call in directly.
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { ctx.hSetupLibrary = MyLoadLibrary( W95INF32DLL ); if ( ctx.hSetupLibrary == NULL ) { ErrorMsg1Param( NULL, IDS_ERR_LOAD_DLL, W95INF32DLL ); return FALSE; }
pfCtlSetLddPath32 = (CTLSETLDDPATH32) GetProcAddress( ctx.hSetupLibrary, achCTLSETLDDPATH32 ); pfGenInstall32 = (GENINSTALL32) GetProcAddress( ctx.hSetupLibrary, achGENINSTALL32 ); pfGetSETUPXErrorText32 = (GETSETUPXERRORTEXT32) GetProcAddress( ctx.hSetupLibrary, achGETSETUPXERRORTEXT32 ); pfGenFormStrWithoutPlaceHolders32 = (GENFORMSTRWITHOUTPLACEHOLDERS32) GetProcAddress( ctx.hSetupLibrary, achGENFORMSTRWITHOUTPLACEHOLDERS32 );
if ( pfCtlSetLddPath32 == NULL || pfGenInstall32 == NULL || pfGetSETUPXErrorText32 == NULL || pfGenFormStrWithoutPlaceHolders32 == NULL ) { ErrorMsg( NULL, IDS_ERR_GET_PROC_ADDR ); FreeLibrary( ctx.hSetupLibrary ); ctx.hSetupLibrary = NULL; return FALSE; } } else { if (!InitializeSetupAPI()) return FALSE;
// BUGBUG: HACK: On NT if we are kicking off setupapi in silent mode,
// it hangs in a GetMessage() call. This is probably because the corr.
// PostThreadMessage() that ted posts fails because no Message Queue has
// been created. The following call should create a queue. Till Ted
// fixes SETUPAPI.DLL, I have added thsi hack!!!
//
PeekMessage(&tmpmsg, NULL, 0, 0, PM_NOREMOVE) ; }
return TRUE; }
//***************************************************************************
//* *
//* NAME: UnloadSetupLib *
//* *
//* SYNOPSIS: Load the proper setup library and functions (for Win95) *
//* *
//* REQUIRES: CheckOSV *
//* *
//* RETURNS: *
//* *
//***************************************************************************
VOID UnloadSetupLib( VOID ) { if ( ctx.hSetupLibrary != NULL ) { FreeLibrary( ctx.hSetupLibrary ); ctx.hSetupLibrary = NULL; } }
//***************************************************************************
//* *
//* NAME: CheckOSVersion *
//* *
//* SYNOPSIS: Checks the OS version and sets some global variables. *
//* *
//* REQUIRES: Nothing *
//* *
//* RETURNS: BOOL: TRUE if successful, FALSE otherwise. *
//* *
//***************************************************************************
BOOL CheckOSVersion( VOID ) { OSVERSIONINFO verinfo; // Version Check
verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx( &verinfo ) == FALSE ) { ErrorMsg( ctx.hWnd, IDS_ERR_OS_VERSION ); return FALSE; }
switch( verinfo.dwPlatformId ) { case VER_PLATFORM_WIN32_WINDOWS: // Win95
ctx.wOSVer = _OSVER_WIN95; ctx.fOSSupportsINFInstalls = TRUE; return TRUE;
case VER_PLATFORM_WIN32_NT: // Win NT
ctx.fOSSupportsINFInstalls = TRUE; ctx.wOSVer = _OSVER_WINNT40;
if ( verinfo.dwMajorVersion <= 3 ) { ctx.wOSVer = _OSVER_WINNT3X; if ( (verinfo.dwMajorVersion < 3) || ((verinfo.dwMajorVersion == 3) && (verinfo.dwMinorVersion < 51 )) ) { // Reject for INF installs and Reject for animations
ctx.fOSSupportsINFInstalls = FALSE; } } else if ( verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion == 0) { ctx.wOSVer = _OSVER_WINNT50; } else if ( (verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion > 0) || verinfo.dwMajorVersion > 5) ctx.wOSVer = _OSVER_WINNT51;
return TRUE;
default: ErrorMsg( ctx.hWnd, IDS_ERR_OS_UNSUPPORTED ); return FALSE; } }
//***************************************************************************
//* *
//* 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 MsgBox2Param( HWND hWnd, UINT nMsgID, LPCSTR szParam1, LPCSTR szParam2, UINT uIcon, UINT uButtons ) { CHAR achMsgBuf[BIG_STRING]; CHAR szTitle[MAX_PATH]; LPSTR szMessage = NULL; LPSTR pszTitle; INT nReturn; CHAR achError[] = "Unexpected Error. Could not load resource."; LPSTR aszParams[2];
// BUGBUG: quiet mode return code should be caller's param passed in.
// we may need to check on FormatMessage's return code and handle it in more completed fashion.
//
if ( (ctx.wQuietMode & QUIETMODE_SHOWMSG) || !(ctx.wQuietMode & QUIETMODE_ALL) ) { aszParams[0] = (LPSTR) szParam1; aszParams[1] = (LPSTR) szParam2;
LoadSz( nMsgID, achMsgBuf, sizeof(achMsgBuf) );
if ( (*achMsgBuf) == '\0' ) { lstrcpy( achMsgBuf, achError ); }
if ( FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, achMsgBuf, 0, 0, (LPSTR) (&szMessage), 0, (va_list *)aszParams ) ) { MessageBeep( uIcon );
if ( ctx.lpszTitle == NULL ) { LoadSz( IDS_ADVDEFTITLE, szTitle, sizeof(szTitle) ); if ( szTitle[0] == '\0' ) { lstrcpy( szTitle, achError ); } pszTitle = szTitle; } else pszTitle = ctx.lpszTitle;
nReturn = MessageBox( hWnd, szMessage, pszTitle, 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: 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: UserDirPrompt *
//* *
//* SYNOPSIS: Pops up a dialog to ask the user for a directory. *
//* *
//* REQUIRES: lpszPromptText: Prompt to display or if null, use next parm *
//* uiPromptResID: ID of string to display as prompt *
//* lpszDefault: Default directory to put in edit box. *
//* lpszDestDir: Buffer to store user selected directory *
//* cbDestDirSize: Size of this buffer *
//* *
//* RETURNS: BOOL: TRUE if everything went well, FALSE *
//* if the user cancelled, or error. *
//* *
//***************************************************************************
BOOL UserDirPrompt( LPSTR lpszPromptText, LPSTR lpszDefault, LPSTR lpszDestDir, ULONG cbDestDirSize, DWORD dwInstNeedSize ) { BOOL fDlgRC; DIRDLGPARMS DirDlgParms;
DirDlgParms.lpszPromptText = lpszPromptText; DirDlgParms.lpszDefault = lpszDefault; DirDlgParms.lpszDestDir = lpszDestDir; DirDlgParms.cbDestDirSize = cbDestDirSize; DirDlgParms.dwInstNeedSize = dwInstNeedSize;
SetControlFont();
fDlgRC = (BOOL) DialogBoxParam( g_hInst, MAKEINTRESOURCE(IDD_DIRDLG), NULL, DirDlgProc, (LPARAM) &DirDlgParms );
if (g_hFont) { DeleteObject(g_hFont); g_hFont = NULL; }
return fDlgRC; }
//***************************************************************************
//* *
//* NAME: DirDlgProc *
//* *
//* SYNOPSIS: Dialog Procedure for our dir dialog window. *
//* *
//* REQUIRES: hwndDlg: *
//* uMsg: *
//* wParam: *
//* lParam: *
//* *
//* RETURNS: BOOL: *
//* *
//***************************************************************************
INT_PTR CALLBACK DirDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static CHAR achDir[MAX_PATH]; static CHAR achMsg[BIG_STRING]; static LPSTR lpszDestDir; static LPSTR lpszDefaultDir; static ULONG cbDestDirSize; static DWORD dwInstNeedSize;
switch (uMsg) {
//*********************************************************************
case WM_INITDIALOG: //*********************************************************************
{ DIRDLGPARMS *DirDlgParms = (DIRDLGPARMS *) lParam;
lpszDestDir = DirDlgParms->lpszDestDir; lpszDefaultDir = DirDlgParms->lpszDefault; cbDestDirSize = DirDlgParms->cbDestDirSize; dwInstNeedSize = DirDlgParms->dwInstNeedSize;
CenterWindow( hwndDlg, GetDesktopWindow() ); SetWindowText( hwndDlg, ctx.lpszTitle );
if ( ! SetDlgItemText( hwndDlg, IDC_TEMPTEXT, DirDlgParms->lpszPromptText ) ) { ErrorMsg( hwndDlg, IDS_ERR_UPDATE_DIR ); EndDialog( hwndDlg, FALSE ); return TRUE; }
SetFontForControl(hwndDlg, IDC_EDIT_DIR); if ( ! SetDlgItemText( hwndDlg, IDC_EDIT_DIR, DirDlgParms->lpszDefault ) ) { ErrorMsg( hwndDlg, IDS_ERR_UPDATE_DIR ); EndDialog( hwndDlg, FALSE ); return TRUE; }
// limit edit control length
SendDlgItemMessage( hwndDlg, IDC_EDIT_DIR, EM_SETLIMITTEXT, (MAX_PATH - 1), 0 );
if ( ctx.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, dwTemp;
// Read the user's entry. If it is different from the default
// and does not exist, prompt user. If user accepts
// create it
if ( ! GetDlgItemText( hwndDlg, IDC_EDIT_DIR, lpszDestDir, cbDestDirSize - 1 ) || !IsFullPath(lpszDestDir) ) { ErrorMsg( hwndDlg, IDS_ERR_EMPTY_DIR_FIELD ); return TRUE; }
// check on the DestDir size if this is not UNC and this drive has not been checked
if ( (*lpszDestDir != '\\' ) && !IsDrvChecked( *lpszDestDir ) ) { if ( !IsEnoughInstSpace( lpszDestDir, dwInstNeedSize, &dwTemp ) ) { CHAR szSize[10];
if ( dwTemp ) { wsprintf( szSize, "%lu", dwTemp ); if ( MsgBox1Param( hwndDlg, IDS_ERR_NO_SPACE_INST, szSize, MB_ICONQUESTION, MB_YESNO|MB_DEFBUTTON2 ) == IDNO ) return TRUE; } else // given drive cannot be checked, error has been posted. no further needed
return TRUE; } }
dwAttribs = GetFileAttributes( lpszDestDir ); if ( dwAttribs == 0xFFFFFFFF ) { // If this new entry is different from the original, then prompt the user.
if ((lstrcmpi(lpszDestDir, lpszDefaultDir) == 0) || MsgBox1Param( hwndDlg, IDS_CREATE_DIR, lpszDestDir, MB_ICONQUESTION, MB_YESNO ) == IDYES ) { if ( FAILED(CreateFullPath( lpszDestDir, FALSE )) ) { ErrorMsg1Param( hwndDlg, IDS_ERR_CREATE_DIR, lpszDestDir ); return TRUE; } } else { return TRUE; } }
if ( ! IsGoodDir( lpszDestDir ) ) { ErrorMsg( hwndDlg, IDS_ERR_INVALID_DIR ); return TRUE; }
EndDialog( hwndDlg, TRUE );
return TRUE; }
//*************************************************************
case IDCANCEL: //*************************************************************
EndDialog( hwndDlg, FALSE ); 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_DIR, achDir ) ) { ErrorMsg( hwndDlg, IDS_ERR_UPDATE_DIR ); EndDialog( hwndDlg, FALSE ); return TRUE; }
return TRUE; }
return TRUE; }
return FALSE; }
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, LPCSTR szTitle, LPSTR szResult ) { BROWSEINFO bi; LPITEMIDLIST pidl; HINSTANCE hShell32Lib; SHFREE pfSHFree; SHGETPATHFROMIDLIST pfSHGetPathFromIDList; SHBROWSEFORFOLDER pfSHBrowseForFolder; static const CHAR achShell32Lib[] = "SHELL32.DLL"; static const CHAR achSHBrowseForFolder[] = "SHBrowseForFolder"; static const CHAR achSHGetPathFromIDList[] = "SHGetPathFromIDList";
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 ( ! ctx.szBrowsePath[0] ) { GetProgramFilesDir( ctx.szBrowsePath, sizeof(ctx.szBrowsePath) ); }
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)ctx.szBrowsePath;
pidl = pfSHBrowseForFolder( &bi );
if ( pidl ) { pfSHGetPathFromIDList( pidl, ctx.szBrowsePath ); if ( ctx.szBrowsePath[0] ) { lstrcpy( szResult, ctx.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: IsGoodDir *
//* *
//* SYNOPSIS: Find out if it's a good temporary directory or not. *
//* *
//* REQUIRES: szPath: *
//* *
//* RETURNS: BOOL: TRUE if good, FALSE if nogood *
//* *
//***************************************************************************
BOOL IsGoodDir( LPCSTR szPath ) { DWORD dwAttribs; HANDLE hFile; char szTestFile[MAX_PATH];
lstrcpy( szTestFile, szPath ); AddPath( szTestFile, "TMP4352$.TMP" ); DeleteFile( szTestFile ); hFile = CreateFile( szTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) { return( FALSE ); }
CloseHandle( hFile ); dwAttribs = GetFileAttributes( szPath );
if ( ( dwAttribs != 0xFFFFFFFF ) && ( dwAttribs & FILE_ATTRIBUTE_DIRECTORY ) ) { return( TRUE ); }
return( FALSE ); }
//***************************************************************************
//* *
//* NAME: CtlSetLDDPath *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT CtlSetLddPath( UINT uiLDID, LPSTR lpszPath, DWORD dwSwitches ) { PSTR pszNewPath = NULL; BOOL fSuccess = TRUE; DWORD dwNewPathSize = 0; HRESULT hResult = S_OK; PSTR lpTmp; BOOL bDBC = FALSE;
dwNewPathSize = max( MAX_PATH, lstrlen(lpszPath) + 1 );
pszNewPath = (PSTR) LocalAlloc( LPTR, dwNewPathSize ); if ( !pszNewPath ) { hResult = HRESULT_FROM_WIN32(GetLastError()); ErrorMsg( ctx.hWnd, IDS_ERR_NO_MEMORY ); goto done; }
if ( ((ctx.dwSetupEngine == ENGINE_SETUPX) && (dwSwitches & LDID_SFN)) || ((dwSwitches & LDID_SFN_NT_ALSO)&& (ctx.wOSVer == _OSVER_WIN95)) ) { if ( GetShortPathName( lpszPath, pszNewPath, dwNewPathSize ) == 0 ) { hResult = HRESULT_FROM_WIN32(GetLastError()); ErrorMsg( ctx.hWnd, IDS_ERR_SHORT_NAME ); goto done; } } else lstrcpy( pszNewPath, lpszPath );
if ( ctx.dwSetupEngine == ENGINE_SETUPX ){
if ( dwSwitches & LDID_OEM_CHARS ) { CharToOem( pszNewPath, pszNewPath ); }
lpTmp = pszNewPath + lstrlen(pszNewPath) - 1; if (*lpTmp == '\\') // Is the last byte a backslash
{ // Check if it is the trail byte of a DBC
lpTmp = pszNewPath; do { bDBC = IsDBCSLeadByte(*lpTmp); lpTmp = CharNext(lpTmp); } while (*lpTmp);
if (bDBC) { // The backslash is a trail byte. Add another backslash
AddPath(pszNewPath, ""); } }
if ( pfCtlSetLddPath32( uiLDID, pszNewPath ) ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_SET_LDID, pszNewPath ); hResult = E_FAIL; goto done; } } else { hResult = MySetupSetDirectoryId( uiLDID, pszNewPath ); if ( FAILED( hResult ) ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_SET_LDID, pszNewPath ); goto done; } }
done:
if ( pszNewPath ) { LocalFree( pszNewPath ); }
return hResult; }
//***************************************************************************
//* *
//* NAME: GenInstall *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: lpszInfFileName: Filename of INF file. *
//* lpszSection: Section of the INF to install *
//* lpszDirectory: Directory of CABs (Temp Dir). *
//* *
//* RETURNS: BOOL: Error result, FALSE == ERROR *
//* *
//***************************************************************************
HRESULT GenInstall( LPSTR lpszInfFilename, LPSTR lpszInstallSection, LPSTR lpszSourceDir ) { CHAR szErrorText[BIG_STRING]; DWORD dwError = 0; HRESULT hResult = S_OK; CHAR szSourceDir[MAX_PATH]; DWORD dwLen = 0;
// Remove trailing backslash from the source directory
lstrcpy( szSourceDir, lpszSourceDir ); dwLen = lstrlen( szSourceDir ); if ( szSourceDir[dwLen-2] != ':' && szSourceDir[dwLen-1] == '\\' ) { szSourceDir[dwLen-1] = '\0'; }
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { CHAR szSFNInf[MAX_PATH] = { 0 };
GetShortPathName( lpszInfFilename, szSFNInf, sizeof(szSFNInf) ); GetShortPathName( szSourceDir, szSourceDir, sizeof(szSourceDir) ); dwError = pfGenInstall32( szSFNInf, lpszInstallSection, szSourceDir, (DWORD) ctx.wQuietMode, HandleToUlong(ctx.hWnd) ); if ( dwError ) { szErrorText[0] = '\0'; pfGetSETUPXErrorText32( dwError, szErrorText, sizeof(szErrorText) ); ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_FAIL, szErrorText ); hResult = E_FAIL; } } else { hResult = InstallOnNT( lpszInstallSection, szSourceDir ); if ( FAILED( hResult ) ) { if ( !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, szErrorText, sizeof(szErrorText), NULL) ) { LoadSz( IDS_ERR_FMTMSG, szErrorText, sizeof(szErrorText) ); if ( *szErrorText == 0 ) lstrcpy( szErrorText, "Could not get the system message. You may run out of the resource." ); }
ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_FAILURE, szErrorText ); } }
return hResult; }
//***************************************************************************
//* *
//* NAME: GetValueFromRegistry *
//* *
//* SYNOPSIS: Get an app-path out of the registry as specified. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: BOOL: Error result, FALSE == ERROR *
//* *
//***************************************************************************
BOOL GetValueFromRegistry( LPSTR szPath, UINT cbPath, LPSTR szKey, LPSTR szSubKey, LPSTR szVName ) { HKEY hkPath = NULL; DWORD dwType = 0; DWORD dwSize = 0; HKEY hkRoot = NULL; PSTR pszTemp = NULL;
// Figure out what root key they want to check
if ( lstrcmpi( szKey, "HKCR" ) == 0 ) { hkRoot = HKEY_CLASSES_ROOT; } else if ( lstrcmpi( szKey, "HKCU" ) == 0 ) { hkRoot = HKEY_CURRENT_USER; } else if ( lstrcmpi( szKey, "HKLM" ) == 0 ) { hkRoot = HKEY_LOCAL_MACHINE; } else if ( lstrcmpi( szKey, "HKU" ) == 0 ) { hkRoot = HKEY_USERS; } else if ( *szKey == '\0' ) { // If they don't specify a root key, then assume they don't want to check
// the registry. So just return as if the registry key doesn't exist.
return FALSE; } else { ErrorMsg( ctx.hWnd, IDS_ERR_INVALID_REGROOT ); return FALSE; }
// Get Path to program from the registry
if ( RegOpenKeyEx( hkRoot, szSubKey, (ULONG) 0, KEY_READ, &hkPath ) != ERROR_SUCCESS ) { return( FALSE ); }
dwSize = cbPath; if ( RegQueryValueEx( hkPath, szVName, NULL, &dwType, (LPBYTE) szPath, &dwSize) != ERROR_SUCCESS ) { RegCloseKey( hkPath ); return( FALSE ); }
RegCloseKey( hkPath );
// If we got nothing or it wasn't a string then we bail out
if ( (dwSize == 0) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) ) { return( FALSE ); }
if ( dwType == REG_EXPAND_SZ ) { pszTemp = (PSTR) LocalAlloc( LPTR, cbPath ); if ( pszTemp == NULL ) { return( FALSE ); } lstrcpy( pszTemp, szPath ); dwSize = ExpandEnvironmentStrings( pszTemp, szPath, cbPath ); LocalFree( pszTemp );
if ( dwSize == 0 || dwSize > cbPath ) { return( FALSE ); } }
return( TRUE ); }
//***************************************************************************
//* *
//* NAME: SetLDIDs *
//* *
//* SYNOPSIS: Sets the LDIDs as specified in the INF file. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//* NOTE: If c_pszSourceDir != NULL then we want to set the source *
//* directory and nothing else. *
//* *
//***************************************************************************
HRESULT SetLDIDs( PCSTR c_pszInfFilename, PCSTR c_pszInstallSection, DWORD dwInstNeedSize, PCSTR c_pszSourceDir ) { CHAR szDestSection[256]; CHAR szDestLDIDs[512]; PSTR pszDestLDID = NULL; PSTR pszNextDestLDID = NULL; CHAR szDestData[256]; DWORD dwStringLength = 0; LPSTR pszCustomSection; DWORD dwLDID[4] = { 0 }; DWORD dwSwitches = 0; DWORD i = 0; DWORD dwFlag = 1; HRESULT hResult = S_OK; CHAR szBuffer[MAX_PATH+2]; static const CHAR c_szCustDest[] = "CustomDestination"; static const CHAR c_szSourceDirKey[] = "SourceDir"; PSTR pszTmp;
// Get section name that specifies the custom LDID information.
if ( FAILED(GetTranslatedString( c_pszInfFilename, c_pszInstallSection, c_szCustDest, szDestSection, sizeof(szDestSection), NULL))) { // There is no Custom Destination specification -- this probably
// means they didn't want to have a custom destination section,
// so we just return with a warm, tingly feeling
hResult = S_OK; goto done; }
// author defined CustomDestination, so add some system directories to the reg before continuing
SetSysPathsInReg();
dwStringLength = GetTranslatedSection( c_pszInfFilename, szDestSection, szDestLDIDs, sizeof(szDestLDIDs)); if ( dwStringLength == 0 ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, szDestSection ); hResult = E_FAIL; goto done; }
pszDestLDID = szDestLDIDs;
while ( *pszDestLDID != '\0' ) { pszNextDestLDID = pszDestLDID + lstrlen(pszDestLDID) + 1;
if (*pszDestLDID == ';') { pszDestLDID = pszNextDestLDID; continue; }
#if 0
hResult = GetTranslatedString( c_pszInfFilename, szDestSection, pszDestLDID, szDestData, sizeof(szDestData), NULL);
if (FAILED(hResult)) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, szDestSection ); goto done; } #endif
if ( pszTmp = ANSIStrChr(pszDestLDID, '=') ) { lstrcpy(szDestData, CharNext(pszTmp)); *pszTmp = '\0'; } else { // invalid define LDID line skip
pszDestLDID = pszNextDestLDID; continue; }
// Parse out the information in this line.
dwFlag = ParseDestinationLine( pszDestLDID, szDestData, &pszCustomSection, &dwLDID[0], &dwLDID[1], &dwLDID[2], &dwLDID[3] ); if ( dwFlag == -1 ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, szDestSection ); hResult = E_FAIL; goto done; }
if ( lstrcmpi( pszCustomSection, c_szSourceDirKey ) == 0 ) { if ( c_pszSourceDir == NULL ) { // The line specifies "SourceDir" but we don't want to set the source dir
pszDestLDID = pszNextDestLDID; continue; } } else { if ( c_pszSourceDir != NULL ) { // The line doesn't specify "SourceDir" but we want to set the source dir
pszDestLDID = pszNextDestLDID; continue; } }
if ( c_pszSourceDir != NULL ) { // szBuffer is MAX_PATH big and c_pszSourceDir is a path, so we
// shouldn't have a problem.
lstrcpy( szBuffer, c_pszSourceDir ); } else { hResult = GetDestinationDir( c_pszInfFilename, pszCustomSection, dwFlag, dwInstNeedSize, szBuffer, sizeof(szBuffer) ); if ( FAILED(hResult) ) { // Error message displayed in GetDestinationDir
goto done; } }
for ( i = 0; i < 4; i += 1 ) { // Default is ANSI LFN
dwSwitches = 0;
if ( dwLDID[i] == 0 ) { continue; }
if ( i == 0 || i == 3 ) { dwSwitches |= LDID_OEM_CHARS; }
if ( (i == 0 || i == 2) && (dwFlag & FLAG_VALUE && !(dwFlag & FLAG_NODIRCHECK) ) ) { dwSwitches |= LDID_SFN; if ((i==0) && (dwLDID[3] != 0) ) { dwSwitches |= LDID_SFN_NT_ALSO; }
if ((i==2) && (dwLDID[1] != 0)) { dwSwitches |= LDID_SFN_NT_ALSO; } }
hResult = CtlSetLddPath( dwLDID[i], szBuffer, dwSwitches ); if ( FAILED( hResult ) ) { // Error message is displayed in ClSetLddPath function.
goto done; } }
pszDestLDID = pszNextDestLDID; }
done:
return hResult; }
//***************************************************************************
//* *
//* NAME: GetDestinationDir *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT GetDestinationDir( PCSTR c_pszInfFilename, PCSTR c_pszCustomSection, DWORD dwFlag, DWORD dwInstNeedSize, PSTR pszBuffer, DWORD dwBufferSize ) { BOOL fFoundRegKey = FALSE; BOOL fFoundLine = FALSE; DWORD j = 0; PSTR pszCustomData = NULL; PSTR pszCurCustomData = NULL; LPSTR pszRootKey = NULL; LPSTR pszBranch = NULL; LPSTR pszValueName = NULL; LPSTR pszPrompt = NULL; LPSTR pszDefault = NULL; HRESULT hResult = S_OK; CHAR szValue[MAX_PATH+2];
ASSERT( pszBuffer != NULL );
// Reset reg key found flag. For each custom destination, we want to set
// this flag to TRUE if any one of the registry keys are found.
fFoundRegKey = FALSE; fFoundLine = FALSE;
for ( j = 0; ; j += 1 ) { if ( FAILED( GetTranslatedLine( c_pszInfFilename, c_pszCustomSection, j, &pszCurCustomData, NULL ) ) || !pszCurCustomData ) { break; }
fFoundLine = TRUE;
// save the last valid customData line before the break off
if ( pszCustomData ) { LocalFree( pszCustomData ); } pszCustomData = pszCurCustomData;
// Parse out the fields in the custom destination line.
if ( ! ParseCustomLine( pszCustomData, &pszRootKey, &pszBranch, &pszValueName, &pszPrompt, &pszDefault, TRUE, TRUE ) ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, c_pszCustomSection ); hResult = E_FAIL; goto done; }
// Check the specified registry branch and grab the contents.
if ( GetValueFromRegistry( szValue, sizeof(szValue), pszRootKey, pszBranch, pszValueName ) == TRUE ) { LPSTR pszTmp;
// If the INF says to strip trailing semi-colon,
// and there is a trailing semi-colon,
// then strip it.
if ( !( dwFlag & FLAG_NOSTRIP ) ) { if ( dwFlag & FLAG_STRIPAFTER_FIRST ) { pszTmp = ANSIStrChr( szValue, ';' ); if ( pszTmp ) *pszTmp = '\0'; } else { if ( szValue[lstrlen(szValue)-1] == ';' ) { szValue[lstrlen(szValue)-1] = '\0'; } } }
// strip off the trailing blanks
pszTmp = szValue; pszTmp += lstrlen(szValue) - 1;
while ( *pszTmp == ' ' ) { *pszTmp = '\0'; pszTmp -= 1; }
// If the INF says to check if directory exists,
// and the directory doesn't exist,
// then treat as if the reg key wasn't found
if ( ! ( dwFlag & FLAG_NODIRCHECK ) && ! DirExists( szValue ) ) { // Directory doesn't exist. Don't break out of loop.
} else { // Directory exists
// If the INF says to save the branch in the LDID,
// then save the branch.
// Otherwise save the value.
if ( dwFlag & FLAG_VALUE ) { pszDefault = szValue; } else { pszDefault = pszBranch; }
fFoundRegKey = TRUE; break; } } // Note; If the registry key is not found, then the defaults as specified in
// the INF file are used.
}
if ( ! fFoundLine ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_INF_SYNTAX, c_pszCustomSection ); hResult = E_FAIL; goto done; }
// 2 specified + 32 not specified + not found reg
// 2 specified + 32 specified + found reg
if ( ((dwFlag & FLAG_FAIL) && (!(dwFlag & FLAG_FAIL_NOT)) && (fFoundRegKey == FALSE)) || ((dwFlag & FLAG_FAIL) && (dwFlag & FLAG_FAIL_NOT) && (fFoundRegKey == TRUE)) ) { // NOTE: This uses the prompt specified in the INF file.
ErrorMsg1Param( ctx.hWnd, IDS_PROMPT, pszPrompt ); hResult = E_FAIL; goto done; }
// Prompt the user for the destination directory.
if ( (dwFlag & FLAG_VALUE) && (! (dwFlag & FLAG_NODIRCHECK)) ) { if ( ctx.wQuietMode || (dwFlag & FLAG_QUIET) ) { lstrcpy( szValue, pszDefault );
// check if the directory has enough disk space to install the program
if ( !IsFullPath(szValue) ) { hResult = E_FAIL; goto done; }
if ( !IsEnoughInstSpace( szValue, dwInstNeedSize, NULL ) ) { ErrorMsg( ctx.hWnd, IDS_ERR_USER_CANCEL_INST ); hResult = HRESULT_FROM_WIN32(ERROR_DISK_FULL); goto done; }
if ( ! DirExists( szValue ) ) { hResult = CreateFullPath( szValue, FALSE ); if ( FAILED(hResult) ) { goto done; } } if ( ! IsGoodDir( szValue ) ) { hResult = E_FAIL; goto done; }
pszDefault = szValue; } else { CHAR szLFNValue[MAX_PATH*2];
MakeLFNPath(pszDefault, szLFNValue, TRUE); if ( UserDirPrompt( pszPrompt, szLFNValue, szValue, sizeof(szValue), dwInstNeedSize ) ) { pszDefault = szValue; } else { ErrorMsg( ctx.hWnd, IDS_ERR_USER_CANCEL_INST ); hResult = HRESULT_FROM_WIN32(ERROR_CANCELLED); goto done; } } }
if ( (DWORD)lstrlen(pszDefault) >= dwBufferSize ) { ErrorMsg( ctx.hWnd, IDS_ERR_TOO_BIG ); hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto done; }
lstrcpy( pszBuffer, pszDefault );
done: // free the buf allocated by GetTranslatedLine
if ( pszCustomData ) { if ( pszCustomData == pszCurCustomData ) pszCurCustomData = NULL; LocalFree( pszCustomData ); }
if ( pszCurCustomData ) { LocalFree( pszCurCustomData ); }
return hResult; }
//***************************************************************************
//* *
//* NAME: DirExists *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL DirExists( LPSTR szDir ) { DWORD dwAttribs = 0;
if ( szDir == NULL ) { return FALSE; }
dwAttribs = GetFileAttributes( szDir ); if ( ( dwAttribs != 0xFFFFFFFF ) && ( dwAttribs & FILE_ATTRIBUTE_DIRECTORY ) ) { return TRUE; }
return FALSE; }
//***************************************************************************
//* *
//* NAME: ParseDestinationLine *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//* Bitwise flags: *
//* *
//* bit Off On Value *
//* --- -------------------- ---------------------------- ----- *
//* 0 Get value Get branch 1 *
//* 1 Use default if none exist Fail if none exist 2 *
//* 2 Non-quiet mode Quiet mode 4 *
//* 3 Strip trailing ";" Don't strip trailing ";" 8 *
//* 4 Treat value as directory Treat value as plain string 16 *
//* *
//***************************************************************************
DWORD ParseDestinationLine( PSTR pszLDIDs, PSTR pszValue, PSTR *ppszSectionName, PDWORD pdwLDID1, PDWORD pdwLDID2, PDWORD pdwLDID3, PDWORD pdwLDID4 ) { PSTR pszPoint = NULL; DWORD dwFlag = DEFAULT_FLAGS; DWORD dwLDID[4] = { 0 }; DWORD i = 0; PSTR pszStr;
pszPoint = pszLDIDs;
for ( i = 0; i < 4; i += 1 ) { // Parse the arguments, SETUP engine is not called. So we only need to check on \'
pszStr = GetStringField( &pszPoint, ",", '\"', TRUE );
if ( pszStr == NULL ) { dwLDID[i] = 0; } else { dwLDID[i] = (DWORD) My_atol(pszStr); } }
*pdwLDID1 = dwLDID[0]; *pdwLDID2 = dwLDID[1]; *pdwLDID3 = dwLDID[2]; *pdwLDID4 = dwLDID[3];
pszStr = pszValue; *ppszSectionName = GetStringField( &pszStr, ",", '\"', TRUE ); if ( *ppszSectionName == NULL || **ppszSectionName == '\0' ) { return (DWORD)-1; }
pszPoint = GetStringField( &pszStr, ",", '\"', TRUE ); if ( pszPoint != NULL && *pszPoint != '\0' ) { dwFlag = (DWORD) My_atol(pszPoint); }
// Special case this. We definitely don't want to prompt the user
// for a registry branch to use!
if ( !( dwFlag & FLAG_VALUE ) ) { dwFlag |= FLAG_QUIET; }
return dwFlag; }
//***************************************************************************
//* *
//* NAME: ParseCustomLine *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL ParseCustomLine( PSTR pszCheckKey, PSTR *ppszRootKey, PSTR *ppszBranch, PSTR *ppszValueName, PSTR *ppszPrompt, PSTR *ppszDefault, BOOL bStripWhiteSpace, BOOL bProcQuote ) { DWORD i = 0; PSTR pszField[5] = { NULL }; BOOL bRet = TRUE;
for ( i = 0; i < 5; i++ ) { // Parse the arguments, SETUP engine has processed \" so we only need to check on \'
if (bProcQuote) pszField[i] = GetStringField( &pszCheckKey, ",", '\'', bStripWhiteSpace ); else pszField[i] = GetStringFieldNoQuote( &pszCheckKey, ",", bStripWhiteSpace );
if ( pszField[i] == NULL ) { bRet = FALSE; break; } }
*ppszRootKey = pszField[0]; *ppszBranch = pszField[1]; *ppszValueName = pszField[2]; *ppszPrompt = pszField[3]; *ppszDefault = pszField[4];
return bRet; }
//***************************************************************************
//* *
//* NAME: RegisterOCXs *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL RegisterOCXs( LPSTR szInfFilename, LPSTR szInstallSection, BOOL fNeedReboot, BOOL fRegister, DWORD dwFlags ) { HRESULT hReturnCode = S_OK; BOOL fOleInitialized = TRUE; PSTR pszOCXLine = NULL; BOOL fSuccess = TRUE; PSTR pszSection = NULL; DWORD i = 0; REGOCXDATA RegOCX = { 0 }; CHAR szRegisterSection[256]; PSTR pszNotUsed; static const CHAR c_szREGISTEROCXSECTION[] = "RegisterOCXs"; static const CHAR c_szUNREGISTEROCXSECTION[] = "UnRegisterOCXs";
// If we want to register, then use the register section.
// If we want to unregister, then use the unregister section.
if ( fRegister ) { if ( dwFlags & COREINSTALL_ROLLBACK ) { pszSection = (PSTR) c_szUNREGISTEROCXSECTION; if ( FAILED(GetTranslatedString( szInfFilename, szInstallSection, pszSection, szRegisterSection, sizeof(szRegisterSection), NULL))) { pszSection = (PSTR) c_szREGISTEROCXSECTION; } } else pszSection = (PSTR) c_szREGISTEROCXSECTION; } else { // if it is call with ROLLBACKL flag on,
// we have backed up all the files and reg data. Now we need to unregist (the new)OCXs from Register list
// before register the old one.
//
if ( dwFlags & COREINSTALL_ROLLBACK ) pszSection = (PSTR) c_szREGISTEROCXSECTION; else pszSection = (PSTR) c_szUNREGISTEROCXSECTION; }
// Grab the section name of the Register OCX section
if ( FAILED(GetTranslatedString( szInfFilename, szInstallSection, pszSection, szRegisterSection, sizeof(szRegisterSection), NULL))) { // There is no Register OCX section. Assume the user wanted it that
// way and return with a big smile.
return TRUE; }
if ( FAILED( OleInitialize( NULL ) ) ) { fOleInitialized = FALSE; } #pragma prefast(disable:56,"False warning at OemToChar line. Using workaround to disable it - PREfast bug 643")
for ( i = 0; ; i += 1 ) { if ( pszOCXLine ) { LocalFree( pszOCXLine ); pszOCXLine = NULL; }
if ( FAILED( GetTranslatedLine( szInfFilename, szRegisterSection, i, &pszOCXLine, NULL ) ) ) { break; }
// process OCX line: Name [,<switch>,<str>] where switch - i== call both entries; in == only call
// DllRegister; n == call none; Empty means just call old DllRegister.
ParseCustomLine( pszOCXLine, &(RegOCX.pszOCX), &(RegOCX.pszSwitch), &(RegOCX.pszParam), &pszNotUsed, &pszNotUsed, TRUE, FALSE );
if ( ctx.dwSetupEngine == ENGINE_SETUPX ) { OemToChar( RegOCX.pszOCX, RegOCX.pszOCX ); }
// before re-regiester OCX at ROLLBACK case, we need to check if the file exists.
// IF not, we don't want to try to register it.
if ( dwFlags & COREINSTALL_ROLLBACK ) { DWORD dwAttr;
dwAttr = GetFileAttributes( RegOCX.pszOCX ); if ( (dwAttr == -1 ) || (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) { //skip this one
continue; } }
// If we need to reboot, then just add registrations to the run once entry.
// Otherwise try to register right away.
// If we are unregistering OCXs, then fNeedReboot should always be FALSE,
// since unregistration happens before a GenInstall.
if ( !fNeedReboot && ( !fRegister || !(dwFlags & COREINSTALL_DELAYREGISTEROCX) ) ) { // no reboot case, the last one params are ignored.
if ( !InstallOCX( &RegOCX, TRUE, fRegister, i ) && !(dwFlags & COREINSTALL_ROLLBACK) ) { fSuccess = FALSE;
if ( fRegister ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_REG_OCX, RegOCX.pszOCX ); goto done; } else { ErrorMsg1Param( ctx.hWnd, IDS_ERR_UNREG_OCX, RegOCX.pszOCX ); } } } else {
// Add a runonce entry so that the OCX is registered on next boot.
//
if ( !InstallOCX( &RegOCX, FALSE, fRegister, i ) ) { ErrorMsg1Param( ctx.hWnd, IDS_ERR_RUNONCE_REG_OCX, RegOCX.pszOCX ); fSuccess = FALSE; goto done; } }
} #pragma prefast(enable:56,"")
done:
if ( fOleInitialized ) { OleUninitialize(); }
if ( pszOCXLine ) { LocalFree( pszOCXLine ); }
return fSuccess; }
//***************************************************************************
//* *
//* NAME: DelDirs *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
void DelDirs( LPCSTR szInfFilename, LPCSTR szInstallSection ) { PSTR pszFolder = NULL; CHAR szDelDirsSection[MAX_PATH]; DWORD i = 0;
if ( FAILED(GetTranslatedString( szInfFilename, szInstallSection, ADVINF_DELDIRS, szDelDirsSection, sizeof(szDelDirsSection), NULL))) { // no demands on remove folders
return; }
for ( i = 0; ; i++ ) { if ( FAILED( GetTranslatedLine( szInfFilename, szDelDirsSection, i, &pszFolder, NULL ) ) || !pszFolder ) { break; }
MyRemoveDirectory( pszFolder );
LocalFree( pszFolder ); pszFolder = NULL; } return; }
//***************************************************************************
//* *
//* NAME: DoCleanup *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
void DoCleanup( LPCSTR szInfFilename, LPCSTR szInstallSection ) { int iFlags;
iFlags = GetTranslatedInt(szInfFilename, szInstallSection, ADVINF_CLEANUP, 0);
if ( iFlags & CLEN_REMVINF ) { DeleteFile( szInfFilename ); }
return; }
// greater than 4.71.0219
//
#define ROEX_VERSION_MS 0x00040047 // 4.71
#define ROEX_VERSION_LS 0x00DB0000 // 0219.0
BOOL UseRunOnceEx() { DWORD dwMV, dwLV; BOOL bRet = FALSE; char szPath[MAX_PATH] = ""; char szBuf[MAX_PATH] = ""; DWORD dwTmp;
GetSystemDirectory( szPath,sizeof( szPath ) ); AddPath( szPath, "iernonce.dll" ); GetVersionFromFile( szPath, &dwMV, &dwLV, TRUE );
// greater than 4.71.0230
//
if ( ( dwMV > ROEX_VERSION_MS ) || (( dwMV == ROEX_VERSION_MS ) && ( dwLV >= ROEX_VERSION_LS )) ) { GetWindowsDirectory( szBuf, MAX_PATH ); AddPath( szBuf, "explorer.exe" ); GetVersionFromFile( szBuf, &dwMV, &dwLV, TRUE ); if (( dwMV < ROEX_VERSION_MS) || (( dwMV == ROEX_VERSION_MS) && ( dwLV < ROEX_VERSION_LS )) ) { HKEY hkey; if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &dwTmp ) == ERROR_SUCCESS ) { wsprintf( szBuf, RUNONCE_IERNONCE, szPath ); if ( RegSetValueEx( hkey, RUNONCEEX, 0, REG_SZ, (CONST UCHAR *)szBuf, lstrlen(szBuf)+1 ) != ERROR_SUCCESS ) { bRet = FALSE; RegCloseKey( hkey ); goto done; } RegCloseKey( hkey ); } else bRet = FALSE; } bRet = TRUE; }
done: return bRet; }
void GetNextRunOnceExSubKey( HKEY hKey, PSTR pszSubKey, int *piSubKeyNum ) { HKEY hSubKey;
for (;;) { wsprintf( pszSubKey, "%d", ++*piSubKeyNum ); if ( RegOpenKeyEx( hKey, pszSubKey,(ULONG) 0, KEY_READ, &hSubKey ) != ERROR_SUCCESS ) { break; } else { RegCloseKey( hSubKey ); } } }
void GetNextRunOnceValName( HKEY hKey, PCSTR pszFormat, PSTR pszValName, int line ) {
do { wsprintf( pszValName, pszFormat, line++ );
} while ( RegQueryValueEx( hKey, pszValName, 0, NULL, NULL, NULL ) == ERROR_SUCCESS );
}
BOOL DoDllReg( HANDLE hOCX, BOOL fRegister ) { FARPROC lpfnDllRegisterServer = NULL; PSTR pszRegSvr = NULL; BOOL fSuccess = FALSE;
if ( fRegister ) { pszRegSvr = (PSTR) achREGSVRDLL; } else { pszRegSvr = (PSTR) achUNREGSVRDLL; }
lpfnDllRegisterServer = GetProcAddress( hOCX, pszRegSvr ); if ( lpfnDllRegisterServer ) { if ( SUCCEEDED( lpfnDllRegisterServer() ) ) { fSuccess = TRUE; } } return fSuccess; }
BOOL DoDllInst( HANDLE hOCX, BOOL fRegister, PCSTR pszParam ) { WCHAR pwstrDllInstArg[MAX_PATH]; DLLINSTALL pfnDllInstall = NULL; BOOL fSuccess = FALSE;
if ( pszParam == NULL ) pszParam = "";
pfnDllInstall = (DLLINSTALL)GetProcAddress( hOCX, "DllInstall" ); if ( pfnDllInstall ) { MultiByteToWideChar(CP_ACP, 0, pszParam, -1, pwstrDllInstArg, ARRAYSIZE(pwstrDllInstArg));
if ( SUCCEEDED( pfnDllInstall( fRegister, pwstrDllInstArg ) ) ) fSuccess = TRUE; } return fSuccess; }
//***************************************************************************
//* *
//* NAME: InstallOCX *
//* *
//* SYNOPSIS: Self-registers the OCX. *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
BOOL InstallOCX( PREGOCXDATA pRegOCX, BOOL fDoItNow, BOOL fRegister, int line ) { PSTR lpszCmdLine = NULL; PSTR lpszCmdLine2 = NULL; BOOL fSuccess = TRUE; HKEY hKey = NULL, hSubKey = NULL; HANDLE hOCX = NULL; BOOL bDoDllReg = TRUE, bDoDllInst = FALSE; PSTR pszCmds[2] = { 0 }; int i;
AdvWriteToLog("InstallOCX: %1 %2\r\n", pRegOCX->pszOCX, fRegister?"Register":"UnRegister" ); // parse what kind OCX entry points to call
if ( pRegOCX->pszSwitch && *pRegOCX->pszSwitch ) { if ( ANSIStrChr( CharUpper(pRegOCX->pszSwitch), 'I' ) ) { bDoDllInst = TRUE; if ( ANSIStrChr( CharUpper(pRegOCX->pszSwitch), 'N' ) ) bDoDllReg = FALSE; } else { fSuccess = FALSE; goto done; } }
lpszCmdLine = (LPSTR) LocalAlloc( LPTR, BUF_1K ); lpszCmdLine2 = (LPSTR) LocalAlloc( LPTR, BUF_1K ); if ( !lpszCmdLine || !lpszCmdLine2) { ErrorMsg( ctx.hWnd, IDS_ERR_NO_MEMORY ); fSuccess = FALSE; goto done; }
// fDoItNow says whether we should add to runonce or register the OCX right away
if ( fDoItNow ) { LPCSTR szExtension = NULL;
// ignore the display name line in this case
if ( *(pRegOCX->pszOCX) == '@' ) { goto done; }
// Figure out what type of OCX we are trying to register: two choices
// 1. EXE
// 2. DLL/OCX/etc
//
szExtension = &pRegOCX->pszOCX[lstrlen(pRegOCX->pszOCX)-3];
if ( lstrcmpi( szExtension, "EXE" ) == 0 ) { PSTR pszRegSvr;
if ( fRegister ) pszRegSvr = (PSTR) achREGSVREXE; else pszRegSvr = (PSTR) achUNREGSVREXE;
lstrcpy( lpszCmdLine, pRegOCX->pszOCX ); lstrcat( lpszCmdLine, pszRegSvr );
if ( LaunchAndWait( lpszCmdLine, NULL, NULL, INFINITE, 0 ) == E_FAIL ) { AdvWriteToLog("InstallOCX: %1 Failed\r\n", lpszCmdLine); fSuccess = FALSE; goto done; } AdvWriteToLog("%1 : Succeeded.\r\n", lpszCmdLine); } else { AdvWriteToLog("LoadLibrary %1\r\n", pRegOCX->pszOCX); hOCX = LoadLibraryEx( pRegOCX->pszOCX, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); if ( hOCX == NULL ) { fSuccess = FALSE; goto done; }
// Install time order: DllRegisterServer, DllInstall
// Uninstall order: DllInstall, DllRegisterServer
if ( fRegister ) { if ( bDoDllReg ) { fSuccess = DoDllReg( hOCX, fRegister ); AdvWriteToLog("Register: DoDllReg: %1\r\n", fSuccess?"Succeeded":"Failed" ); }
if ( fSuccess && bDoDllInst ) { fSuccess = DoDllInst( hOCX, fRegister, pRegOCX->pszParam ); AdvWriteToLog("Register: DoDllInstall: %1\r\n", fSuccess?"Succeeded":"Failed" ); } } else { if ( bDoDllInst ) { fSuccess = DoDllInst( hOCX, fRegister, pRegOCX->pszParam ); AdvWriteToLog("UnRegister: DoDllReg: %1\r\n", fSuccess?"Succeeded":"Failed" ); }
if ( fSuccess && bDoDllReg ) { fSuccess = DoDllReg( hOCX, fRegister ); AdvWriteToLog("UnRegister: DoDllInstall: %1\r\n", fSuccess?"Succeeded":"Failed" ); } } } } else { // Add to runonce or runonceex
// from current logic, Unregister OCX will never be here!
//
char szPath[MAX_PATH]; LPCSTR lpRegTmp; DWORD dwTmp; HKEY hRealKey; static BOOL bRunOnceEx = FALSE; static int iSubKeyNum = 0;
if ( iSubKeyNum == 0 ) { if ( UseRunOnceEx() ) { iSubKeyNum = 799; bRunOnceEx = TRUE; } }
// decide to add the entry to RunOnce or RunOnceEx
if ( !bRunOnceEx ) { // ignore the display name line in this case
if ( *(pRegOCX->pszOCX) == '@' ) { goto done; } // no ierunonce.dll, use RunOnce key rather than RunOnceEx key
lpRegTmp = REGSTR_PATH_RUNONCE; } else { lpRegTmp = REGSTR_PATH_RUNONCEEX; }
// open RunOnce or RunOnceEx key here
if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, lpRegTmp, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwTmp ) != ERROR_SUCCESS ) { fSuccess = FALSE; goto done; }
// Generate the next unused SubKey name
//
if ( bRunOnceEx ) { if ( line == 0 ) GetNextRunOnceExSubKey( hKey, szPath, &iSubKeyNum ); else wsprintf( szPath, "%d", iSubKeyNum ); }
// Generate the Value Name and ValueData.
//
if ( bRunOnceEx ) { if ( RegCreateKeyEx( hKey, szPath, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hSubKey, &dwTmp ) != ERROR_SUCCESS ) { fSuccess = FALSE; goto done; }
// if use RunOnceEx, process @ leaded display name.
if ( *pRegOCX->pszOCX == '@' ) { if ( RegSetValue( hKey, szPath, REG_SZ, (LPCSTR)CharNext(pRegOCX->pszOCX), lstrlen(CharNext(pRegOCX->pszOCX))+1 ) != ERROR_SUCCESS ) { fSuccess = FALSE; } goto done; }
GetNextRunOnceValName( hSubKey, "%03d", szPath, line ); if ( bDoDllReg ) { wsprintf( lpszCmdLine, RUNONCEEXDATA, pRegOCX->pszOCX, fRegister? achREGSVRDLL : achUNREGSVRDLL ); }
if ( bDoDllInst ) { wsprintf( lpszCmdLine2, "%s|%s|%c,%s",pRegOCX->pszOCX, "DllInstall", fRegister? 'i':'u', pRegOCX->pszParam ? pRegOCX->pszParam : "" ); } hRealKey = hSubKey; if ( fRegister ) { pszCmds[0] = lpszCmdLine; pszCmds[1] = lpszCmdLine2; } else { pszCmds[1] = lpszCmdLine; pszCmds[0] = lpszCmdLine2; } } else { GetNextRunOnceValName( hKey, achIEXREG, szPath, line ); wsprintf( lpszCmdLine, achRUNDLL, pRegOCX->pszOCX, pRegOCX->pszSwitch ?pRegOCX->pszSwitch:"", pRegOCX->pszParam ? pRegOCX->pszParam : "" ); hRealKey = hKey; pszCmds[0] = lpszCmdLine; pszCmds[1] = ""; }
for ( i=0; i<2; i++ ) { if (*pszCmds[i]) { AdvWriteToLog("Delay Register: Value=%1 Data=%2\r\n", szPath, pszCmds[i]); if ( RegSetValueEx( hRealKey, szPath, 0, REG_SZ, (CONST UCHAR *) pszCmds[i], lstrlen(pszCmds[i])+1 ) != ERROR_SUCCESS ) { fSuccess = FALSE; goto done; }
if ( bRunOnceEx ) GetNextRunOnceValName( hRealKey, "%03d", szPath, line ); } } }
done:
if ( hOCX != NULL ) { FreeLibrary( hOCX ); }
if ( hSubKey != NULL ) { RegCloseKey( hSubKey ); }
if ( hKey != NULL ) { RegCloseKey( hKey ); }
if ( lpszCmdLine != NULL ) { LocalFree( lpszCmdLine ); }
if ( lpszCmdLine2 != NULL ) LocalFree( lpszCmdLine2 );
AdvWriteToLog("InstallOCX: End %1\r\n", pRegOCX->pszOCX); return fSuccess; }
//***************************************************************************
//
// FormStrWithoutPlaceHolders( LPSTR szDst, LPCSTR szSrc, LPCSTR lpFile );
//
// This function can be easily described by giving examples of what it
// does:
// Input: GenFormStrWithoutPlaceHolders(dest,"desc=%MS_XYZ%", hinf) ;
// INF file has MS_VGA="Microsoft XYZ" in its [Strings] section!
//
// Output: "desc=Microsoft XYZ" in buffer dest when done.
//
//
// ENTRY:
// szDst - the destination where the string after the substitutions
// for the place holders (the ones enclosed in "%' chars!)
// is placed. This buffer should be big enough (LINE_LEN)
// szSrc - the string with the place holders.
//
// EXIT:
//
//***************************************************************************
DWORD FormStrWithoutPlaceHolders( LPCSTR szSrc, LPSTR szDst, DWORD dwDstSize, LPCSTR szInfFilename ) { INT uCnt ; CHAR *pszTmp; LPSTR pszSaveDst;
pszSaveDst = szDst;
// Do until we reach the end of source (null char)
while( ( *szDst++ = *szSrc ) ) { // Increment source as we have only incremented destination above
if( *szSrc++ == '%' ) { if ( *szSrc == '%' ) { // One can use %% to get a single percentage char in message
szSrc++; continue; }
// see if it is well formed -- there should be a '%' delimiter
pszTmp = (LPSTR) szSrc; while ( (*pszTmp != '\0') && (*pszTmp != '%') ) { pszTmp += 1; }
if ( *pszTmp == '%' ) { szDst--; // get back to the '%' char to replace
// yes, there is a STR_KEY to be looked for in [Strings] sect.
*pszTmp = '\0' ; // replace '%' with a NULL char
// szSrc points to the replaceable key now as we put the NULL char above.
if ( ! MyGetPrivateProfileString( szInfFilename, "Strings", szSrc, szDst, dwDstSize - (DWORD)(szDst - pszSaveDst) ) ) { // key is missing in [Strings] section!
return (DWORD) -1; } else { // all was well, Dst filled right, but unfortunately count not passed
// back, like it used too... :-( quick fix is a lstrlen()...
uCnt = lstrlen( szDst ) ; }
*pszTmp = '%'; // put back original character
szSrc = pszTmp + 1 ; // set Src after the second '%'
szDst += uCnt ; // set Dst also right.
} // else it is ill-formed -- we use the '%' as such!
else { return (DWORD)-1; } }
} /* while */ return (DWORD)lstrlen(pszSaveDst);
}
// BUGBUG:BUGBUG:BUGBUG:BUGBUG
// The code below is duplicated in wextract.exe. If you do changed/fixes to this code
// make sure to also change the code in wextract.exe
//***************************************************************************
//* *
//* NAME: GetWininitSize *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// Returns the size of wininit.ini in the windows directory.
// 0 if not found
DWORD GetWininitSize() { CHAR szPath[MAX_PATH]; HFILE hFile; DWORD dwSize = (DWORD)0; if ( GetWindowsDirectory( szPath, MAX_PATH ) ) { AddPath( szPath, "wininit.ini" ); if ((hFile = _lopen(szPath, OF_READ|OF_SHARE_DENY_NONE)) != HFILE_ERROR) { dwSize = _llseek(hFile, 0L, FILE_END); _lclose(hFile); } } return dwSize; }
//***************************************************************************
//* *
//* NAME: GetRegValueSize *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// 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; }
//***************************************************************************
//* *
//* NAME: GetNumberOfValues *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// 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; }
//***************************************************************************
//* *
//* NAME: InternalNeedRebootInit *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// Returns the rebootcheck value depending on the OS we get passed in.
DWORD InternalNeedRebootInit(WORD wOSVer) { DWORD dwReturn = (DWORD)0;
switch (wOSVer) { case _OSVER_WIN95: dwReturn = GetWininitSize(); break;
case _OSVER_WINNT40: case _OSVER_WINNT50: case _OSVER_WINNT51: dwReturn = GetRegValueSize(szNT4XDelayUntilReboot, szNT4XPendingValue); break;
case _OSVER_WINNT3X: dwReturn = GetNumberOfValues(szNT3XDelayUntilReboot); break;
} return dwReturn; }
//***************************************************************************
//* *
//* NAME: InternalNeedReboot *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// 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 InternalNeedReboot(DWORD dwRebootCheck, WORD wOSVer) { return (dwRebootCheck != InternalNeedRebootInit(wOSVer)); }
//***************************************************************************
//* *
//* NAME: IsEnoughInstSpace *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// Checks the install destination dir free disk space
//
BOOL IsEnoughInstSpace( LPSTR szPath, DWORD dwInstNeedSize, LPDWORD pdwPadSize ) { DWORD dwFreeBytes = 0; CHAR achDrive[MAX_PATH]; DWORD dwVolFlags; DWORD dwMaxCompLen;
ASSERT( szPath );
// set to zero to indicate to called that the given drive can not be checked.
if ( pdwPadSize ) *pdwPadSize = 0;
// If you are here, we expect that the caller have validated the path which
// has the Fullpath directory name
//
if ( dwInstNeedSize == 0 ) return TRUE;
if ( szPath[1] == ':' ) { lstrcpyn( achDrive, szPath, 4 ); } else if ( (szPath[0] == '\\') && (szPath[1] == '\\') ) { return TRUE; //no way to get it
} else return FALSE; // you should not get here, if so, we don't know how to check it.
if ((dwFreeBytes=GetSpace(achDrive))==0) { ErrorMsg1Param( NULL, IDS_ERR_GET_DISKSPACE, achDrive ); //SetCurrentDirectory( achOldPath );
return( FALSE ); }
// find out if the drive is compressed
if ( !GetVolumeInformation( achDrive, NULL, 0, NULL, &dwMaxCompLen, &dwVolFlags, NULL, 0 ) ) { ErrorMsg1Param( NULL, IDS_ERR_GETVOLINFOR, achDrive ); //SetCurrentDirectory( achOldPath );
return( FALSE ); }
if ( pdwPadSize ) *pdwPadSize = dwInstNeedSize;
if ( (dwVolFlags & FS_VOL_IS_COMPRESSED) && ctx.bCompressed ) { dwInstNeedSize = dwInstNeedSize + dwInstNeedSize/4; if ( pdwPadSize ) *pdwPadSize = dwInstNeedSize; }
if ( dwInstNeedSize > dwFreeBytes ) return FALSE; else return TRUE; }
//***************************************************************************
//* *
//* NAME: My_atol *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
LONG My_atol( LPSTR nptr ) { INT c; LONG total; INT sign;
while ( *nptr == ' ' || *nptr == '\t' ) { ++nptr; }
c = (INT)(UCHAR) *nptr++; sign = c; if ( c == '-' || c == '+' ) { c = (INT)(UCHAR) *nptr++; }
total = 0;
while ( c >= '0' && c <= '9' ) { total = 10 * total + (c - '0'); c = (INT)(UCHAR) *nptr++; }
if ( sign == '-' ) { return -total; } else { return total; } }
//***************************************************************************
//* *
//* NAME: My_atoi *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
INT My_atoi( LPSTR nptr ) { return (INT) My_atol(nptr); }
//***************************************************************************
//* *
//* NAME: IsFullPath *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
// return TRUE if given path is FULL pathname
//
BOOL IsFullPath( PCSTR pszPath ) { if ( (pszPath == NULL) || (lstrlen(pszPath) < 3) ) { return FALSE; }
if ( (pszPath[1] == ':') || ((pszPath[0] == '\\') && (pszPath[1]=='\\') ) ) return TRUE; else return FALSE; }
//***************************************************************************
//* *
//* NAME: GetUNCroot *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
/*
BOOL GetUNCroot( LPSTR pszinPath, LPSTR pszoutPath ) { ASSERT(pszinPath); ASSERT(pszoutPath);
// if you are called, called is sure that you are UNC path
// get \\ first
*pszoutPath++ = *pszinPath++; *pszoutPath++ = *pszinPath++;
if ( *pszinPath == '\\' ) { return FALSE; // catch '\\\' case
}
while ( *pszinPath != '\0' ) { if ( *pszinPath == '\\' ) { break; } *pszoutPath++ = *pszinPath++; }
if ( *(pszinPath-1) == '\\' ) { return FALSE; }
*pszoutPath = '\0'; return TRUE; } */
//***************************************************************************
//* *
//* NAME: MyFileSize *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
DWORD MyFileSize( PCSTR pszFile ) { HANDLE hFile; DWORD dwSize = 0;
if ( *pszFile == 0 ) return 0;
hFile = CreateFile( pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (hFile != INVALID_HANDLE_VALUE) { dwSize = GetFileSize( hFile, NULL ); CloseHandle( hFile ); }
return dwSize; }
//***************************************************************************
//* *
//* NAME: CreateFullPath *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT CreateFullPath( PCSTR c_pszPath, BOOL bHiden ) { CHAR szPath[MAX_PATH]; PSTR pszPoint = NULL; BOOL fLastDir = FALSE; HRESULT hReturnCode = S_OK; LPSTR szTmp; int i;
if ( ! IsFullPath( (PSTR)c_pszPath ) ) { hReturnCode = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME); goto done; }
lstrcpy( szPath, c_pszPath );
if ( lstrlen(szPath) > 3 ) { szTmp = CharPrev(szPath, szPath + lstrlen(szPath)) ; if ( szTmp > szPath && *szTmp == '\\' ) *szTmp = '\0'; }
// If it's a UNC path, seek up to the first share name.
if ( szPath[0] == '\\' && szPath[1] == '\\' ) { pszPoint = &szPath[2]; for (i=0; i < 2; i++) { while ( *pszPoint != '\\' ) { if ( *pszPoint == '\0' ) {
// Share name missing? Else, nothing after sare name!
if (i == 0) hReturnCode = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
goto done; } pszPoint = CharNext( pszPoint ); } } pszPoint = CharNext( pszPoint ); } else { // Otherwise, just point to the beginning of the first directory
pszPoint = &szPath[3]; }
while ( *pszPoint != '\0' ) { while ( *pszPoint != '\\' && *pszPoint != '\0' ) { pszPoint = CharNext( pszPoint ); }
if ( *pszPoint == '\0' ) { fLastDir = TRUE; }
*pszPoint = '\0';
if ( GetFileAttributes( szPath ) == 0xFFFFFFFF ) { if ( ! CreateDirectory( szPath, NULL ) ) { hReturnCode = HRESULT_FROM_WIN32(GetLastError()); break; } else { if ( fLastDir && bHiden ) SetFileAttributes( szPath, FILE_ATTRIBUTE_HIDDEN ); } } if ( fLastDir ) { break; }
*pszPoint = '\\'; pszPoint = CharNext( pszPoint ); }
done:
return hReturnCode; }
//***************************************************************************
//* *
//* NAME: LaunchAndWait *
//* *
//* SYNOPSIS: *
//* *
//* REQUIRES: *
//* *
//* RETURNS: *
//* *
//***************************************************************************
HRESULT LaunchAndWait(LPSTR pszCmd, LPSTR pszDir, HANDLE *phProc, DWORD dwWaitTime, DWORD dwCmdsFlags) { STARTUPINFO startInfo = { 0 }; PROCESS_INFORMATION processInfo; HRESULT hr = S_OK; BOOL fRet;
if(phProc) *phProc = NULL;
AdvWriteToLog("LaunchAndWait: Cmd=%1\r\n", pszCmd); // Create process on pszCmd
startInfo.cb = sizeof(startInfo); startInfo.dwFlags |= STARTF_USESHOWWINDOW; if ( dwCmdsFlags & RUNCMDS_QUIET ) startInfo.wShowWindow = SW_HIDE; else startInfo.wShowWindow = SW_SHOWNORMAL ;
fRet = CreateProcess(NULL, pszCmd, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, pszDir, &startInfo, &processInfo);
if(!fRet) { // Create Process failed
hr = E_FAIL; goto done; } else { HANDLE pHandle; BOOL fQuit = FALSE; DWORD dwRet;
CloseHandle( processInfo.hThread );
pHandle = processInfo.hProcess;
if( phProc ) { *phProc = processInfo.hProcess; goto done; } else if ( dwCmdsFlags & RUNCMDS_NOWAIT ) { goto done; }
while(!fQuit) { dwRet = MsgWaitForMultipleObjects(1, &pHandle, FALSE, dwWaitTime, QS_ALLINPUT); // Give abort the highest priority
if( (dwRet == WAIT_OBJECT_0) || ( dwRet == WAIT_TIMEOUT) ) { if (dwRet == WAIT_TIMEOUT) AdvWriteToLog("LaunchAndWait: %1: TimedOut.\r\n", pszCmd); fQuit = 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) fQuit = TRUE; else { // otherwise dispatch it
DispatchMessage(&msg); } // end of PeekMessage while loop
} } } CloseHandle( pHandle ); }
done: AdvWriteToLog("LaunchAndWait: End hr=0x%1!x!, %2\r\n", hr, pszCmd); return hr; }
// RO_GetPrivateProfileSection
// ensure the file attribute is not read-only because the kernel api bug
//
DWORD RO_GetPrivateProfileSection( LPCSTR lpSec, LPSTR lpBuf, DWORD dwSize, LPCSTR lpFile) { DWORD dwRealSize; DWORD dwAttr; BOOL bHaveRead = FALSE;
dwAttr = GetFileAttributes( lpFile ); if ( (dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY) ) { if ( !SetFileAttributes( lpFile, FILE_ATTRIBUTE_NORMAL ) ) { char szInfFilePath[MAX_PATH]; char szInfFileName[MAX_PATH];
// ErrorMsg1Param( NULL, IDS_ERR_CANT_SETA_FILE, lpFile );
if ( GetTempPath(sizeof(szInfFilePath), szInfFilePath) ) { if ( !IsGoodDir( szInfFilePath ) ) { GetWindowsDirectory( szInfFilePath, sizeof(szInfFilePath) ); }
if ( GetTempFileName(szInfFilePath, TEXT("INF"), 0, szInfFileName) ) { SetFileAttributes( szInfFileName, FILE_ATTRIBUTE_NORMAL ); DeleteFile( szInfFileName ); CopyFile( lpFile, szInfFileName, FALSE ); SetFileAttributes( szInfFileName, FILE_ATTRIBUTE_NORMAL ); dwRealSize = GetPrivateProfileSection( lpSec, lpBuf, dwSize, szInfFileName ); bHaveRead = TRUE; DeleteFile( szInfFileName ); } }
//if ( !bHaveRead )
//ErrorMsg1Param( NULL, IDS_ERR_CANT_SETA_FILE, lpFile );
} }
if ( !bHaveRead ) dwRealSize = GetPrivateProfileSection( lpSec, lpBuf, dwSize, lpFile );
if ( (dwAttr != -1) && (dwAttr & FILE_ATTRIBUTE_READONLY) ) { SetFileAttributes( lpFile, dwAttr ); }
return dwRealSize;
}
BOOL GetThisModulePath( LPSTR lpPath, int size ) { LPSTR lpTmp;
ASSERT(lpPath);
if ( GetModuleFileName( g_hInst, lpPath, size ) ) {
lpTmp = CharPrev( lpPath, lpPath+lstrlen(lpPath));
// chop filename off
//
while ( (lpTmp > lpPath) && *lpTmp && (*lpTmp != '\\') ) lpTmp = CharPrev( lpPath, lpTmp );
if ( *CharPrev( lpPath, lpTmp ) != ':' ) *lpTmp = '\0'; else *CharNext( lpTmp ) = '\0'; return TRUE; }
return FALSE; }
HINSTANCE MyLoadLibrary( LPSTR lpFile ) { CHAR szPath[MAX_PATH]; HINSTANCE hInst = NULL; DWORD dwAttr;
ASSERT( lpFile );
if ( GetThisModulePath( szPath, sizeof(szPath) ) ) { AddPath( szPath, lpFile ); if ( ((dwAttr = GetFileAttributes(szPath)) != -1) && !( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) ) { hInst = LoadLibraryEx( szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); } }
// If we did not load the DLL yet, try plain LoadLibrary
if (hInst == NULL) hInst = LoadLibrary( lpFile );
return hInst; }
// typedef into advpack.h file
//typedef struct tagVERHEAD {
// WORD wTotLen;
// WORD wValLen;
// WORD wType; /* always 0 */
// WCHAR szKey[(sizeof("VS_VERSION_INFO")+3)&~03];
// VS_FIXEDFILEINFO vsf;
//} VERHEAD ;
/*
* MyGetFileVersionInfo: Maps a file directly without using LoadLibrary. This ensures * that the right version of the file is examined without regard to where the loaded image * is. Since this is local, it allocates the memory which is freed by the caller. */ BOOL NTGetFileVersionInfo(LPTSTR lpszFilename, LPVOID *lpVersionInfo) { VS_FIXEDFILEINFO *pvsFFI = NULL; UINT uiBytes = 0; HINSTANCE hinst; HRSRC hVerRes; HANDLE FileHandle = NULL; HANDLE MappingHandle = NULL; LPVOID DllBase = NULL; VERHEAD *pVerHead; BOOL bResult = FALSE; DWORD dwHandle; DWORD dwLength;
if (!lpVersionInfo) return FALSE;
*lpVersionInfo = NULL;
FileHandle = CreateFile( lpszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (FileHandle == INVALID_HANDLE_VALUE) goto Cleanup;
MappingHandle = CreateFileMapping( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL );
if (MappingHandle == NULL) goto Cleanup;
DllBase = MapViewOfFileEx( MappingHandle, FILE_MAP_READ, 0, 0, 0, NULL ); if (DllBase == NULL) goto Cleanup;
hinst = (HMODULE)((ULONG_PTR)DllBase | 0x00000001);
hVerRes = FindResource(hinst, MAKEINTRESOURCE(VS_VERSION_INFO), VS_FILE_INFO); if (hVerRes == NULL) { // Probably a 16-bit file. Fall back to system APIs.
if(!(dwLength = GetFileVersionInfoSize(lpszFilename, &dwHandle))) { if(!GetLastError()) SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); goto Cleanup; }
if(!(*lpVersionInfo = LocalAlloc(LPTR, dwLength))) goto Cleanup;
if(!GetFileVersionInfo(lpszFilename, 0, dwLength, *lpVersionInfo)) goto Cleanup;
bResult = TRUE; goto Cleanup; }
pVerHead = (VERHEAD*)LoadResource(hinst, hVerRes); if (pVerHead == NULL) goto Cleanup;
*lpVersionInfo = LocalAlloc(LPTR, pVerHead->wTotLen + pVerHead->wTotLen/2); if (*lpVersionInfo == NULL) goto Cleanup;
memcpy(*lpVersionInfo, (PVOID)pVerHead, pVerHead->wTotLen); bResult = TRUE;
Cleanup: if (FileHandle) CloseHandle(FileHandle); if (MappingHandle) CloseHandle(MappingHandle); if (DllBase) UnmapViewOfFile(DllBase); if (*lpVersionInfo && bResult == FALSE) LocalFree(*lpVersionInfo);
return bResult; }
// this API will always get the version of the disk file
HRESULT WINAPI GetVersionFromFileEx(LPSTR lpszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer, BOOL bVersion) { unsigned uiSize; DWORD dwVerInfoSize; DWORD dwHandle; VS_FIXEDFILEINFO * lpVSFixedFileInfo; void FAR *lpBuffer = NULL; LPVOID lpVerBuffer; CHAR szNewName[MAX_PATH]; BOOL bToCleanup = FALSE; BOOL bContinue = FALSE;
*pdwMSVer = *pdwLSVer = 0L;
bContinue = NTGetFileVersionInfo(lpszFilename, &lpBuffer);
if ( bContinue ) { if (bVersion) { // Get the value for Translation
if (VerQueryValue(lpBuffer, "\\", (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize))
{ *pdwMSVer = lpVSFixedFileInfo->dwFileVersionMS; *pdwLSVer = lpVSFixedFileInfo->dwFileVersionLS; } } else { if (VerQueryValue(lpBuffer, "\\VarFileInfo\\Translation", &lpVerBuffer, &uiSize) && (uiSize)) { *pdwMSVer = LOWORD(*((DWORD *) lpVerBuffer)); // Language ID
*pdwLSVer = HIWORD(*((DWORD *) lpVerBuffer)); // Codepage ID
} } }
if ( bToCleanup ) DeleteFile( szNewName ); if ( lpBuffer ) LocalFree( lpBuffer ); return S_OK; }
//this api will get the version of the file being loaded
HRESULT WINAPI GetVersionFromFile(LPSTR lpszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer, BOOL bVersion) { unsigned uiSize; DWORD dwVerInfoSize; DWORD dwHandle; VS_FIXEDFILEINFO * lpVSFixedFileInfo; void FAR *lpBuffer; LPVOID lpVerBuffer; CHAR szNewName[MAX_PATH]; BOOL bToCleanup = FALSE;
*pdwMSVer = *pdwLSVer = 0L;
dwVerInfoSize = GetFileVersionInfoSize(lpszFilename, &dwHandle); lstrcpy( szNewName, lpszFilename ); if ( (dwVerInfoSize == 0) && FileExists( szNewName ) ) { CHAR szPath[MAX_PATH]; // due to version.dll bug, file in extended character path will failed version.dll apis.
// So we copy it to a normal path and get its version info from there then clean it up.
GetWindowsDirectory( szPath, sizeof(szPath) ); GetTempFileName( szPath, "_&_", 0, szNewName ); CopyFile( lpszFilename, szNewName, FALSE ); bToCleanup = TRUE; dwVerInfoSize = GetFileVersionInfoSize( szNewName, &dwHandle ); }
if (dwVerInfoSize) { // Alloc the memory for the version stamping
lpBuffer = LocalAlloc(LPTR, dwVerInfoSize); if (lpBuffer) { // Read version stamping info
if (GetFileVersionInfo(szNewName, dwHandle, dwVerInfoSize, lpBuffer)) { if (bVersion) { // Get the value for Translation
if (VerQueryValue(lpBuffer, "\\", (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize))
{ *pdwMSVer = lpVSFixedFileInfo->dwFileVersionMS; *pdwLSVer = lpVSFixedFileInfo->dwFileVersionLS; } } else { if (VerQueryValue(lpBuffer, "\\VarFileInfo\\Translation", &lpVerBuffer, &uiSize) && (uiSize)) { *pdwMSVer = LOWORD(*((DWORD *) lpVerBuffer)); // Language ID
*pdwLSVer = HIWORD(*((DWORD *) lpVerBuffer)); // Codepage ID
} } } LocalFree(lpBuffer); } }
if ( bToCleanup ) DeleteFile( szNewName ); return S_OK; }
#define WININIT_INI "wininit.ini"
// when the files is busy, adding them to wininit.ini
//
BOOL AddWinInit( LPSTR from, LPSTR to) { LPSTR lpWininit; BOOL bRet = FALSE;
if ( ctx.wOSVer == _OSVER_WIN95 ) { lpWininit = (LPSTR) LocalAlloc( LPTR, MAX_PATH ); if ( !lpWininit ) { ErrorMsg( NULL, IDS_ERR_NO_MEMORY ); return FALSE; }
GetWindowsDirectory( lpWininit, MAX_PATH); AddPath( lpWininit, WININIT_INI);
WritePrivateProfileString( NULL, NULL, NULL, lpWininit );
if ( WritePrivateProfileString( "Rename", to, from, lpWininit ) ) bRet = TRUE;
WritePrivateProfileString( NULL, NULL, NULL, lpWininit );
LocalFree( lpWininit ); } else { bRet = MoveFileEx(from, to, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING); } return bRet; }
void GetBackupName( LPSTR lpName, BOOL fOld ) { LPSTR pTmp; LPSTR pExt;
#define BACK_OLD ".~ol"
#define BACK_NEW ".~nw"
if ( fOld ) pExt = BACK_OLD; else pExt = BACK_NEW;
pTmp = CharPrev( lpName, lpName + lstrlen(lpName) );
while ( (pTmp>lpName) && *pTmp && (*pTmp != '\\') && (*pTmp != '.') ) { pTmp = CharPrev( lpName, pTmp ); } if ( (pTmp==lpName) || (*pTmp == '\\') ) { lstrcat( lpName, pExt ); } else { lstrcpy( pTmp, pExt ); }
}
BOOL UpdateHelpDlls( LPCSTR *ppszDlls, INT numDlls, LPSTR pszPath, LPSTR pszMsg, DWORD dwFlag) { DWORD dwSysMsV, dwSysLsV, dwTmpMsV, dwTmpLsV; int i = 0; LPSTR pSysEnd; LPSTR pTmpEnd; CHAR szTmpPath[MAX_PATH] = { 0 }; CHAR szSystemPath[MAX_PATH] = { 0 }; CHAR szBuf[MAX_PATH]; BOOL fCopySucc = TRUE; BOOL bRet = TRUE; BOOL fBackup[3] = {0}; BOOL bAlertReboot = FALSE;
// This function is used to update all the help Dlls: advpack, setupapi or setupx
// based on passed in ppDlls
// if not path passed in, get the module path (tmp path)
if (pszPath==NULL) { if (!GetThisModulePath( szTmpPath, sizeof(szTmpPath) ) ) { DEBUGMSG("Can not get ModuleFileName directory"); return FALSE; } } else lstrcpy( szTmpPath, pszPath);
pTmpEnd = szTmpPath + lstrlen(szTmpPath);
// check if the newer or equal version files exist
if ( !GetSystemDirectory( szSystemPath, sizeof(szSystemPath) ) ) { DEBUGMSG("Can not get system directory"); return FALSE; } pSysEnd = szSystemPath + lstrlen(szSystemPath);
// check if the.dll need to be updated
//
for ( i = 0; i < numDlls; i += 1 ) { // restore the systemPath and ModulePath
*pTmpEnd = '\0'; *pSysEnd = '\0';
AddPath( szTmpPath, ppszDlls[i] );
if ( GetFileAttributes( szTmpPath ) == -1 ) { continue; } GetVersionFromFile( szTmpPath, &dwTmpMsV, &dwTmpLsV, TRUE );
AddPath( szSystemPath, ppszDlls[i] ); if ( GetFileAttributes( szSystemPath ) != -1 ) { GetVersionFromFile( szSystemPath, &dwSysMsV, &dwSysLsV, TRUE );
// compare if we need to copy those files
//
if ( (dwSysMsV > dwTmpMsV) || ((dwSysMsV == dwTmpMsV) && (dwSysLsV >= dwTmpLsV)) ) { continue; } SetFileAttributes( szSystemPath, FILE_ATTRIBUTE_NORMAL );
//backup the original files first
lstrcpy( szBuf, szSystemPath ); GetBackupName( szBuf, TRUE ); SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL ); DeleteFile( szBuf ); if ( MoveFile( szSystemPath, szBuf ) ) { fBackup[i] = TRUE; } }
if ( !CopyFile( szTmpPath, szSystemPath, FALSE ) ) { //if forced to update
if ( dwFlag & UPDHLPDLLS_FORCED ) { // copy to a basename.000 format
lstrcpy( szBuf, szSystemPath ); // get the temp name in destination dir to copy to
GetBackupName( szBuf, FALSE ); SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL ); if ( CopyFile( szTmpPath, szBuf, FALSE ) ) { if ( AddWinInit( szBuf, szSystemPath ) ) { if (dwFlag & UPDHLPDLLS_ALERTREBOOT) bAlertReboot = TRUE; continue; } else bRet = FALSE; } else { wsprintf( szBuf, "Cannot create TMP file for %s Dll.", pszMsg ); DEBUGMSG(szBuf); bRet = FALSE; } }
// you are here, means the current CopyFile/delay-CopyFile failed.
// restore the original state, clean-up backup file if there.
//
while ( i >= 0 ) { if ( fBackup[i] ) { *pSysEnd = '\0'; AddPath( szSystemPath, ppszDlls[i] ); lstrcpy( szBuf, szSystemPath ); GetBackupName( szBuf, TRUE ); SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL ); DeleteFile( szSystemPath ); if( !MoveFile( szBuf, szSystemPath ) ) { wsprintf(szBuf, "Cannot restore %s dlls.", pszMsg); DEBUGMSG(szBuf); } } i--; }
fCopySucc = FALSE; break; } }
// clean up .~ol files
if ( fCopySucc ) { for ( i=0; i<numDlls; i++) { if ( fBackup[i] ) { *pSysEnd = '\0'; AddPath( szSystemPath, ppszDlls[i]); lstrcpy( szBuf, szSystemPath ); GetBackupName( szBuf, TRUE ); SetFileAttributes( szBuf, FILE_ATTRIBUTE_NORMAL ); DeleteFile( szBuf ); } }
// if caller want ot alert reboot, means that they want to get false return if the dlls is not
// in place now.
if (bAlertReboot) bRet = FALSE; } return bRet; }
void MyRemoveDirectory( LPSTR szFolder ) { while ( RemoveDirectory( szFolder ) ) { GetParentDir( szFolder ); } }
BOOL IsDrvChecked( char chDrv ) { static char szDrvChecked[MAX_NUM_DRIVES] = { 0 }; int idx;
idx = (CHAR)CharUpper( (PSTR)chDrv ) - 'A';
if ( szDrvChecked[idx] ) return TRUE; else szDrvChecked[idx] = chDrv;
return FALSE; }
/////////////////////////////////////////////////////////////////////////////
// ENTRY POINT: DelNode
//
// SYNOPSIS: Deletes a file or directory
//
// RETURNS:
// S_OK success
// E_FAIL failure
/////////////////////////////////////////////////////////////////////////////
#define ADN_NO_SAFETY_CHECKS 0x40000000 // undocumented flag
HRESULT WINAPI DelNode(LPCSTR pszFileOrDirName, DWORD dwFlags) { HRESULT hResult = S_OK;
// we won't handle relative paths and UNC's(unless flag specified)
// BUGBUG: <oliverl> we're not checking for UNC server here
if (!IsFullPath(pszFileOrDirName) || (pszFileOrDirName[0] == '\\' && pszFileOrDirName[1] == '\\' && !(dwFlags & ADN_DEL_UNC_PATHS))) return E_FAIL;
if (!(GetFileAttributes(pszFileOrDirName) & FILE_ATTRIBUTE_DIRECTORY)) // file
{ SetFileAttributes(pszFileOrDirName, FILE_ATTRIBUTE_NORMAL); if (!DeleteFile(pszFileOrDirName)) hResult = E_FAIL; } else if (dwFlags & ADN_DEL_IF_EMPTY) // delete the dir only if it's empty
{ SetFileAttributes(pszFileOrDirName, FILE_ATTRIBUTE_NORMAL); if (!RemoveDirectory(pszFileOrDirName)) hResult = E_FAIL; } else // delete the node
{ char szFile[MAX_PATH], *pszPtr; WIN32_FIND_DATA fileData; HANDLE hFindFile;
if (!(dwFlags & ADN_NO_SAFETY_CHECKS)) { // if pszFileOrDirName is the root dir or windows dir or system dir or
// Program Files dir, return E_FAIL; this is just a safety precaution
hResult = DirSafe(pszFileOrDirName); }
if (SUCCEEDED(hResult)) { lstrcpy(szFile, pszFileOrDirName); AddPath(szFile, ""); pszPtr = szFile + lstrlen(szFile); // save this position
lstrcpy(pszPtr, "*");
if ((hFindFile = FindFirstFile(szFile, &fileData)) != INVALID_HANDLE_VALUE) { do { // skip "." and ".."; if ADN_DONT_DEL_SUBDIRS is specified, skip all sub-dirs
if ((fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (lstrcmp(fileData.cFileName, ".") == 0 || lstrcmp(fileData.cFileName, "..") == 0 || (dwFlags & ADN_DONT_DEL_SUBDIRS))) continue;
lstrcpy(pszPtr, fileData.cFileName);
// we need to pass along the ADN_DEL_UNC_PATHS flag, but all other flags
// are only for the top level node
if (dwFlags & ADN_DEL_UNC_PATHS) hResult = DelNode(szFile, ADN_DEL_UNC_PATHS); else hResult = DelNode(szFile, 0); // delete the file or sub-dir
} while (SUCCEEDED(hResult) && FindNextFile(hFindFile, &fileData));
FindClose(hFindFile);
if (SUCCEEDED(hResult) && !(dwFlags & ADN_DONT_DEL_DIR)) { // delete the dir; if DelNode fails, it's an error condition if ADN_DONT_DEL_SUBDIRS is not specified
if (dwFlags & ADN_DEL_UNC_PATHS) { if (FAILED(DelNode(pszFileOrDirName, ADN_DEL_IF_EMPTY | ADN_DEL_UNC_PATHS)) && !(dwFlags & ADN_DONT_DEL_SUBDIRS)) hResult = E_FAIL; } else { if (FAILED(DelNode(pszFileOrDirName, ADN_DEL_IF_EMPTY)) && !(dwFlags & ADN_DONT_DEL_SUBDIRS)) hResult = E_FAIL; }
} } else hResult = E_FAIL; } }
return hResult; }
/////////////////////////////////////////////////////////////////////////////
// ENTRY POINT: DelNodeRunDLL32
//
// SYNOPSIS: Deletes a file or directory; the parameters to this API are of
// WinMain type
//
// RETURNS:
// S_OK success
// E_FAIL failure
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI DelNodeRunDLL32(HWND hwnd, HINSTANCE hInstance, PSTR pszParms, INT nShow) { PSTR pszFileOrDirName = GetStringField(&pszParms, ",", '\"', TRUE); PSTR pszFlags = GetStringField(&pszParms, ",", '\"', TRUE);
return DelNode(pszFileOrDirName, (pszFlags != NULL) ? My_atol(pszFlags) : 0); }
HRESULT DirSafe(LPCSTR pszDir) // If pszDir is the root drive of windows dir or windows dir or system dir or
// Program Files dir, return E_FAIL; otherwise, return S_OK
{ char szUnsafeDir[MAX_PATH], szDir[MAX_PATH];
lstrcpy(szDir, pszDir); AddPath(szDir, "");
*szUnsafeDir = '\0'; GetWindowsDirectory(szUnsafeDir, sizeof(szUnsafeDir)); AddPath(szUnsafeDir, "");
if (lstrcmpi(szDir, szUnsafeDir) == 0) // windows dir
return E_FAIL; else { szUnsafeDir[3] = '\0';
if (lstrcmpi(szDir, szUnsafeDir) == 0) // root drive of windows dir
return E_FAIL; else { *szUnsafeDir = '\0'; GetSystemDirectory(szUnsafeDir, sizeof(szUnsafeDir)); AddPath(szUnsafeDir, "");
if (lstrcmpi(szDir, szUnsafeDir) == 0) // system dir
return E_FAIL; else { *szUnsafeDir = '\0'; GetProgramFilesDir(szUnsafeDir, sizeof(szUnsafeDir)); AddPath(szUnsafeDir, "");
if (lstrcmpi(szDir, szUnsafeDir) == 0) // program files dir
return E_FAIL; else { // check for the short pathname of the program files dir
GetShortPathName(szUnsafeDir, szUnsafeDir, sizeof(szUnsafeDir)); AddPath(szUnsafeDir, "");
if (lstrcmpi(szDir, szUnsafeDir) == 0) // short pathname of program files dir
return E_FAIL; } } } }
return S_OK; }
void SetControlFont() { LOGFONT lFont; if (GetSystemMetrics(SM_DBCSENABLED) && (GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof (lFont), &lFont) > 0)) { g_hFont = CreateFontIndirect((LPLOGFONT)&lFont); } }
void SetFontForControl(HWND hwnd, UINT uiID) { if (g_hFont) { SendDlgItemMessage(hwnd, uiID, WM_SETFONT, (WPARAM)g_hFont ,0L); } }
void MyGetPlatformSection(LPCSTR lpSec, LPCSTR lpInfFile, LPSTR szNewSection) { OSVERSIONINFO VerInfo; SYSTEM_INFO SystemInfo; char szSection[MAX_PATH]; DWORD dwReqSize = 0;
lstrcpy(szSection, lpSec); lstrcpy(szNewSection, lpSec); VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&VerInfo); if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { GetSystemInfo( &SystemInfo ); switch (SystemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: lstrcat( szSection, ".NTx86" ); break;
case PROCESSOR_ARCHITECTURE_AMD64: lstrcat( szSection, ".NTAmd64" ); break; case PROCESSOR_ARCHITECTURE_IA64: lstrcat( szSection, ".NTIa64" ); break;
default: DEBUGMSG("MyGetPlatformSection - need to deal w/ new PROCESS_ARCHITECTURE type!!"); ASSERT(FALSE); break; }
if (SUCCEEDED(GetTranslatedLine(lpInfFile, szSection, 0, NULL, &dwReqSize )) && (dwReqSize!=0)) { lstrcpy(szNewSection, szSection); } else { lstrcpy(szSection, lpSec); lstrcat(szSection, ".NT"); if (SUCCEEDED(GetTranslatedLine(lpInfFile, szSection, 0, NULL, &dwReqSize )) && (dwReqSize!=0)) lstrcpy(szNewSection, szSection); } } else { lstrcat(szSection, ".WIN"); if (SUCCEEDED(GetTranslatedLine(lpInfFile, szSection, 0, NULL, &dwReqSize )) && (dwReqSize!=0)) lstrcpy(szNewSection, szSection); } }
typedef HRESULT (WINAPI *PFProcessDownloadSection)(HINF, HWND, BOOL, LPCSTR, LPCSTR, LPVOID);
HRESULT RunPatchingCommands(PCSTR c_pszInfFilename, PCSTR szInstallSection, PCSTR c_pszSourceDir) { CHAR szBuf[512]; CHAR szDllName[MAX_PATH]; HRESULT hResult = S_OK; INFCONTEXT InfContext; static const CHAR c_szPatching[] = "Patching"; static const CHAR c_szAdvpackExt[] = "LoadAdvpackExtension";
//Check if patching is enabled for this section
if(!GetTranslatedInt(c_pszInfFilename, szInstallSection, c_szPatching, 0)) { goto done; }
//Read the dllname and entry point from LoadAdvpackExtension= line
if(FAILED(GetTranslatedString(c_pszInfFilename, szInstallSection, c_szAdvpackExt, szBuf, sizeof(szBuf), NULL))) { goto done; }
//Got the extension dll
if(GetFieldString(szBuf, 0, szDllName, sizeof(szDllName))) { CHAR szEntryPoint[MAX_PATH]; HINSTANCE hInst = LoadLibrary(szDllName); if(!hInst) { hResult = HRESULT_FROM_WIN32(GetLastError()); goto done; }
if(GetFieldString(szBuf, 1, szEntryPoint, sizeof(szEntryPoint))) { PFProcessDownloadSection pfn = (PFProcessDownloadSection)GetProcAddress(hInst, szEntryPoint); if(!pfn) { hResult = HRESULT_FROM_WIN32(GetLastError()); goto done; }
hResult = pfn(ctx.hInf, ctx.hWnd, ctx.wQuietMode, szInstallSection, c_pszSourceDir, NULL); }
FreeLibrary(hInst);
}
done:
return hResult;
}
|