//*************************************************************************** //* Copyright (c) Microsoft Corporation 1995-1996. All rights reserved. * //*************************************************************************** //* * //* ADVPACK.C - Advanced helper-dll for WExtract. * //* * //*************************************************************************** //*************************************************************************** //* INCLUDE FILES * //*************************************************************************** #include #include #include #include #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 [.NTx86] present, this section get GenInstall, exit. //(2) if (1) is not present, [.NT] present and get GenInstal, exitl; //(3) if both [.NTx86] and [.NT] not present, [] 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 [.Win] present, GetInstall it. //(2) if (1) is not present, GenInstall [] // 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 [,,] 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 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; }