//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// // JobWatchDlg.cpp : implementation file // #include "stdafx.h" #include "ServiceInstallDlg.h" #include "tier1/strtools.h" #define DEFAULT_INSTALL_LOCATION "C:\\Program Files\\Valve\\vmpi_service" #define HLKM_WINDOWS_RUN_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run" #define VMPI_SERVICE_VALUE_NAME "VMPI Service" #define VMPI_SERVICE_UI_VALUE_NAME "VMPI Service UI" // These are the files required for installation. char *g_pInstallFiles[] = { "vmpi_service.exe", "vmpi_service_ui.exe", "WaitAndRestart.exe", "vmpi_service_install.exe", "tier0.dll", "vmpi_transfer.exe", "filesystem_stdio.dll", "vstdlib.dll" }; #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif HWND g_hMessageControl = NULL; HKEY g_hVMPIKey = NULL; // hklm/software/valve/vmpi. bool g_bNoOutput = false; bool g_bDontTouchUI = false; bool g_bReinstalling = false; FILE *g_fpLog = NULL; char* FindArg( int argc, char **argv, const char *pArgName, char *pDefaultValue="" ) { for ( int i=0; i < argc; i++ ) { if ( stricmp( argv[i], pArgName ) == 0 ) { if ( (i+1) >= argc ) return pDefaultValue; else return argv[i+1]; } } return NULL; } void CloseLog() { if ( g_fpLog ) { fflush( g_fpLog ); fclose( g_fpLog ); flushall(); g_fpLog = NULL; } } void OpenLog() { CloseLog(); g_fpLog = fopen( "c:\\vmpi_service_install.log", "wt" ); } void AddToLog( const char *pMsg ) { if ( g_fpLog ) { fprintf( g_fpLog, "%s", pMsg ); } } SpewRetval_t MySpewOutputFunc( SpewType_t spewType, const tchar *pMsg ) { AddToLog( pMsg ); if ( spewType == SPEW_MESSAGE || spewType == SPEW_WARNING ) { // Format the message and send it to the control. CUtlVector msg; msg.SetSize( V_strlen( pMsg )*2 + 1 ); char *pOut = msg.Base(); const char *pIn = pMsg; while ( *pIn ) { if ( *pIn == '\n' ) { *pOut++ = '\r'; *pOut++ = '\n'; } else { *pOut++ = *pIn; } ++pIn; } *pOut = 0; int nLen = (int)SendMessage( g_hMessageControl, EM_GETLIMITTEXT, 0, 0 ); SendMessage( g_hMessageControl, EM_SETSEL, nLen, nLen ); SendMessage( g_hMessageControl, EM_REPLACESEL, FALSE, (LPARAM)msg.Base() ); } // Show a message box for warnings and errors. if ( spewType == SPEW_ERROR || spewType == SPEW_WARNING ) { if ( !g_bNoOutput ) AfxMessageBox( pMsg, MB_OK ); } if ( spewType == SPEW_ERROR ) { CloseLog(); TerminateProcess( GetCurrentProcess(), 2 ); } return SPEW_CONTINUE; } void ScanDirectory( const char *pDirName, CUtlVector &subDirs, CUtlVector &files ) { subDirs.Purge(); files.Purge(); char strPattern[MAX_PATH]; V_ComposeFileName( pDirName, "*.*", strPattern, sizeof( strPattern ) ); WIN32_FIND_DATA fileInfo; // File information HANDLE hFile = ::FindFirstFile( strPattern, &fileInfo ); if ( hFile == INVALID_HANDLE_VALUE ) return; do { if ( fileInfo.cFileName[0] == '.' ) continue; if ( fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) subDirs.AddToTail( fileInfo.cFileName ); else files.AddToTail( fileInfo.cFileName ); } while( ::FindNextFile(hFile, &fileInfo) ); ::FindClose( hFile ); } int DeleteDirectory( const char *pRootDir, bool bDeleteSubdirectories, char errorFile[MAX_PATH] ) { errorFile[0] = 0; CUtlVector subDirs, files; ScanDirectory( pRootDir, subDirs, files ); // First nuke any subdirectories. if ( bDeleteSubdirectories && !g_bReinstalling ) { for ( int i=0; i < subDirs.Count(); i++ ) { char fullName[MAX_PATH]; V_ComposeFileName( pRootDir, subDirs[i], fullName, sizeof( fullName ) ); // Delete subdirectory int iRC = DeleteDirectory( fullName, bDeleteSubdirectories, errorFile ); if ( iRC ) return iRC; } } for ( int i=0; i < files.Count(); i++ ) { char fullName[MAX_PATH]; V_ComposeFileName( pRootDir, files[i], fullName, sizeof( fullName ) ); // Set file attributes if ( !SetFileAttributes( fullName, FILE_ATTRIBUTE_NORMAL ) ) return GetLastError(); // Delete file if ( !DeleteFile( fullName ) ) { V_strncpy( errorFile, fullName, MAX_PATH ); return GetLastError(); } } if( !g_bReinstalling ) { // Set directory attributes if ( !SetFileAttributes( pRootDir, FILE_ATTRIBUTE_NORMAL ) ) return GetLastError(); // Delete directory if ( !RemoveDirectory( pRootDir ) ) return GetLastError(); } return 0; } bool CreateDirectory_R( const char *pDirName ) { char chPrevDir[MAX_PATH]; V_strncpy( chPrevDir, pDirName, sizeof( chPrevDir ) ); if ( V_StripLastDir( chPrevDir, sizeof( chPrevDir ) ) ) { if ( V_stricmp( chPrevDir, ".\\" ) != 0 && V_stricmp( chPrevDir, "./" ) != 0 ) if ( !CreateDirectory_R( chPrevDir ) ) return false; } if ( _access( pDirName, 0 ) == 0 ) return true; return CreateDirectory( pDirName, NULL ) || GetLastError() == ERROR_ALREADY_EXISTS; } bool SetupStartMenuSubFolderName( const char *pSubFolderName, char *pOut, int outLen ) { LPITEMIDLIST pidl; // Get a pointer to an item ID list that represents the path of a special folder HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidl); if ( hr != S_OK ) return false; // Convert the item ID list's binary representation into a file system path char szPath[_MAX_PATH]; BOOL f = SHGetPathFromIDList(pidl, szPath); // Free the LPITEMIDLIST they gave us. LPMALLOC pMalloc; hr = SHGetMalloc(&pMalloc); pMalloc->Free(pidl); pMalloc->Release(); if ( f ) { V_ComposeFileName( szPath, pSubFolderName, pOut, outLen ); return true; } else { return false; } } bool CreateStartMenuLink( const char *pSubFolderName, const char *pLinkName, const char *pLinkTarget, const char *pArguments ) { char fullFolderName[MAX_PATH]; if ( !SetupStartMenuSubFolderName( pSubFolderName, fullFolderName, sizeof( fullFolderName ) ) ) return false; // Create the folder if necessary. if ( !CreateDirectory_R( fullFolderName ) ) { Msg( "CreateStartMenuLink failed - can't create directory %s.\n", fullFolderName ); return false; } IShellLink* psl = NULL; // Get a pointer to the IShellLink interface. bool bRet = false; CoInitialize( NULL ); HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast(&psl)); if (SUCCEEDED(hres)) { psl->SetPath( pLinkTarget ); // Set the path to the shortcut target if ( pArguments ) psl->SetArguments( pArguments ); // Query IShellLink for the IPersistFile interface for saving //the shortcut in persistent storage. IPersistFile* ppf = NULL; hres = psl->QueryInterface( IID_IPersistFile, reinterpret_cast(&ppf) ); if (SUCCEEDED(hres)) { // Setup the filename for the link. char linkFilename[MAX_PATH]; V_ComposeFileName( fullFolderName, pLinkName, linkFilename, sizeof( linkFilename ) ); V_strncat( linkFilename, ".lnk", sizeof( linkFilename ) ); // Ensure that the string is ANSI. WCHAR wsz[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, linkFilename, -1, wsz, MAX_PATH); // Save the link by calling IPersistFile::Save. hres = ppf->Save( wsz, TRUE ); ppf->Release(); bRet = true; } psl->Release(); } CoUninitialize(); return bRet; } char* GetLastErrorString() { static char err[2048]; LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); strncpy( err, (char*)lpMsgBuf, sizeof( err ) ); LocalFree( lpMsgBuf ); err[ sizeof( err ) - 1 ] = 0; return err; } bool LaunchApp( char *pCommandLine, const char *pBaseDir ) { STARTUPINFO si; memset( &si, 0, sizeof( si ) ); si.cb = sizeof( si ); PROCESS_INFORMATION pi; memset( &pi, 0, sizeof( pi ) ); return CreateProcess( NULL, pCommandLine, NULL, NULL, FALSE, 0, NULL, pBaseDir, &si, &pi ) != 0; } bool StartVMPIServiceUI( const char *pInstallLocation ) { if ( g_bDontTouchUI ) { Msg( "StartVMPIServiceUI: Ignoring due to -DontTouchUI.\n" ); return true; } char cmdLine[MAX_PATH]; V_ComposeFileName( pInstallLocation, "vmpi_service_ui.exe", cmdLine, sizeof( cmdLine ) ); return LaunchApp( cmdLine, pInstallLocation ); } bool StartVMPIService( SC_HANDLE hSCManager ) { bool bRet = true; // First, get rid of an old service with the same name. SC_HANDLE hMyService = OpenService( hSCManager, VMPI_SERVICE_NAME_INTERNAL, SERVICE_START ); if ( hMyService ) { if ( StartService( hMyService, NULL, NULL ) ) { Msg( "Started!\n" ); } else { Error( "Can't start the service.\n" ); bRet = false; } } else { Error( "Can't open service: %s\n", VMPI_SERVICE_NAME_INTERNAL ); bRet = false; } CloseServiceHandle( hMyService ); return bRet; } bool StopRunningApp() { if ( g_bDontTouchUI ) { Msg( "StopRunningApp: -DontTouchUI was specified, so exiting before stopping the app.\n" ); return true; } // Send the ISocket *pSocket = CreateIPSocket(); if ( pSocket ) { if ( pSocket->BindToAny( 0 ) ) { CUtlVector protocolVersions; protocolVersions.AddToTail( VMPI_PROTOCOL_VERSION ); if ( VMPI_PROTOCOL_VERSION == 5 ) protocolVersions.AddToTail( 4 ); // We want this installer to kill the previous services too. for ( int iProtocolVersion=0; iProtocolVersion < protocolVersions.Count(); iProtocolVersion++ ) { char cPacket[4] = { protocolVersions[iProtocolVersion], VMPI_PASSWORD_OVERRIDE, // (force it to accept this message). 0, VMPI_STOP_SERVICE }; CIPAddr addr( 127, 0, 0, 1, 0 ); for ( int iPort=VMPI_SERVICE_PORT; iPort <= VMPI_LAST_SERVICE_PORT; iPort++ ) { addr.port = iPort; pSocket->SendTo( &addr, cPacket, sizeof( cPacket ) ); } } // Give it a sec to get the message and shutdown in case we're restarting. Sleep( 2000 ); // This is the overkill method. If it didn't shutdown gracefully, kill it. HMODULE hInst = LoadLibrary( "psapi.dll" ); if ( hInst ) { typedef BOOL (WINAPI *EnumProcessesFn)(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded); typedef BOOL (WINAPI *EnumProcessModulesFn)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); typedef DWORD (WINAPI *GetModuleBaseNameFn)( HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize ); EnumProcessesFn EnumProcesses = (EnumProcessesFn)GetProcAddress( hInst, "EnumProcesses" ); EnumProcessModulesFn EnumProcessModules = (EnumProcessModulesFn)GetProcAddress( hInst, "EnumProcessModules" ); GetModuleBaseNameFn GetModuleBaseName = (GetModuleBaseNameFn)GetProcAddress( hInst, "GetModuleBaseNameA" ); if ( EnumProcessModules && EnumProcesses ) { // Now just to make sure, kill the processes we're interested in. DWORD procIDs[1024]; DWORD nBytes; if ( EnumProcesses( procIDs, sizeof( procIDs ), &nBytes ) ) { DWORD nProcs = nBytes / sizeof( procIDs[0] ); for ( DWORD i=0; i < nProcs; i++ ) { HANDLE hProc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, procIDs[i] ); if ( hProc ) { HMODULE hModules[1024]; if ( EnumProcessModules( hProc, hModules, sizeof( hModules ), &nBytes ) ) { DWORD nModules = nBytes / sizeof( hModules[0] ); for ( DWORD iModule=0; iModule < nModules; iModule++ ) { char filename[512]; if ( GetModuleBaseName( hProc, hModules[iModule], filename, sizeof( filename ) ) ) { if ( Q_stristr( filename, "vmpi_service.exe" ) || Q_stristr( filename, "vmpi_service_ui.exe" ) ) { TerminateProcess( hProc, 1 ); CloseHandle( hProc ); hProc = NULL; break; } } } } CloseHandle( hProc ); } } } } FreeLibrary( hInst ); } } pSocket->Release(); } return true; } bool StopOrDeleteService( SC_HANDLE hSCManager, bool bDelete ) { bool bRet = true; // First, get rid of an old service with the same name. SC_HANDLE hOldService = OpenService( hSCManager, VMPI_SERVICE_NAME_INTERNAL, SERVICE_STOP | DELETE ); if ( hOldService ) { // Stop the service. Msg( "Found the service already running.\n" ); Msg( "Stopping service...\n" ); SERVICE_STATUS status; ControlService( hOldService, SERVICE_CONTROL_STOP, &status ); if ( bDelete ) { Msg( "Deleting service...\n" ); bool bExitedNicely = false; DWORD startTime = GetTickCount(); while ( 1 ) { BOOL bRet = DeleteService( hOldService ); if ( !bRet || bRet == ERROR_SERVICE_MARKED_FOR_DELETE ) { Msg( "Deleted old service.\n" ); bExitedNicely = true; break; } // Wait for the service to stop for 8 seconds. if ( GetTickCount() - startTime > 8000 ) break; } if ( !bExitedNicely ) { Error( "Couldn't delete the old '%s' service! Error: %s.\n", VMPI_SERVICE_NAME, GetLastErrorString() ); bRet = false; } } CloseServiceHandle( hOldService ); } return bRet; } bool GetExistingInstallationLocation( CString &strInstallLocation ) { char buf[1024]; DWORD bufSize = sizeof( buf ); DWORD dwType; if ( RegQueryValueEx( g_hVMPIKey, SERVICE_INSTALL_LOCATION_KEY, NULL, &dwType, (LPBYTE)buf, &bufSize ) == ERROR_SUCCESS ) { if ( dwType == REG_SZ ) { strInstallLocation = buf; return true; } } return false; } void RemoveRegistryKeys() { // Delete the run values (that tells it to run the app when the user logs in). HKEY hKey = NULL; RegCreateKey( HKEY_LOCAL_MACHINE, HLKM_WINDOWS_RUN_KEY, &hKey ); RegDeleteValue( hKey, VMPI_SERVICE_VALUE_NAME ); RegDeleteValue( hKey, VMPI_SERVICE_UI_VALUE_NAME ); // Get rid of the "InstallLocation" value. RegDeleteValue( g_hVMPIKey, SERVICE_INSTALL_LOCATION_KEY ); } bool IsAnInstallFile( const char *pName ) { for ( int i=0; i < ARRAYSIZE( g_pInstallFiles ); i++ ) { if ( V_stricmp( g_pInstallFiles[i], pName ) == 0 ) return true; } return false; } bool AnyNonInstallFilesInDirectory( const char *strInstallLocation ) { char searchStr[MAX_PATH]; V_ComposeFileName( strInstallLocation, "*.*", searchStr, sizeof( searchStr ) ); _finddata_t data; long handle = _findfirst( searchStr, &data ); if ( handle != -1 ) { do { if ( data.name[0] == '.' || (data.attrib & _A_SUBDIR) != 0 ) continue; if ( !IsAnInstallFile( data.name ) ) return true; } while( _findnext( handle, &data ) == 0 ); _findclose( handle ); } return false; } ///////////////////////////////////////////////////////////////////////////// // CServiceInstallDlg dialog CServiceInstallDlg::CServiceInstallDlg(CWnd* pParent /*=NULL*/) : CDialog(CServiceInstallDlg::IDD, pParent) { //{{AFX_DATA_INIT(CServiceInstallDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } CServiceInstallDlg::~CServiceInstallDlg() { } void CServiceInstallDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CServiceInstallDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CServiceInstallDlg, CDialog) //{{AFX_MSG_MAP(CServiceInstallDlg) ON_BN_CLICKED(IDC_CANCEL_BUTTON, OnCancel) ON_BN_CLICKED(IDC_INSTALL_BUTTON, OnInstall) ON_BN_CLICKED(IDC_UNINSTALL_BUTTON2, OnUninstall) ON_BN_CLICKED(IDC_START_EXISTING_BUTTON, OnStartExisting) ON_BN_CLICKED(IDC_STOP_EXISTING_BUTTON, OnStopExisting) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CServiceInstallDlg message handlers const char* FindArg( const char *pArgName, const char *pDefault="" ) { for ( int i=1; i < __argc; i++ ) { if ( Q_stricmp( pArgName, __argv[i] ) == 0 ) { if ( (i+1) < __argc ) return __argv[i+1]; else return pDefault; } } return NULL; } BOOL CServiceInstallDlg::OnInitDialog() { CDialog::OnInitDialog(); HICON hIcon = LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_MAINFRAME ) ); SetIcon( hIcon, true ); OpenLog(); // Setup the registry key for the install location. if ( RegCreateKey( HKEY_LOCAL_MACHINE, VMPI_SERVICE_KEY, &g_hVMPIKey ) != ERROR_SUCCESS ) { Error( "Can't open registry key: %s.", VMPI_SERVICE_KEY ); return FALSE; } VerifyInstallFiles(); g_hMessageControl = ::GetDlgItem( GetSafeHwnd(), IDC_TEXTOUTPUT ); SpewOutputFunc( MySpewOutputFunc ); // Init the service manager. m_hSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( !m_hSCManager ) { Error( "OpenSCManager failed (%s)!\n", GetLastErrorString() ); return FALSE; } // See if there is a previous installation. CString strInstallLocation; if ( GetExistingInstallationLocation( strInstallLocation ) ) SetDlgItemText( IDC_INSTALL_LOCATION, strInstallLocation ); else SetDlgItemText( IDC_INSTALL_LOCATION, DEFAULT_INSTALL_LOCATION ); // Now, if they passed in a command line option . if ( FindArg( __argc, __argv, "-install_quiet" ) ) { g_bReinstalling = true; g_bNoOutput = true; g_bDontTouchUI = (FindArg( __argc, __argv, "-DontTouchUI", NULL ) != 0); OnInstall(); EndDialog( 0 ); } else if ( FindArg( __argc, __argv, "-uninstall_quiet" ) ) { g_bNoOutput = true; DoUninstall( false ); EndDialog( 0 ); } else if ( FindArg( __argc, __argv, "-start" ) ) { OnStartExisting(); } else if ( FindArg( __argc, __argv, "-stop" ) ) { OnStopExisting(); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CServiceInstallDlg::OnCancel(void) { EndDialog( 1 ); } // This function registers the service with the service manager. bool InstallService( SC_HANDLE hSCManager, const char *pBaseDir ) { char filename[512], uiFilename[512]; V_ComposeFileName( pBaseDir, "vmpi_service.exe", filename, sizeof( filename ) ); V_ComposeFileName( pBaseDir, "vmpi_service_ui.exe", uiFilename, sizeof( uiFilename ) ); // Try a to reinstall the service for up to 5 seconds. Msg( "Creating new service...\n" ); SC_HANDLE hMyService = NULL; DWORD startTime = GetTickCount(); while ( GetTickCount() - startTime < 5000 ) { // Now reinstall it. hMyService = CreateService( hSCManager, // Service Control Manager database. VMPI_SERVICE_NAME_INTERNAL, // Service name. VMPI_SERVICE_NAME, // Display name. SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, // Start automatically on system bootup. SERVICE_ERROR_NORMAL, filename, // Executable to register for the service. NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // account NULL // password ); if ( hMyService ) break; else Sleep( 300 ); } if ( !hMyService ) { Warning( "CreateService failed (%s)!\n", GetLastErrorString() ); CloseServiceHandle( hSCManager ); return false; } // Now setup the UI executable to run when their system starts. HKEY hUIKey = NULL; RegCreateKey( HKEY_LOCAL_MACHINE, HLKM_WINDOWS_RUN_KEY, &hUIKey ); if ( !hUIKey || RegSetValueEx( hUIKey, VMPI_SERVICE_UI_VALUE_NAME, 0, REG_SZ, (unsigned char*)uiFilename, strlen( uiFilename) + 1 ) != ERROR_SUCCESS ) { Warning( "Can't install registry key for %s\n", uiFilename ); return false; } CloseServiceHandle( hMyService ); return true; } void SetupStartMenuLinks( const char *pInstallerFilename ) { CreateStartMenuLink( "Valve\\VMPI", "Start VMPI Service", pInstallerFilename, "-start" ); CreateStartMenuLink( "Valve\\VMPI", "Stop VMPI Service", pInstallerFilename, "-stop" ); CreateStartMenuLink( "Valve\\VMPI", "Uninstall VMPI", pInstallerFilename, NULL ); } void RemoveStartMenuLinks() { char fullFolderName[MAX_PATH]; if ( !SetupStartMenuSubFolderName( "Valve\\VMPI", fullFolderName, sizeof( fullFolderName ) ) ) return; char errorFile[MAX_PATH]; if ( !DeleteDirectory( fullFolderName, true, errorFile ) ) { Msg( "Unable to remove Start Menu items in %s.\n", fullFolderName ); } } void CServiceInstallDlg::OnInstall() { // Get the install location. Msg( "Verifying install location.\n" ); CString strInstallLocation; if ( !GetDlgItemText( IDC_INSTALL_LOCATION, strInstallLocation ) ) { Error( "Can't get install location." ); return; } if ( strchr( strInstallLocation, ':' ) == NULL ) { Warning( "Install location must be an absolute path (include a colon)." ); return; } // Stop the existing service. if ( !DoUninstall( false ) ) return; // Create the directory. Msg( "Creating install directory %s.\n", strInstallLocation ); if ( !CreateDirectory_R( strInstallLocation ) ) { Warning( "Unable to create directory: %s.", (const char*)strInstallLocation ); return; } // Copy the files down. Msg( "Copying files.\n" ); char chDir[MAX_PATH]; GetModuleFileName( NULL, chDir, sizeof( chDir ) ); V_StripFilename( chDir ); for ( int i=0; i < ARRAYSIZE( g_pInstallFiles ); i++ ) { char srcFilename[MAX_PATH], destFilename[MAX_PATH]; V_ComposeFileName( chDir, g_pInstallFiles[i], srcFilename, sizeof( srcFilename ) ); V_ComposeFileName( strInstallLocation, g_pInstallFiles[i], destFilename, sizeof( destFilename ) ); if ( !CopyFile( srcFilename, destFilename, FALSE ) ) { Sleep( 2000 ); if ( !CopyFile( srcFilename, destFilename, FALSE ) ) { Error( "CopyFile() failed.\nSrc: %s\nDest: %s\n%s", srcFilename, destFilename, GetLastErrorString() ); return; } } } // Register the service. if ( !InstallService( m_hSCManager, strInstallLocation ) ) return; // Write the new location to the registry. Msg( "Updating registry.\n" ); if ( RegSetValueEx( g_hVMPIKey, SERVICE_INSTALL_LOCATION_KEY, 0, REG_SZ, (BYTE*)(const char*)strInstallLocation, V_strlen( strInstallLocation ) + 1 ) != ERROR_SUCCESS ) { Error( "RegSetValueEx( %s, %s ) failed.", SERVICE_INSTALL_LOCATION_KEY, (const char*)strInstallLocation ); return; } // Setup start menu links. char installerFilename[MAX_PATH]; V_ComposeFileName( strInstallLocation, "vmpi_service_install.exe", installerFilename, sizeof( installerFilename ) ); SetupStartMenuLinks( installerFilename ); // Start the new service. Msg( "Starting new service.\n" ); if ( DoStartExisting() ) { Warning( "Installed successfully!" ); } } bool CServiceInstallDlg::DoUninstall( bool bShowMessage ) { // Figure out where to uninstall from. CString strInstallLocation; if ( !GetDlgItemText( IDC_INSTALL_LOCATION, strInstallLocation ) ) { Error( "Can't get install location." ); return false; } if ( _access( strInstallLocation, 0 ) == 0 && !g_bNoOutput ) { // Don't ask if they care if we delete all the files in that directory if the only exes in there are the install exes. if ( AnyNonInstallFilesInDirectory( strInstallLocation ) ) { char str[512]; V_snprintf( str, sizeof( str ), "Warning: this will delete all files under this directory: \n%s\nContinue?", strInstallLocation ); if ( AfxMessageBox( str, MB_YESNO ) != IDYES ) return false; } } // Stop both the service and the win app. bool bDone = StopRunningApp() && StopOrDeleteService( m_hSCManager, true ); if ( !bDone ) return false; bool bSuccess = true; RemoveRegistryKeys(); char errorFile[MAX_PATH]; if ( !NukeDirectory( strInstallLocation, errorFile ) ) { // When reinstalling, the service may not be done exiting, so give it a sec. Sleep( 2000 ); if ( !NukeDirectory( strInstallLocation, errorFile ) ) { if ( errorFile[0] ) Msg( "NukeDirectory( %s ) failed.\nError on file: %s\n", strInstallLocation, errorFile ); else Msg( "NukeDirectory( %s ) failed.\n", strInstallLocation ); Msg( "Uninstall complete, but files are left over in %s.\n", strInstallLocation ); bSuccess = false; } } RemoveStartMenuLinks(); if ( bShowMessage && bSuccess ) AfxMessageBox( "Uninstall successful." ); return true; } void CServiceInstallDlg::OnUninstall() { DoUninstall( true ); } void CServiceInstallDlg::OnStartExisting() { if ( DoStartExisting() ) AfxMessageBox( "Started successfully." ); } bool CServiceInstallDlg::DoStartExisting() { StopRunningApp(); StopOrDeleteService( m_hSCManager, false ); CString strInstallLocation; if ( !GetExistingInstallationLocation( strInstallLocation ) ) { Error( "The VMPI service is not installed." ); return false; } if ( StartVMPIService( m_hSCManager ) ) { return StartVMPIServiceUI( strInstallLocation ); } else { return false; } } void CServiceInstallDlg::OnStopExisting() { // Stop the app but don't delete it. bool bDone = StopRunningApp() && StopOrDeleteService( m_hSCManager, false ); if ( bDone ) { AfxMessageBox( "Service successfully stopped." ); } } bool CServiceInstallDlg::NukeDirectory( const char *pDir, char errorFile[MAX_PATH] ) { // If the directory doesn't exist anyways, then return true.. if ( _access( pDir, 0 ) != 0 ) return true; return DeleteDirectory( pDir, true, errorFile ) == 0; } void CServiceInstallDlg::VerifyInstallFiles() { char chDir[MAX_PATH]; GetModuleFileName( NULL, chDir, sizeof( chDir ) ); V_StripFilename( chDir ); for ( int i=0; i < ARRAYSIZE( g_pInstallFiles ); i++ ) { char filename[MAX_PATH]; V_ComposeFileName( chDir, g_pInstallFiles[i], filename, sizeof( filename ) ); if ( _access( filename, 0 ) != 0 ) { char szErrorMessage[MAX_PATH]; V_snprintf( szErrorMessage, sizeof( szErrorMessage ), "Required installation file missing: %s", filename ); AfxMessageBox( szErrorMessage ); return; } } }