|
|
#include "svcpack.h"
//
// The module instance and name
//
HINSTANCE hDllInstance;
//
// The path to the OS Source
//
TCHAR OsSourcePath[MAX_PATH];
//
// Function declarations
//
BOOL DoPhaseOneWork(VOID);
BOOL DoPhaseTwoWork(VOID);
BOOL DoPhaseThreeWork(VOID);
BOOL DoPhaseFourWork(VOID);
BOOL InitializeSourcePath( PTSTR SourcePath, HINF hInf );
BOOL MyInstallProductCatalog( LPCTSTR PathToCatalog, LPCTSTR CatalogNoPath );
LPTSTR CombinePaths( IN LPTSTR ParentPath, IN LPCTSTR ChildPath, OUT LPTSTR TargetPath // can be same as ParentPath if want to append
);
BOOL SpawnProcessAndWaitForItToComplete( IN LPTSTR CommandLine, OUT PDWORD ReturnCode OPTIONAL );
BOOL RunInfProcesses( IN HINF hInf );
BOOL GetInfValue( IN HINF hInf, IN LPTSTR SectionName, IN LPTSTR KeyName, OUT PDWORD pdwValue );
BOOL DoesInfVersionInfoMatch( IN HINF hInf );
BOOL CALLBACK SvcPackCallbackRoutine( IN DWORD dwSetupInterval, IN DWORD dwParam1, IN DWORD dwParam2, IN DWORD dwParam3 )
{
switch ( dwSetupInterval ) { case SVCPACK_PHASE_1: //
// install catalogs, etc.
//
DoPhaseOneWork(); case SVCPACK_PHASE_2: case SVCPACK_PHASE_3: break;
case SVCPACK_PHASE_4: //
// Do registry changes, etc.
//
DoPhaseFourWork(); break;
}
return TRUE;
}
BOOL WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvResreved) {
switch (fdwReason) { case DLL_PROCESS_ATTACH: //
// Save the module instance and name
//
hDllInstance = hInstance;
break;
case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: default: break; } return TRUE; }
BOOL DoPhaseOneWork( VOID ) /*++
Routine Description:
Routine installs the catalogs listed in the svcpack.inf's [ProductCatalogsToInstall] section. It is assumed that these catalogs are present at the os source path.
Arguments:
None.
Return Value:
TRUE if the catalogs were successfully installed.
--*/ { HINF hInf; TCHAR CatalogSourcePath[MAX_PATH]; INFCONTEXT InfContext; BOOL RetVal = TRUE; //
// Open the svcpack.inf so we can install items from it.
//
hInf = SetupOpenInfFile( TEXT("SVCPACK.INF"), NULL, INF_STYLE_WIN4, NULL); if (hInf == INVALID_HANDLE_VALUE) { return(FALSE); }
//
// Make sure the INF has matching version info
// Return TRUE even if the versions don't match so setup doesn't barf.
//
if (!DoesInfVersionInfoMatch(hInf)) { goto e0; }
//
// Initialize the source path global variable and save it off for later.
//
if (!InitializeSourcePath(OsSourcePath,hInf)) { RetVal = FALSE; goto e0; }
//
// see if we actually have any catalogs to install
//
if (SetupFindFirstLine( hInf, TEXT("ProductCatalogsToInstall"), NULL, &InfContext)) { UINT Count,Total; //
// we have catalogs in the section, so let's install them.
//
Total = SetupGetLineCount(hInf, TEXT("ProductCatalogsToInstall"));
for (Count = 0; Count < Total; Count++) { PCTSTR CatalogNoPath;
//
// retrieve a catalog name
//
if(SetupGetLineByIndex( hInf, TEXT("ProductCatalogsToInstall"), Count, &InfContext)) { CatalogNoPath = pSetupGetField(&InfContext,1);
//
// build the full path to the catalog
//
_tcscpy(CatalogSourcePath,OsSourcePath); CombinePaths( CatalogSourcePath, CatalogNoPath, CatalogSourcePath);
//
// now install the catalog
//
if (!MyInstallProductCatalog( CatalogSourcePath, CatalogNoPath)) { RetVal = FALSE; } } else { RetVal = FALSE; } } }
e0: SetupCloseInfFile( hInf ); return(RetVal); }
BOOL MyInstallProductCatalog( LPCTSTR PathToCatalog, LPCTSTR CatalogSourceNoPath ) /*++
Routine Description:
Routine installs the specified catalog with the given source name. The routine will copy (and if necessary, expand) the catalog file. It then validates and installs the catalog.
Arguments:
PathToCatalog - full path to catalog CatalogSourceNoPath - just the filename part of the catalog, which we use as the filename of the catalog to be installed.
Return Value:
TRUE if the catalogs were successfully installed.
--*/
{ TCHAR CatalogDestPath[MAX_PATH]; TCHAR CatalogDestWithPath[MAX_PATH]; BOOL RetVal = FALSE; SetupapiVerifyProblem Problem = SetupapiVerifyCatalogProblem;
//
// we need to copy (and potentially expand) the catalog from the source,
// and we use %windir% as a working directory.
//
if(GetWindowsDirectory( CatalogDestPath, sizeof(CatalogDestPath)/sizeof(CatalogDestPath[0])) && GetTempFileName( CatalogDestPath, TEXT("SETP"), 0, CatalogDestWithPath)) {
//
// assume that media is already present -- since product catalogs
// we installed just prior to this, we know that media was present
// just a few moments ago
//
if ((SetupDecompressOrCopyFile( PathToCatalog, CatalogDestWithPath, NULL) == NO_ERROR)
&& (pSetupVerifyCatalogFile(CatalogDestWithPath) == NO_ERROR) && (pSetupInstallCatalog( CatalogDestWithPath, CatalogSourceNoPath, NULL) == NO_ERROR)) { RetVal = TRUE; }
//
// cleanup the temp file.
//
DeleteFile(CatalogDestWithPath);
}
return(RetVal);
}
BOOL InitializeSourcePath( PTSTR SourcePath, HINF hInf ) /*++
Routine Description:
Routine retrieves the os source path from the registry, then appends the subdirectory in the specified inf.
Arguments:
None.
Return Value:
TRUE if the catalogs were successfully installed.
--*/
{ HKEY hKey = NULL; TCHAR TempPath[MAX_PATH]; TCHAR MyAnswerFile[MAX_PATH]; DWORD Type,Size = MAX_PATH; INFCONTEXT InfContext; BOOL RetVal = FALSE; //
// if it was already initialized to something, just return TRUE.
//
if (*SourcePath != (TCHAR)TEXT('\0')) { RetVal = TRUE; goto e0; }
GetSystemDirectory(MyAnswerFile, MAX_PATH); CombinePaths( MyAnswerFile, TEXT("$winnt$.inf"), MyAnswerFile );
GetPrivateProfileString( TEXT("Data"), TEXT("DosPath"), TEXT(""), TempPath, sizeof(TempPath)/sizeof(TCHAR), MyAnswerFile ); _tcscpy(SourcePath,TempPath); RetVal = TRUE;
//
// now append the subdirectory specified in the inf (if any)
//
if (hInf && SetupFindFirstLine( hInf, TEXT("SetupData"), TEXT("CatalogSubDir"), &InfContext)) { PCTSTR p = pSetupGetField(&InfContext,1);
CombinePaths( SourcePath, p, SourcePath); }
e0: return(RetVal); }
BOOL DoPhaseFourWork(VOID) {
BOOL Success = TRUE; HINF hInf = NULL;
//
// Attempt to open the SVCPACK.INF file.
// If found, and no problems with it, do
// the associated work.
//
hInf = SetupOpenInfFile ( TEXT("SVCPACK.INF"), NULL, INF_STYLE_WIN4, NULL );
if (( hInf == NULL ) || ( hInf == INVALID_HANDLE_VALUE )) { Success = FALSE; goto exit0; }
//
// Make sure the INF has matching version info.
// Return TRUE even if the versions don't match so setup doesn't barf.
//
if (!DoesInfVersionInfoMatch(hInf)) { goto exit1; }
Success = RunInfProcesses( hInf );
exit1: SetupCloseInfFile( hInf ); exit0: return Success;
}
BOOL SpawnProcessAndWaitForItToComplete( IN LPTSTR CommandLine, OUT PDWORD ReturnCode OPTIONAL ) { LPTSTR InternalCommandLine = NULL; PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo; BOOL Success;
//
// CreateProcess needs a non-const command line buffer because it likes
// to party on it.
//
InternalCommandLine = malloc( MAX_PATH );
if ( InternalCommandLine == NULL ) { return FALSE; }
_tcscpy( InternalCommandLine, CommandLine );
ZeroMemory( &StartupInfo, sizeof( StartupInfo )); StartupInfo.cb = sizeof( StartupInfo );
Success = CreateProcess( NULL, InternalCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo );
if ( ! Success ) { free( InternalCommandLine ); return FALSE; }
WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
if ( ReturnCode != NULL ) { GetExitCodeProcess( ProcessInfo.hProcess, ReturnCode ); }
CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread ); free( InternalCommandLine );
return TRUE; }
LPTSTR CombinePaths( IN LPTSTR ParentPath, IN LPCTSTR ChildPath, OUT LPTSTR TargetPath // can be same as ParentPath if want to append
) { ULONG ParentLength = _tcslen( ParentPath ); LPTSTR p;
if ( ParentPath != TargetPath ) { memcpy( TargetPath, ParentPath, ParentLength * sizeof(TCHAR) ); }
p = TargetPath + ParentLength;
if (( ParentLength > 0 ) && ( *( p - 1 ) != '\\' ) && ( *( p - 1 ) != '/' )) { *p++ = '\\'; }
_tcscpy( p, ChildPath );
return TargetPath; }
BOOL RunInfProcesses( IN HINF hInf ) {
LPTSTR SectionName = TEXT("SetupHotfixesToRun"); LPTSTR szFileName; LPTSTR szFullPath; INFCONTEXT InfContext; BOOL Success = TRUE;
//
// Loop through all the lines in the SetupHotfixesToRun section,
// spawning off each one.
//
szFileName = malloc( MAX_PATH ); if (szFileName == NULL) { Success = FALSE; goto exit0; }
szFullPath = malloc( MAX_PATH ); if (szFullPath == NULL) { Success = FALSE; goto exit1; } Success = SetupFindFirstLine( hInf, SectionName, NULL, &InfContext ) && SetupGetLineText( &InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL ); while ( Success ) { *szFullPath = 0; CombinePaths( OsSourcePath, szFileName, szFullPath ); //
// OK, spawn the EXE, and ignore any errors returned
//
SpawnProcessAndWaitForItToComplete( szFullPath, NULL ); Success = SetupFindNextLine( &InfContext, &InfContext ) && SetupGetLineText( &InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL ); } Success = TRUE; free( (PVOID)szFullPath ); exit1: free( (PVOID)szFileName ); exit0: return Success;
}
BOOL GetInfValue( IN HINF hInf, IN LPTSTR SectionName, IN LPTSTR KeyName, OUT PDWORD pdwValue ) { BOOL Success; TCHAR TextBuffer[MAX_PATH];
Success = SetupGetLineText( NULL, hInf, SectionName, KeyName, TextBuffer, (sizeof(TextBuffer)/sizeof(TCHAR)), NULL );
*pdwValue = _tcstoul( TextBuffer, NULL, 0 );
return Success; }
BOOL DoesInfVersionInfoMatch( IN HINF hInf ) {
DWORD dwBuildNumber, dwMajorVersion, dwMinorVersion; OSVERSIONINFOEX OsVersionInfo;
if (( ! GetInfValue( hInf, TEXT("Version"), TEXT("BuildNumber"), &dwBuildNumber )) || ( ! GetInfValue( hInf, TEXT("Version"), TEXT("MajorVersion"), &dwMajorVersion )) || ( ! GetInfValue( hInf, TEXT("Version"), TEXT("MinorVersion"), &dwMinorVersion ))) {
return FALSE; }
OsVersionInfo.dwOSVersionInfoSize = sizeof( OsVersionInfo ); if (!GetVersionEx( (LPOSVERSIONINFO) &OsVersionInfo )) {
return FALSE; }
if ((OsVersionInfo.dwBuildNumber != dwBuildNumber) || (OsVersionInfo.dwMajorVersion != dwMajorVersion) || (OsVersionInfo.dwMinorVersion != dwMinorVersion)) {
return FALSE; }
return TRUE; }
|