|
|
/*
* Copyright (c) 2001 Microsoft Corporation * * Module Name: * * ocgen.cpp * * Abstract: * * This file handles all messages passed by the OC Manager * * Author: * * Michael Zoran (mzoran) Dec-2001 * * Environment: * * User Mode */
#define _OCGEN_CPP_
#include <stdlib.h>
#include <assert.h>
#include <tchar.h>
#include <objbase.h>
#include <shlwapi.h>
#include <lm.h>
#include <malloc.h>
#include "ocgen.h"
#pragma hdrstop
// also referred to in ocgen.h // forward reference
struct BITS_SUBCOMPONENT_DATA { const TCHAR * SubcomponentName; const TCHAR * SubcomponentKeyFileName; UINT64 FileVersion; BOOL Preinstalled; BOOL ShouldUpgrade; };
DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc); DWORD_PTR OnQueryImage(); DWORD OnQuerySelStateChange(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state, UINT flags); DWORD OnCalcDiskSpace(LPCTSTR ComponentId, LPCTSTR SubcomponentId, DWORD addComponent, HDSKSPC dspace); DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue); DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId); DWORD OnQueryState(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state); DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId); DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per);
BOOL VerifyComponent(LPCTSTR ComponentId); BOOL StateInfo(LPCTSTR SubcomponentId, BOOL *state); DWORD RegisterServers(HINF hinf, LPCTSTR component, DWORD state); DWORD EnumSections(HINF hinf, const TCHAR *component, const TCHAR *key, DWORD index, INFCONTEXT *pic, TCHAR *name); DWORD RegisterServices(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state); DWORD CleanupNetShares(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state); DWORD RunExternalProgram(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
BITS_SUBCOMPONENT_DATA* FindSubcomponent( LPCTSTR SubcomponentId ); DWORD InitializeSubcomponentStates( ); DWORD GetFileVersion64( LPCTSTR szFullPath, ULONG64 *pVer ); DWORD GetModuleVersion64( HMODULE hDll, ULONG64 * pVer );
HRESULT StopIIS();
// for registering dlls
typedef HRESULT (__stdcall *pfn)(void);
#define KEYWORD_REGSVR TEXT("RegSvr")
#define KEYWORD_UNREGSVR TEXT("UnregSvr")
#define KEYWORD_UNINSTALL TEXT("Uninstall")
#define KEYWORD_SOURCEPATH TEXT("SourcePath")
#define KEYWORD_DELSHARE TEXT("DelShare")
#define KEYWORD_ADDSERVICE TEXT("AddService")
#define KEYWORD_DELSERVICE TEXT("DelService")
#define KEYWORD_SHARENAME TEXT("Share")
#define KEYWORD_RUN TEXT("Run")
#define KEYVAL_SYSTEMSRC TEXT("SystemSrc")
#define KEYWORD_COMMANDLINE TEXT("CommandLine")
#define KEYWORD_TICKCOUNT TEXT("TickCount")
// Services keywords/options
#define KEYWORD_SERVICENAME TEXT("ServiceName")
#define KEYWORD_DISPLAYNAME TEXT("DisplayName")
#define KEYWORD_SERVICETYPE TEXT("ServiceType")
#define KEYWORD_STARTTYPE TEXT("StartType")
#define KEYWORD_ERRORCONTROL TEXT("ErrorControl")
#define KEYWORD_IMAGEPATH TEXT("BinaryPathName")
#define KEYWORD_LOADORDER TEXT("LoadOrderGroup")
#define KEYWORD_DEPENDENCIES TEXT("Dependencies")
#define KEYWORD_STARTNAME TEXT("ServiceStartName")
#define KEYWORD_PASSWORD TEXT("Password")
#define KEYVAL_ON TEXT("on")
#define KEYVAL_OFF TEXT("off")
#define KEYVAL_DEFAULT TEXT("default")
const char gszRegisterSvrRoutine[] = "DllRegisterServer"; const char gszUnregisterSvrRoutine[] = "DllUnregisterServer"; BOOL g_fRebootNeed = FALSE;
BITS_SUBCOMPONENT_DATA g_Subcomponents[] = { { TEXT("BITSServerExtensionsManager"), TEXT("bitsmgr.dll"), 0, FALSE, FALSE },
{ TEXT("BITSServerExtensionsISAPI"), TEXT("bitssrv.dll"), 0, FALSE, FALSE } };
const ULONG g_NumberSubcomponents = 2; BOOL g_AllSubcomponentsPreinstalled = FALSE; BOOL g_UpdateNeeded = FALSE; BOOL g_IISStopped = FALSE;
PER_COMPONENT_DATA g_Component;
/*
* called by CRT when _DllMainCRTStartup is the DLL entry point */
BOOL WINAPI DllMain( IN HINSTANCE hinstance, IN DWORD reason, IN LPVOID reserved ) {
BOOL b;
UNREFERENCED_PARAMETER(reserved);
b = true;
switch(reason) { case DLL_PROCESS_ATTACH: ghinst = hinstance; loginit();
// Fall through to process first thread
case DLL_THREAD_ATTACH: b = true; break;
case DLL_PROCESS_DETACH: break;
case DLL_THREAD_DETACH: break; }
return(b); }
DWORD_PTR OcEntry( IN LPCTSTR ComponentId, IN LPCTSTR SubcomponentId, IN UINT Function, IN UINT Param1, IN OUT PVOID Param2 ) {
DWORD_PTR rc;
DebugTraceOCNotification(Function, ComponentId); logOCNotification(Function, ComponentId);
switch(Function) {
case OC_PREINITIALIZE: #ifdef ANSI
rc = OCFLAG_ANSI; #else
rc = OCFLAG_UNICODE; #endif
break;
case OC_INIT_COMPONENT: rc = OnInitComponent(ComponentId, (PSETUP_INIT_COMPONENT)Param2); break;
case OC_EXTRA_ROUTINES: rc = OnExtraRoutines(ComponentId, (PEXTRA_ROUTINES)Param2); break;
case OC_SET_LANGUAGE: rc = (DWORD_PTR)false; break;
case OC_QUERY_IMAGE: rc = OnQueryImage(); break;
case OC_REQUEST_PAGES: rc = 0; break;
case OC_QUERY_CHANGE_SEL_STATE: rc = OnQuerySelStateChange(ComponentId, SubcomponentId, Param1, (UINT)((UINT_PTR)Param2)); break;
case OC_CALC_DISK_SPACE: rc = OnCalcDiskSpace(ComponentId, SubcomponentId, Param1, Param2); break;
case OC_QUEUE_FILE_OPS: rc = OnQueueFileOps(ComponentId, SubcomponentId, (HSPFILEQ)Param2); break;
case OC_NOTIFICATION_FROM_QUEUE: rc = NO_ERROR; break;
case OC_QUERY_STEP_COUNT: rc = 2; break;
case OC_COMPLETE_INSTALLATION: rc = OnCompleteInstallation(ComponentId, SubcomponentId); break;
case OC_CLEANUP: rc = NO_ERROR; break;
case OC_QUERY_STATE: rc = OnQueryState(ComponentId, SubcomponentId, Param1); break;
case OC_NEED_MEDIA: rc = false; break;
case OC_ABOUT_TO_COMMIT_QUEUE: rc = OnAboutToCommitQueue(ComponentId,SubcomponentId); break;
case OC_QUERY_SKIP_PAGE: rc = false; break;
case OC_WIZARD_CREATED: rc = NO_ERROR; break;
default: rc = NO_ERROR; break; }
DebugTrace(1, TEXT("processing completed")); logOCNotificationCompletion();
return rc; }
/*-------------------------------------------------------*/ /*
* OC Manager message handlers * *-------------------------------------------------------*/
/*
* OnInitComponent() * * handler for OC_INIT_COMPONENT */
DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc) { INFCONTEXT context; TCHAR buf[256]; HINF hinf; BOOL rc;
memset( &g_Component, 0, sizeof( g_Component ) );
if (!VerifyComponent( ComponentId ) ) return NO_ERROR;
DWORD dwResult = InitializeSubcomponentStates(); if ( ERROR_SUCCESS != dwResult ) return dwResult;
g_IISStopped = FALSE;
// store component inf handle
g_Component.hinf = (psc->ComponentInfHandle == INVALID_HANDLE_VALUE) ? NULL : psc->ComponentInfHandle;
// open the inf
if (g_Component.hinf) SetupOpenAppendInfFile(NULL, g_Component.hinf,NULL);
// copy helper routines and flags
g_Component.HelperRoutines = psc->HelperRoutines;
g_Component.Flags = psc->SetupData.OperationFlags;
g_Component.SourcePath = NULL;
// play
srand(GetTickCount());
return NO_ERROR; }
/*
* OnExtraRoutines() * * handler for OC_EXTRA_ROUTINES */
DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per) {
if (!VerifyComponent( ComponentId ) ) return NO_ERROR;
memcpy(&g_Component.ExtraRoutines, per, sizeof( g_Component.ExtraRoutines ) ); g_Component.ExtraRoutines.size = sizeof( g_Component.ExtraRoutines );
return NO_ERROR; }
/*
* OnSetLanguage() * * handler for OC_SET_LANGUAGE */
DWORD_PTR OnQueryImage() { return (DWORD_PTR)LoadBitmap(NULL,MAKEINTRESOURCE(32754)); // OBM_CLOSE
}
/*
* OnQuerySelStateChange() * * don't let the user deselect the sam component */
DWORD OnQuerySelStateChange(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state, UINT flags) {
DWORD rc = true;
if ( !VerifyComponent( ComponentId ) ) return rc;
if ( !_tcsicmp( SubcomponentId, TEXT( "BITSServerExtensions" ) ) ) {
if ( state ) {
if ( flags & OCQ_DEPENDENT_SELECTION ) { rc = false; }
} } return rc; }
/*
* OnCalcDiskSpace() * * handler for OC_ON_CALC_DISK_SPACE */
DWORD OnCalcDiskSpace(LPCTSTR ComponentId, LPCTSTR SubcomponentId, DWORD addComponent, HDSKSPC dspace) { DWORD rc = NO_ERROR; TCHAR section[S_SIZE];
//
// Param1 = 0 if for removing component or non-0 if for adding component
// Param2 = HDSKSPC to operate on
//
// Return value is Win32 error code indicating outcome.
//
// In our case the private section for this component/subcomponent pair
// is a simple standard inf install section, so we can use the high-level
// disk space list api to do what we want.
//
if (!VerifyComponent( ComponentId ) ) return NO_ERROR;
StringCchCopy(section, S_SIZE, SubcomponentId);
if (addComponent) { rc = SetupAddInstallSectionToDiskSpaceList(dspace, g_Component.hinf, NULL, section, 0, 0); } else { rc = SetupRemoveInstallSectionFromDiskSpaceList(dspace, g_Component.hinf, NULL, section, 0, 0); }
if (!rc) rc = GetLastError(); else rc = NO_ERROR;
return rc; }
/*
* OnQueueFileOps() * * handler for OC_QUEUE_FILE_OPS */
DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue) { BOOL state; BOOL rc; INFCONTEXT context; TCHAR section[256]; TCHAR srcpathbuf[256]; TCHAR *srcpath;
if (!VerifyComponent(ComponentId)) return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId) return NO_ERROR;
g_Component.queue = queue;
if (!StateInfo(SubcomponentId, &state)) return NO_ERROR;
StringCchPrintfW(section, 256, SubcomponentId);
rc = TRUE; if (!state) { // being uninstalled. Fetch uninstall section name.
rc = SetupFindFirstLine(g_Component.hinf, SubcomponentId, KEYWORD_UNINSTALL, &context);
if (rc) { rc = SetupGetStringField(&context, 1, section, sizeof(section) / sizeof(TCHAR), NULL); }
// also, unregister the dlls and kill services before deletion
SetupInstallServicesFromInfSection(g_Component.hinf, section, 0); SetupInstallFromInfSection(NULL,g_Component.hinf,section,SPINST_UNREGSVR,NULL,NULL,0,NULL,NULL,NULL,NULL); }
if (rc) { // if uninstalling, don't use version checks
rc = SetupInstallFilesFromInfSection(g_Component.hinf, NULL, queue, section, g_Component.SourcePath, // state ? SP_COPY_NEWER : 0);
0 ); }
if (!rc) return GetLastError();
return NO_ERROR; }
/*
* OnCompleteInstallation * * handler for OC_COMPLETE_INSTALLATION */
DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId) { INFCONTEXT context; TCHAR section[256]; BOOL state; BOOL rc; DWORD Error = NO_ERROR;
// Do post-installation processing in the cleanup section.
// This way we know all compoents queued for installation
// have beein installed before we do our stuff.
if (!VerifyComponent(ComponentId)) return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId) return NO_ERROR;
// if this is gui mode setup, need to regsvr just in case something
// changed even if the files are not being replaced.
if ( !(g_Component.Flags & SETUPOP_STANDALONE) && ( ( _tcsicmp( TEXT("BITSServerExtensionsManager"), SubcomponentId ) == 0 ) || ( _tcsicmp( TEXT("BITSServerExtensionsISAPI"), SubcomponentId ) == 0 ) ) ) {
BOOL SettingChanged = StateInfo( SubcomponentId, &state );
if ( !SettingChanged && !state ) return NO_ERROR; // if its not installed, leave it uninstalled.
}
else if ( !StateInfo( SubcomponentId, &state) ) return NO_ERROR;
StringCchPrintfW(section, 256, SubcomponentId);
rc = TRUE; if (!state) { // being uninstalled. Fetch uninstall section name.
rc = SetupFindFirstLine(g_Component.hinf, SubcomponentId, KEYWORD_UNINSTALL, &context);
if (rc) { rc = SetupGetStringField(&context, 1, section, sizeof(section) / sizeof(TCHAR), NULL); } }
if (state) { //
// installation
//
if (rc) { // process the inf file
rc = SetupInstallFromInfSection(NULL, // hwndOwner
g_Component.hinf, // inf handle
section, // name of component
SPINST_ALL & ~SPINST_FILES, NULL, // relative key root
NULL, // source root path
0, // copy flags
NULL, // callback routine
NULL, // callback routine context
NULL, // device info set
NULL); // device info struct
if (rc) { rc = SetupInstallServicesFromInfSection(g_Component.hinf, section, 0); Error = GetLastError(); if (!rc && Error == ERROR_SECTION_NOT_FOUND) { rc = TRUE; Error = NO_ERROR; } if (rc) { if (Error == ERROR_SUCCESS_REBOOT_REQUIRED) { g_Component.HelperRoutines.SetReboot(g_Component.HelperRoutines.OcManagerContext,TRUE); } Error = NO_ERROR; rc = RunExternalProgram(&g_Component, section, state); } } }
} else { //
// uninstallation
//
if (rc) {
rc = RunExternalProgram(&g_Component, section, state);
} if (rc) { rc = CleanupNetShares(&g_Component, section, state);
} }
if (!rc && (Error == NO_ERROR) ) { Error = GetLastError( ); }
return Error; }
/*
* OnQueryState() * * handler for OC_QUERY_STATE */
DWORD OnQueryState(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state) { if ( !VerifyComponent( ComponentId ) ) return SubcompUseOcManagerDefault;
BITS_SUBCOMPONENT_DATA* SubcomponentData = FindSubcomponent( SubcomponentId );
if ( !SubcomponentData ) {
if ( !_tcsicmp( TEXT( "BITSServerExtensions" ), SubcomponentId ) ) {
if ( OCSELSTATETYPE_ORIGINAL == state && g_AllSubcomponentsPreinstalled ) return SubcompOn; else return SubcompUseOcManagerDefault;
} else return SubcompUseOcManagerDefault;
}
if ( OCSELSTATETYPE_ORIGINAL == state ) {
return SubcomponentData->Preinstalled ? SubcompOn : SubcompOff;
}
return SubcompUseOcManagerDefault; }
/*
* OnAboutToCommitQueue() * * handler for OC_ABOUT_TO_COMMIT_QUEUE */
DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId) { BOOL state; BOOL rc; INFCONTEXT context; TCHAR section[256]; TCHAR srcpathbuf[256]; TCHAR *srcpath;
if (!VerifyComponent( ComponentId )) return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId) return NO_ERROR;
if (!StateInfo( SubcomponentId, &state)) return NO_ERROR;
if (state) {
if ( g_UpdateNeeded ) {
if ( !g_IISStopped ) { StopIIS(); g_IISStopped = FALSE; }
}
return NO_ERROR; }
// Fetch uninstall section name.
rc = SetupFindFirstLine( g_Component.hinf, SubcomponentId, KEYWORD_UNINSTALL, &context);
if (rc) { rc = SetupGetStringField( &context, 1, section, sizeof(section) / sizeof(TCHAR), NULL); }
if (rc) rc = SetupInstallServicesFromInfSection(g_Component.hinf, section, 0);
if (rc) { rc = SetupInstallFromInfSection( NULL, g_Component.hinf, section, SPINST_ALL & ~SPINST_FILES, NULL, NULL, 0, NULL, NULL, NULL, NULL); } if (rc) { SetLastError(NO_ERROR); } return GetLastError();
}
BOOL VerifyComponent( LPCTSTR ComponentId ) { if ( !_tcsicmp( ComponentId, TEXT("BITSServerExtensions") ) ) return TRUE; return FALSE; }
// loads current selection state info into "state" and
// returns whether the selection state was changed
BOOL StateInfo( LPCTSTR SubcomponentId, BOOL *state ) { BOOL rc = TRUE;
assert(state);
// otherwise, check for a change in installation state
*state = g_Component.HelperRoutines.QuerySelectionState( g_Component.HelperRoutines.OcManagerContext, SubcomponentId, OCSELSTATETYPE_CURRENT);
if (*state == g_Component.HelperRoutines.QuerySelectionState( g_Component.HelperRoutines.OcManagerContext, SubcomponentId, OCSELSTATETYPE_ORIGINAL)) { // no change
rc = FALSE; }
if ( *state ) {
BITS_SUBCOMPONENT_DATA* SubcomponentData = FindSubcomponent( SubcomponentId );
if ( SubcomponentData && g_UpdateNeeded ) rc = TRUE;
}
return rc; }
/*
* EnumSections() * * finds the name of a section for a specified keyword */
DWORD EnumSections( HINF hinf, const TCHAR *component, const TCHAR *key, DWORD index, INFCONTEXT *pic, TCHAR *name ) { TCHAR section[S_SIZE];
if (!SetupFindFirstLine(hinf, component, NULL, pic)) return 0;
if (!SetupFindNextMatchLine(pic, key, pic)) return 0;
if (index > SetupGetFieldCount(pic)) return 0;
if (!SetupGetStringField(pic, index, section, SBUF_SIZE, NULL)) return 0;
if (name) StringCchCopy(name, S_SIZE, section);
return SetupFindFirstLine(hinf, section, NULL, pic); }
DWORD OcLog( LPCTSTR ComponentId, UINT level, LPCTSTR sz ) { TCHAR fmt[5000]; PPER_COMPONENT_DATA cd;
if (!VerifyComponent( ComponentId ) ) return NO_ERROR;
assert(g_Component.ExtraRoutines.LogError); assert(level); assert(sz);
StringCchCopy(fmt, 5000, TEXT("%s: %s"));
return g_Component.ExtraRoutines.LogError( g_Component.HelperRoutines.OcManagerContext, level, fmt, ComponentId, sz); }
DWORD CleanupNetShares( PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state) { INFCONTEXT ic; TCHAR sname[S_SIZE]; DWORD section; TCHAR *keyword;
if (state) { return NO_ERROR; } else { keyword = KEYWORD_DELSHARE; }
for (section = 1; EnumSections(cd->hinf, component, keyword, section, &ic, sname); section++) { INFCONTEXT sic; NET_API_STATUS netStat;
CHAR Temp[SBUF_SIZE]; TCHAR ShareName[ SBUF_SIZE ];
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_SHARENAME, &sic)) { log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_SHARENAME ); continue; }
if (!SetupGetStringField(&sic, 1, ShareName, SBUF_SIZE, NULL)) { log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_SHARENAME ); continue; }
#ifdef UNICODE
netStat = NetShareDel( NULL, ShareName, 0 ); #else // UNICODE
WCHAR ShareNameW[ SBUF_SIZE ]; mbstowcs( ShareNameW, ShareName, lstrlen(ShareName)); netStat = NetShareDel( NULL, ShareNameW, 0 ); #endif // UNICODE
if ( netStat != NERR_Success ) { log( TEXT("OCGEN: Failed to remove %s share. Error 0x%08x\r\n"), ShareName, netStat ); continue; }
log( TEXT("OCGEN: %s share removed successfully.\r\n"), ShareName ); }
return TRUE; }
DWORD RunExternalProgram( PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state) { INFCONTEXT ic; TCHAR sname[S_SIZE]; DWORD section; TCHAR *keyword;
keyword = KEYWORD_RUN;
for (section = 1; EnumSections(cd->hinf, component, keyword, section, &ic, sname); section++) { INFCONTEXT sic; TCHAR CommandLine[ SBUF_SIZE ]; CHAR szTickCount[ SBUF_SIZE ]; ULONG TickCount; BOOL b; STARTUPINFO startupinfo; PROCESS_INFORMATION process_information; DWORD dwErr;
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_COMMANDLINE , &sic)) { log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_COMMANDLINE ); continue; }
if (!SetupGetStringField(&sic, 1, CommandLine, SBUF_SIZE, NULL)) { log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_COMMANDLINE ); continue; }
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_TICKCOUNT, &sic)) { log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_TICKCOUNT ); continue; }
if (!SetupGetStringFieldA(&sic, 1, szTickCount, SBUF_SIZE, NULL)) { log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_TICKCOUNT ); continue; }
TickCount = atoi( szTickCount );
ZeroMemory( &startupinfo, sizeof(startupinfo) ); startupinfo.cb = sizeof(startupinfo); startupinfo.dwFlags = STARTF_USESHOWWINDOW; startupinfo.wShowWindow = SW_HIDE | SW_SHOWMINNOACTIVE;
b = CreateProcess( NULL, CommandLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &startupinfo, &process_information ); if ( !b ) { log( TEXT("OCGEN: failed to spawn %s process.\r\n"), CommandLine ); continue; }
dwErr = WaitForSingleObject( process_information.hProcess, TickCount * 1000 ); if ( dwErr != NO_ERROR ) { log( TEXT("OCGEN: WaitForSingleObject() failed. Error 0x%08x\r\n"), dwErr ); TerminateProcess( process_information.hProcess, -1 ); CloseHandle( process_information.hProcess ); CloseHandle( process_information.hThread ); continue; }
CloseHandle( process_information.hProcess ); CloseHandle( process_information.hThread );
log( TEXT("OCGEN: %s successfully completed within %u seconds.\r\n"), CommandLine, TickCount ); }
return TRUE; }
BITS_SUBCOMPONENT_DATA* FindSubcomponent( LPCTSTR SubcomponentId ) {
for( unsigned int i = 0; i < g_NumberSubcomponents; i++ ) {
if ( _tcsicmp( SubcomponentId, g_Subcomponents[i].SubcomponentName ) == 0 ) return &g_Subcomponents[i];
} return NULL;
}
DWORD InitializeSubcomponentStates() { // Load this module's version information
DWORD dwResult; ULONG64 ThisModuleVersion; BOOL AllSubcomponentsPreinstalled = TRUE; BOOL UpdateNeeded = TRUE;
dwResult = GetModuleVersion64( ghinst, &ThisModuleVersion ); if ( ERROR_SUCCESS != dwResult ) return dwResult;
TCHAR SystemDirectory[ MAX_PATH * 2 ]; GetSystemWindowsDirectory( SystemDirectory, MAX_PATH + 1 ); StringCchCat( SystemDirectory, MAX_PATH * 2, TEXT("\\System32\\") );
for( unsigned int i = 0; i < g_NumberSubcomponents; i++ ) {
TCHAR FileName[ MAX_PATH * 2 ]; StringCchCopy( FileName, MAX_PATH * 2, SystemDirectory ); StringCchCatW( FileName, MAX_PATH * 2, g_Subcomponents[ i ].SubcomponentKeyFileName );
dwResult = GetFileVersion64( FileName, &g_Subcomponents[ i ].FileVersion );
// If the file isn't found, skip it
if ( ERROR_FILE_NOT_FOUND == dwResult || ERROR_PATH_NOT_FOUND == dwResult ) { AllSubcomponentsPreinstalled = FALSE; continue; }
if ( dwResult != ERROR_SUCCESS ) return dwResult;
g_Subcomponents[ i ].Preinstalled = TRUE; g_Subcomponents[ i ].ShouldUpgrade = g_Subcomponents[ i ].FileVersion < ThisModuleVersion;
if ( g_Subcomponents[i].ShouldUpgrade ) UpdateNeeded = TRUE;
}
g_AllSubcomponentsPreinstalled = AllSubcomponentsPreinstalled; g_UpdateNeeded = TRUE; return ERROR_SUCCESS;
}
DWORD GetFileVersion64( LPCTSTR szFullPath, ULONG64 * pVer ) { DWORD dwHandle; DWORD dwLen;
*pVer = 0;
//
// Check to see if the file exists
//
DWORD dwAttributes = GetFileAttributes( szFullPath );
if ( INVALID_FILE_ATTRIBUTES == dwAttributes ) return GetLastError();
//
// Get the file version info size
//
if ((dwLen = GetFileVersionInfoSize( (LPTSTR)szFullPath, &dwHandle)) == 0) return GetLastError();
//
// Allocate enough size to hold version info
//
char * VersionInfo = new char[ dwLen ];
if ( !VersionInfo ) return ERROR_NOT_ENOUGH_MEMORY;
//
// Get the version info
//
if (!GetFileVersionInfo( (LPTSTR)szFullPath, dwHandle, dwLen, VersionInfo )) { DWORD Error = GetLastError(); delete[] VersionInfo; return Error; }
{
VS_FIXEDFILEINFO *pvsfi; UINT dwLen2;
if ( VerQueryValue( VersionInfo, TEXT("\\"), (LPVOID *)&pvsfi, &dwLen2 ) ) { *pVer = ( ULONG64(pvsfi->dwFileVersionMS) << 32) | (pvsfi->dwFileVersionLS); }
}
delete[] VersionInfo; return ERROR_SUCCESS;
}
//
// This ungainly typedef seems to have no global definition. There are several identical
// definitions in the Windows NT sources, each of which has that bizarre bit-stripping
// on szKey. I got mine from \nt\base\ntsetup\srvpack\update\splib\common.h.
//
typedef struct tagVERHEAD { WORD wTotLen; WORD wValLen; WORD wType; /* always 0 */ WCHAR szKey[(sizeof("VS_VERSION_INFO")+3)&~03]; VS_FIXEDFILEINFO vsf; } VERHEAD ;
DWORD GetModuleVersion64( HMODULE hDll, ULONG64 * pVer ) { DWORD* pdwTranslation; VS_FIXEDFILEINFO* pFileInfo; UINT uiSize;
*pVer = 0;
HRSRC hrsrcVersion = FindResource( hDll, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
if (!hrsrcVersion) return GetLastError();
HGLOBAL hglobalVersion = LoadResource(hDll, hrsrcVersion); if (!hglobalVersion) return GetLastError();
VERHEAD * pVerHead = (VERHEAD *) LockResource(hglobalVersion); if (!pVerHead) return GetLastError();
// I stole this code from \nt\com\complus\src\shared\util\svcerr.cpp,
// and the comment is theirs:
//
// VerQueryValue will write to the memory, for some reason.
// Therefore we must make a writable copy of the version
// resource info before calling that API.
void *pvVersionInfo = new char[ pVerHead->wTotLen + pVerHead->wTotLen/2 ];
if ( !pvVersionInfo ) return ERROR_NOT_ENOUGH_MEMORY;
memcpy(pvVersionInfo, pVerHead, pVerHead->wTotLen);
// Retrieve file version info
if ( VerQueryValue( pvVersionInfo, L"\\", (void**)&pFileInfo, &uiSize) ) { *pVer = (ULONG64(pFileInfo->dwFileVersionMS) << 32) | (pFileInfo->dwFileVersionLS); }
delete[] pvVersionInfo;
return ERROR_SUCCESS; }
HRESULT BITSGetStartupInfo( LPSTARTUPINFOA lpStartupInfo ) {
__try { GetStartupInfoA( lpStartupInfo ); } __except( EXCEPTION_EXECUTE_HANDLER ) { return E_OUTOFMEMORY; } return S_OK;
}
HRESULT StopIIS() {
//
// Restarts IIS by calling "iisreset /stop" at the commandline.
//
STARTUPINFOA StartupInfo;
HRESULT Hr = BITSGetStartupInfo( &StartupInfo );
if ( FAILED( Hr ) ) return Hr;
#define IISSTOP_EXE "iisreset.exe"
#define IISSTOP_CMDLINE "iisreset /stop"
PROCESS_INFORMATION ProcessInfo; CHAR sApplicationPath[MAX_PATH]; CHAR *pApplicationName = NULL; CHAR sCmdLine[MAX_PATH]; DWORD dwLen = MAX_PATH; DWORD dwCount;
dwCount = SearchPathA(NULL, // Search Path, NULL is PATH
IISSTOP_EXE, // Application
NULL, // Extension (already specified)
dwLen, // Length (char's) of sApplicationPath
sApplicationPath, // Path + Name for application
&pApplicationName ); // File part of sApplicationPath
if (dwCount == 0) { return HRESULT_FROM_WIN32( GetLastError() ); }
if (dwCount > dwLen) { return HRESULT_FROM_WIN32( ERROR_BUFFER_OVERFLOW ); }
StringCbCopyA(sCmdLine, MAX_PATH, IISSTOP_CMDLINE);
BOOL RetVal = CreateProcessA( sApplicationPath, // name of executable module
sCmdLine, // command line string
NULL, // SD
NULL, // SD
FALSE, // handle inheritance option
CREATE_NO_WINDOW, // creation flags
NULL, // new environment block
NULL, // current directory name
&StartupInfo, // startup information
&ProcessInfo // process information
);
if ( !RetVal ) return HRESULT_FROM_WIN32( GetLastError() );
WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
DWORD Status; GetExitCodeProcess( ProcessInfo.hProcess, &Status );
CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread );
return HRESULT_FROM_WIN32( Status ); }
|