void CVMPIServiceConnMgr::HandlePacket( const char *pData, int len )
{
	switch( pData[0] )
	{
		case VMPI_KILL_PROCESS:
		{
			HandlePacket_KILL_PROCESS( NULL );
		}
		break;
		
		case VMPI_SERVICE_DISABLE:
		{
			KillRunningProcess( "Got a VMPI_SERVICE_DISABLE packet", true );
			SetAppState( VMPI_SERVICE_STATE_DISABLED );
			SaveStateToRegistry();
		}
		break;

		case VMPI_SERVICE_ENABLE:
		{
			if ( g_iCurState == VMPI_SERVICE_STATE_DISABLED )
			{
				SetAppState( VMPI_SERVICE_STATE_IDLE );
			}
			SaveStateToRegistry();
		}
		break;

		case VMPI_SERVICE_UPDATE_PASSWORD:
		{
			const char *pStr = pData + 1;
			SetPassword( pStr );
			
			// Send out the new state.
			SendCurStateTo( -1 );
		}
		break;

		case VMPI_SERVICE_SCREENSAVER_MODE:
		{
			g_bScreensaverMode = (pData[1] != 0);
			SendCurStateTo( -1 );
			SaveStateToRegistry();
		}
		break;

		case VMPI_SERVICE_EXIT:
		{
			Msg( "Got a VMPI_SERVICE_EXIT packet.\n ");
			ServiceHelpers_ExitEarly();
		}
		break;
	}
}
void HandlePacket_STOP_SERVICE( bf_read &buf, const CIPAddr &ipFrom )
{
	Msg( "Got a STOP_SERVICE packet. Shutting down...\n" );

	CWaitTimer timer( 1 );
	while ( 1 )
	{
		AddServicesBrowserIP( ipFrom );
		SendStateToServicesBrowsers();

		if ( timer.ShouldKeepWaiting() )
			Sleep( 200 );
		else
			break;
	}

	StopUI();
	ServiceHelpers_ExitEarly();
}
void WINAPI MyServiceCtrlHandler( DWORD Opcode )
{ 
    DWORD status; 
 
    switch(Opcode) 
    { 
        case SERVICE_CONTROL_STOP: 
			// Do whatever it takes to stop here. 
			ServiceHelpers_ExitEarly();

            MyServiceStatus.dwWin32ExitCode = 0; 
            MyServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
 
            if ( !SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus) )
            { 
                status = GetLastError(); 
                Msg( "[MY_SERVICE] SetServiceStatus error %ld\n", status ); 
            } 
 
            Msg( "[MY_SERVICE] Leaving MyService \n", 0 ); 
            return; 
 
        case SERVICE_CONTROL_INTERROGATE: 
			// Fall through to send current status. 
            break; 
 
        default: 
            Msg("[MY_SERVICE] Unrecognized opcode %ld\n", Opcode ); 
    } 
 
    // Send current status. 
    if ( !SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus ) )
    { 
        status = GetLastError(); 
        Msg( "[MY_SERVICE] SetServiceStatus error %ld\n", status ); 
    } 
}
// Returns true if the service was just patched and should exit.
bool CheckDownloaderFinished()
{
	if ( !g_Waiting_hProcess )
		return false;
	
	// Check if the downloader has timed out and kill it if necessary.
	if ( Plat_FloatTime() - g_Waiting_StartTime > MAX_DOWNLOADER_TIME_ALLOWED )
	{
		TerminateProcess( g_Waiting_hProcess, 1 );
		CloseHandle( g_Waiting_hProcess );
		g_Waiting_hProcess = NULL;
		return false;
	}

	// Check if it's done.
	if ( WaitForSingleObject( g_Waiting_hProcess, 0 ) != WAIT_OBJECT_0 )
		return false;

	CloseHandle( g_Waiting_hProcess );
	g_Waiting_hProcess = NULL;

	// Ok, it's done. Did it finish successfully?
	char testFilename[MAX_PATH];
	V_ComposeFileName( g_FileCachePath, "ReadyToGo.txt", testFilename, sizeof( testFilename ) );
	if ( _access( testFilename, 0 ) != 0 )
		return false;
		
	// Ok, the downloader finished successfully. Run the worker app.
	if ( g_bSuperDebugMode )
		AdjustSuperDebugArgs( g_Waiting_Argv );

	// Figure out the name of the master machine.
	V_strncpy( g_CurMasterName, "<unknown>", sizeof( g_CurMasterName ) );
	for ( int iArg=1; iArg < g_Waiting_Argv.Count()-1; iArg++ )
	{
		if ( stricmp( g_Waiting_Argv[iArg], "-mpi_MasterName" ) == 0 )
		{
			Q_strncpy( g_CurMasterName, g_Waiting_Argv[iArg+1], sizeof( g_CurMasterName ) );
		}
	}

	char DLLFilename[MAX_PATH];
	if ( FindArg( __argc, __argv, "-TryDLLMode" ) && 
		g_RunMode == RUNMODE_CONSOLE && 
		GetDLLFilename( g_Waiting_Argv, DLLFilename ) &&
		!g_Waiting_bPatching )
	{
		// This is just a helper for debugging. If it's VRAD, we can run it
		// in-process as a DLL instead of running it as a separate EXE.
		RunInDLL( DLLFilename, g_Waiting_Argv );
	}
	else
	{
		// Run the (hopefully!) MPI app they specified.
		RunProcessAtCommandLine( g_Waiting_Argv, g_Waiting_bShowAppWindow, g_Waiting_bPatching, g_Waiting_Priority );
		
		if ( g_Waiting_bPatching )
		{														
			// Tell any currently-running UI apps to patch themselves and quit ASAP so the installer can finish.
			SendPatchCommandToUIs( g_dwRunningProcessId );

			ResumeThread( g_hRunningThread ); // We started the installer suspended so we could make sure we'd send out the patch command.
			
			// We just ran the installer, but let's forget about it, otherwise we'll kill its process when we exit here.
			CloseHandle( g_hRunningProcess );
			CloseHandle( g_hRunningThread ) ;
			g_hRunningProcess = g_hRunningThread = NULL;
			g_RunningProcess_ExeName[0] = 0;
			g_RunningProcess_MapName[0] = 0;

			ServiceHelpers_ExitEarly();
			return true;
		}
	}
	
	g_Waiting_Argv.PurgeAndDeleteElements();
	return false;
}