Windows2003-3790/inetcore/setup/iexpress/advpack/advpack.c
2020-09-30 16:53:55 +02:00

6347 lines
231 KiB
C

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