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