summaryrefslogtreecommitdiff
path: root/utils/vmpi/vmpi_service_install
diff options
context:
space:
mode:
Diffstat (limited to 'utils/vmpi/vmpi_service_install')
-rw-r--r--utils/vmpi/vmpi_service_install/ServiceInstallDlg.cpp1043
-rw-r--r--utils/vmpi/vmpi_service_install/ServiceInstallDlg.h72
-rw-r--r--utils/vmpi/vmpi_service_install/StdAfx.cpp15
-rw-r--r--utils/vmpi/vmpi_service_install/StdAfx.h41
-rw-r--r--utils/vmpi/vmpi_service_install/res/vmpi.icobin0 -> 3310 bytes
-rw-r--r--utils/vmpi/vmpi_service_install/res/vmpi_service_install.icobin0 -> 1078 bytes
-rw-r--r--utils/vmpi/vmpi_service_install/res/vmpi_service_install.rc213
-rw-r--r--utils/vmpi/vmpi_service_install/resource.h27
-rw-r--r--utils/vmpi/vmpi_service_install/vmpi_service_install.cpp75
-rw-r--r--utils/vmpi/vmpi_service_install/vmpi_service_install.h56
-rw-r--r--utils/vmpi/vmpi_service_install/vmpi_service_install.rc173
-rw-r--r--utils/vmpi/vmpi_service_install/vmpi_service_install.vpc87
12 files changed, 1602 insertions, 0 deletions
diff --git a/utils/vmpi/vmpi_service_install/ServiceInstallDlg.cpp b/utils/vmpi/vmpi_service_install/ServiceInstallDlg.cpp
new file mode 100644
index 0000000..6a22176
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/ServiceInstallDlg.cpp
@@ -0,0 +1,1043 @@
+//========= 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<char> 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<CString> &subDirs, CUtlVector<CString> &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<CString> 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<void**>(&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<void**>(&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<char> 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;
+ }
+ }
+}
+
diff --git a/utils/vmpi/vmpi_service_install/ServiceInstallDlg.h b/utils/vmpi/vmpi_service_install/ServiceInstallDlg.h
new file mode 100644
index 0000000..01dc433
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/ServiceInstallDlg.h
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#if !defined(AFX_SERVICEINSTALLDLG_H__761BDEEF_D549_4F10_817C_1C1FAF9FCA47__INCLUDED_)
+#define AFX_SERVICEINSTALLDLG_H__761BDEEF_D549_4F10_817C_1C1FAF9FCA47__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// JobWatchDlg.h : header file
+//
+
+
+#include "resource.h"
+#include "tier1/utlvector.h"
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CJobWatchDlg dialog
+
+class CServiceInstallDlg : public CDialog
+{
+// Construction
+public:
+ CServiceInstallDlg( CWnd* pParent = NULL); // standard constructor
+ virtual ~CServiceInstallDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CJobWatchDlg)
+ enum { IDD = IDD_SERVICE_INSTALL_DIALOG};
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CJobWatchDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ SC_HANDLE m_hSCManager;
+
+ void VerifyInstallFiles();
+
+ bool DoStartExisting();
+ bool NukeDirectory( const char *pDir, char errorFile[MAX_PATH] );
+ bool DoUninstall( bool bShowMessage );
+
+ // Generated message map functions
+ //{{AFX_MSG(CJobWatchDlg)
+ virtual BOOL OnInitDialog();
+ virtual void OnCancel();
+ virtual void OnInstall();
+ virtual void OnUninstall();
+ virtual void OnStartExisting();
+ virtual void OnStopExisting();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SERVICEINSTALLDLG_H__761BDEEF_D549_4F10_817C_1C1FAF9FCA47__INCLUDED_)
diff --git a/utils/vmpi/vmpi_service_install/StdAfx.cpp b/utils/vmpi/vmpi_service_install/StdAfx.cpp
new file mode 100644
index 0000000..e10b100
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/StdAfx.cpp
@@ -0,0 +1,15 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// stdafx.cpp : source file that includes just the standard includes
+// vmpi_service_install.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/utils/vmpi/vmpi_service_install/StdAfx.h b/utils/vmpi/vmpi_service_install/StdAfx.h
new file mode 100644
index 0000000..d243112
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/StdAfx.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__E8FBDA6A_CE57_4416_8329_90155CD6CEC3__INCLUDED_)
+#define AFX_STDAFX_H__E8FBDA6A_CE57_4416_8329_90155CD6CEC3__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include "tier0/basetypes.h"
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#include <afxdisp.h> // MFC Automation classes
+#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <winsvc.h>
+#include <io.h>
+
+#include "iphelpers.h"
+#include "vmpi.h"
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__E8FBDA6A_CE57_4416_8329_90155CD6CEC3__INCLUDED_)
diff --git a/utils/vmpi/vmpi_service_install/res/vmpi.ico b/utils/vmpi/vmpi_service_install/res/vmpi.ico
new file mode 100644
index 0000000..24dc2cf
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/res/vmpi.ico
Binary files differ
diff --git a/utils/vmpi/vmpi_service_install/res/vmpi_service_install.ico b/utils/vmpi/vmpi_service_install/res/vmpi_service_install.ico
new file mode 100644
index 0000000..7eef0bc
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/res/vmpi_service_install.ico
Binary files differ
diff --git a/utils/vmpi/vmpi_service_install/res/vmpi_service_install.rc2 b/utils/vmpi/vmpi_service_install/res/vmpi_service_install.rc2
new file mode 100644
index 0000000..6e93fd0
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/res/vmpi_service_install.rc2
@@ -0,0 +1,13 @@
+//
+// VMPI_BROWSER_JOB_WATCH.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/utils/vmpi/vmpi_service_install/resource.h b/utils/vmpi/vmpi_service_install/resource.h
new file mode 100644
index 0000000..9330dcb
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/resource.h
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by vmpi_service_install.rc
+//
+#define IDD_SERVICE_INSTALL_DIALOG 102
+#define IDR_MAINFRAME 128
+#define IDD_SERVICE_INSTALL 135
+#define IDC_TEXTOUTPUT 200
+#define IDC_COMMAND_LINE 201
+#define IDC_INSTALL_LOCATION 201
+#define IDC_INSTALL_BUTTON 1011
+#define IDC_CANCEL_BUTTON 1012
+#define IDC_UNINSTALL_BUTTON2 1013
+#define IDC_START_EXISTING_BUTTON 1014
+#define IDC_STOP_EXISTING_BUTTON 1015
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 131
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1012
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/utils/vmpi/vmpi_service_install/vmpi_service_install.cpp b/utils/vmpi/vmpi_service_install/vmpi_service_install.cpp
new file mode 100644
index 0000000..f366efa
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/vmpi_service_install.cpp
@@ -0,0 +1,75 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// vmpi_browser_job_watch.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "vmpi_service_install.h"
+#include "ServiceInstallDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CServiceInstallApp
+
+BEGIN_MESSAGE_MAP(CServiceInstallApp, CWinApp)
+ //{{AFX_MSG_MAP(CServiceInstallApp)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG
+ ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CServiceInstallApp construction
+
+CServiceInstallApp::CServiceInstallApp()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CServiceInstallApp object
+
+CServiceInstallApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CServiceInstallApp initialization
+
+BOOL CServiceInstallApp::InitInstance()
+{
+ AfxEnableControlContainer();
+
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need.
+
+ CServiceInstallDlg dlg;
+ m_pMainWnd = &dlg;
+ int nResponse = dlg.DoModal();
+ if (nResponse == IDOK)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with OK
+ }
+ else if (nResponse == IDCANCEL)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with Cancel
+ }
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
diff --git a/utils/vmpi/vmpi_service_install/vmpi_service_install.h b/utils/vmpi/vmpi_service_install/vmpi_service_install.h
new file mode 100644
index 0000000..e29f338
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/vmpi_service_install.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// vmpi_browser_job_watch.h : main header file for the VMPI_BROWSER_JOB_WATCH application
+//
+
+#if !defined(AFX_VMPI_SERVICE_INSTALL_H__1DF22047_F615_4799_913A_222E3701BE5E__INCLUDED_)
+#define AFX_VMPI_SERVICE_INSTALL_H__1DF22047_F615_4799_913A_222E3701BE5E__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CVMPIBrowserJobWatchApp:
+// See vmpi_browser_job_watch.cpp for the implementation of this class
+//
+
+class CServiceInstallApp : public CWinApp
+{
+public:
+ CServiceInstallApp();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CVMPIBrowserJobWatchApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CVMPIBrowserJobWatchApp)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_VMPI_SERVICE_INSTALL_H__1DF22047_F615_4799_913A_222E3701BE5E__INCLUDED_)
diff --git a/utils/vmpi/vmpi_service_install/vmpi_service_install.rc b/utils/vmpi/vmpi_service_install/vmpi_service_install.rc
new file mode 100644
index 0000000..f9d59aa
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/vmpi_service_install.rc
@@ -0,0 +1,173 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif //_WIN32\r\n"
+ "#include ""res\\vmpi_service_install.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON "res\\vmpi.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "FileDescription", "vmpi_service_install MFC Application"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "vmpi_service_install"
+ VALUE "LegalCopyright", "Copyright (C) 2003"
+ VALUE "OriginalFilename", "vmpi_service_install.EXE"
+ VALUE "ProductName", "vmpi_service_install Application"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SERVICE_INSTALL_DIALOG DIALOGEX 0, 0, 467, 366
+STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "VMPI Service Installer"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_INSTALL_LOCATION,69,52,388,14,ES_AUTOHSCROLL
+ PUSHBUTTON "&Install / Update",IDC_INSTALL_BUTTON,9,78,107,14
+ PUSHBUTTON "&Uninstall",IDC_UNINSTALL_BUTTON2,9,103,50,14
+ PUSHBUTTON "&Start Existing",IDC_START_EXISTING_BUTTON,66,103,50,14
+ PUSHBUTTON "S&top Existing",IDC_STOP_EXISTING_BUTTON,123,103,50,14
+ PUSHBUTTON "&Quit",IDC_CANCEL_BUTTON,180,103,50,14
+ EDITTEXT IDC_TEXTOUTPUT,9,132,448,224,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL
+ LTEXT "Install Directory:",IDC_STATIC,9,55,51,8
+ LTEXT "This application will install the VMPI service onto your local machine.\nPlease enter a location to install it and click the Install button.",IDC_STATIC,15,9,442,36
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SERVICE_INSTALL_DIALOG, DIALOG
+ BEGIN
+ VERTGUIDE, 9
+ VERTGUIDE, 457
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif //_WIN32
+#include "res\vmpi_service_install.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/utils/vmpi/vmpi_service_install/vmpi_service_install.vpc b/utils/vmpi/vmpi_service_install/vmpi_service_install.vpc
new file mode 100644
index 0000000..2c40ddb
--- /dev/null
+++ b/utils/vmpi/vmpi_service_install/vmpi_service_install.vpc
@@ -0,0 +1,87 @@
+//-----------------------------------------------------------------------------
+// VMPI_SERVICE_INSTALL.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+$Macro OUTBINNAME "vmpi_service_install"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc"
+
+$Configuration "Debug"
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\,..\..\common,..\..\..\public"
+ $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;WINVER=0x400"
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $Create/UsePCHThroughFile "stdafx.h"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "nafxcwd.lib"
+ $IgnoreSpecificLibrary "nafxcw.lib libcmt.lib libcmtd.lib"
+ }
+}
+
+$Configuration "Release"
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\,..\..\common,..\..\..\public"
+ $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;WINVER=0x400"
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $Create/UsePCHThroughFile "stdafx.h"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "nafxcw.lib libcmt.lib"
+ $IgnoreSpecificLibrary "nafxcwd.lib libcmtd.lib"
+ }
+}
+
+$Project "Vmpi_service_install"
+{
+ $Folder "Source Files"
+ {
+ -$File "$SRCDIR\public\tier0\memoverride.cpp"
+
+ $File "StdAfx.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
+ }
+ }
+ }
+
+ $File "ServiceInstallDlg.cpp"
+ $File "vmpi_service_install.cpp"
+ $File "vmpi_service_install.rc"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "ServiceInstallDlg.h"
+ $File "Resource.h"
+ $File "StdAfx.h"
+ $File "vmpi_service_install.h"
+ }
+
+ $Folder "Resource Files"
+ {
+ $File "res\vmpi_service_install.ico"
+ $File "res\vmpi_service_install.rc2"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $DynamicFile "$SRCDIR\lib\public\vmpi.lib"
+ }
+}