windows-nt/Source/XPSP1/NT/admin/services/drizzle/server/bitsoc/ocgen.cpp
2020-09-26 16:20:57 +08:00

1327 lines
34 KiB
C++

/*
* 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 );
}