summaryrefslogtreecommitdiff
path: root/utils/xbox/vxconsole/local_cmds.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/xbox/vxconsole/local_cmds.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/xbox/vxconsole/local_cmds.cpp')
-rw-r--r--utils/xbox/vxconsole/local_cmds.cpp1307
1 files changed, 1307 insertions, 0 deletions
diff --git a/utils/xbox/vxconsole/local_cmds.cpp b/utils/xbox/vxconsole/local_cmds.cpp
new file mode 100644
index 0000000..05e5cdb
--- /dev/null
+++ b/utils/xbox/vxconsole/local_cmds.cpp
@@ -0,0 +1,1307 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// LOCAL_CMDS.CPP
+//
+// Local commands ( *xxxx ) executed by this application.
+//=====================================================================================//
+#include "vxconsole.h"
+
+localCommand_t g_localCommands[] =
+{
+ // Command name, Flags Handler Help string
+ // console commands
+ { "*cls", FN_CONSOLE, lc_cls, ": Clear the screen" },
+ { "*connect", FN_CONSOLE, lc_autoConnect, ": Connect and listen until successful" },
+ { "*disconnect", FN_CONSOLE, lc_disconnect, ": Terminate Debug Console session" },
+ { "*help", FN_CONSOLE, lc_help, "[command] : List commands/usage" },
+ { "*quit", FN_CONSOLE, lc_quit, ": Terminate console" },
+ { "*run", FN_XBOX, lc_run, "[app.xex] : Run application or Reboot" },
+ { "*reset", FN_XBOX, lc_reset, "Reboot" },
+ { "*screenshot", FN_XBOX, lc_screenshot, "<file.bmp> : Copy the screen to file.bmp" },
+ { "*memory", FN_APP, lc_memory, ": Dump Memory Stats" },
+ { "*dir", FN_XBOX, lc_dir, "<filepath> [/s]: Directory listing" },
+ { "*del", FN_XBOX, lc_del, "<filepath> [/s] [/q]: Delete file" },
+ { "*modules", FN_XBOX, lc_modules, ": Lists currently loaded modules" },
+ { "*sections", FN_XBOX, lc_sections, "<module> : Lists the sections in the module" },
+ { "*bug", FN_CONSOLE, lc_bug, ": Open bug submission form" },
+ { "*clearconfigs", FN_XBOX, lc_ClearConfigs, ": Erase all game configs" },
+
+ // xcommands
+ { "*break", FN_XBOX, NULL, " addr=<address> | 'Write'/'Read'/'Execute'=<address> size=<DataSize> ['clear']: Sets/Clears a breakpoint" },
+// { "*bye", FN_XBOX, NULL, ": Closes connection" },
+ { "*continue", FN_XBOX, NULL, " thread=<threadid>: Resumes execution of a thread which has been stopped" },
+// { "*delete", FN_XBOX, NULL, " name=<remotefile>: Deletes a file on the Xbox" },
+// { "*dirlist", FN_XBOX, NULL, " name=<remotedir>: Lists the items in the directory" },
+ { "*getcontext", FN_XBOX, NULL, " thread=<threadid> 'Control' | 'Int' | 'FP' | 'Full': Gets the context of the thread" },
+ { "*getfileattributes", FN_XBOX, NULL, " name=<remotefile>: Gets attributes of a file" },
+ { "*getmem", FN_XBOX, NULL, " addr=<address> length=<len>: Reads memory from the Xbox" },
+ { "*go", FN_XBOX, NULL, ": Resumes suspended title threads" },
+ { "*halt", FN_XBOX, NULL, " thread=<threadid> Breaks a thread" },
+ { "*isstopped", FN_XBOX, NULL, " thread=<threadid>: Determines if a thread is stopped and why" },
+ { "*mkdir", FN_XBOX, NULL, " name=<remotedir>: Creates a new directory on the Xbox" },
+ { "*modlong", FN_XBOX, NULL, " name=<module>: Lists the long name of the module" },
+// { "*reboot", FN_XBOX, NULL, " [warm] [wait]: Reboots the xbox" },
+ { "*rename", FN_XBOX, NULL, " name=<remotefile> newname=<newname>: Renames a file on the Xbox" },
+ { "*resume", FN_XBOX, NULL, " thread=<threadid>: Resumes thread execution" },
+ { "*setcontext", FN_XBOX, NULL, " thread=<threadid>: Sets the context of the thread." },
+ { "*setfileattributes", FN_XBOX, NULL, " <remotefile> <attrs>: Sets attributes of a file" },
+ { "*setmem", FN_XBOX, NULL, " addr=<address> data=<rawdata>: Sets memory on the Xbox" },
+ { "*stop", FN_XBOX, NULL, ": Stops the process" },
+ { "*suspend", FN_XBOX, NULL, " thread=<threadid>: Suspends the thread" },
+ { "*systime", FN_XBOX, NULL, ": Gets the system time of the xbox" },
+ { "*threadinfo", FN_XBOX, NULL, " thread=<threadid>: Gets thread info" },
+ { "*threads", FN_XBOX, lc_threads, ": Gets the thread list" },
+// { "*title", FN_XBOX, NULL, " dir=<remotedir> name=<remotexex> [cmdline=<cmdline>]: Sets title to run" },
+ { "*xexinfo", FN_XBOX, NULL, " name=<remotexex | 'running'>: Gets info on an xex" },
+ { "*crash", FN_XBOX, lc_crashdump, " crash the console, emitting a dump" },
+};
+const int g_numLocalCommands = sizeof( g_localCommands )/sizeof( g_localCommands[0] );
+
+static BOOL g_bAutoConnectQuiet;
+static int g_bAutoConnectWait;
+
+//-----------------------------------------------------------------------------
+// MatchCommands
+//
+//-----------------------------------------------------------------------------
+int MatchLocalCommands( char* cmdStr, const char* cmdList[], int maxCmds )
+{
+ int numCommands = 0;
+
+ // look in local
+ int matchLen = strlen( cmdStr );
+ for ( int i=0; i<g_numLocalCommands; i++ )
+ {
+ if ( !strnicmp( cmdStr, g_localCommands[i].strCommand, matchLen ) )
+ {
+ cmdList[numCommands++] = g_localCommands[i].strCommand;
+ if ( numCommands >= maxCmds )
+ break;
+ }
+ }
+
+ return ( numCommands );
+}
+
+//-----------------------------------------------------------------------------
+// DecodeRebootArgs
+//
+//-----------------------------------------------------------------------------
+void DecodeRebootArgs( int argc, char** argv, char* xexPath, char* xexName, char* xexArgs )
+{
+ char drive[MAX_PATH];
+ char dir[MAX_PATH];
+ char filename[MAX_PATH];
+ char extension[MAX_PATH];
+
+ xexPath[0] = '\0';
+ xexName[0] = '\0';
+ xexArgs[0] = '\0';
+
+ if ( !argc )
+ return;
+
+ _splitpath( argv[0], drive, dir, filename, extension );
+
+ sprintf( xexPath, "%s%s", drive, dir );
+ sprintf( xexName, "%s%s", filename, extension );
+
+ for ( int i=1; i<argc; i++ )
+ {
+ strcat( xexArgs, argv[i] );
+ if ( i < argc-1 )
+ strcat( xexArgs, " " );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Helper function. Causes a disconnect, has optional re-connect time.
+// A non-zero wait will delay before attempting re-connect.
+//-----------------------------------------------------------------------------
+void DoDisconnect( BOOL bKeepConnection, int waitTime )
+{
+ // save state, user gates auto-connect ability
+ int autoConnect = g_autoConnect;
+
+ // full disconnect, disables autoconnect
+ lc_disconnect( 0, NULL );
+
+ if ( autoConnect && bKeepConnection && waitTime > 0 )
+ {
+ // restore autoconnect status
+ lc_autoConnect( 0, NULL );
+
+ // lets the system settle a little between contexts
+ g_bAutoConnectWait = waitTime;
+ g_bAutoConnectQuiet = FALSE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// lc_bug
+//
+//-----------------------------------------------------------------------------
+BOOL lc_bug( int argc, char* argv[] )
+{
+ if ( argc != 1 )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 1, args );
+ goto cleanUp;
+ }
+
+ BugDlg_Open();
+
+ return TRUE;
+
+cleanUp:
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_dir
+//
+//-----------------------------------------------------------------------------
+BOOL lc_dir( int argc, char* argv[] )
+{
+ fileNode_t *nodePtr;
+ fileNode_t *pFileList;
+ int numFiles;
+ int numDirs;
+ __int64 totalBytes;
+ bool recurse;
+ char dateTimeString[256];
+ char sizeString[64];
+ char filePath[MAX_PATH];
+ char fileName[MAX_PATH];
+ char targetName[MAX_PATH];
+ char newPath[MAX_PATH];
+ SYSTEMTIME systemTime;
+ SYSTEMTIME localTime;
+ const char *dirString;
+ BOOL errCode;
+ int nPass;
+ TIME_ZONE_INFORMATION tzInfo;
+
+ pFileList = NULL;
+ errCode = FALSE;
+
+ if ( argc < 2 )
+ {
+ char* args[2] = {"*dir", argv[0]};
+ lc_help( 2, args );
+ goto cleanUp;
+ }
+
+ strcpy( newPath, argv[1] );
+
+ // seperate components
+ Sys_StripFilename( newPath, filePath, sizeof( filePath ) );
+ Sys_StripPath( newPath, fileName, sizeof( fileName ) );
+
+ if ( fileName[0] )
+ {
+ if ( !strstr( fileName,"*" ) && !strstr( fileName,"?" ) )
+ {
+ // assume filename was a directory name
+ strcat( newPath, "\\" );
+ Sys_StripFilename( newPath, filePath, sizeof( filePath ) );
+ Sys_StripPath( newPath, fileName, sizeof( fileName ) );
+ }
+ }
+
+ recurse = false;
+ if ( argc >= 3 )
+ {
+ if ( !stricmp( argv[2], "/s" ) )
+ recurse = true;
+ }
+
+ if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_DIRECTORY|FA_READONLY, 0, &pFileList ) )
+ {
+ ConsoleWindowPrintf( RGB( 255,0,0 ), "Bad Target Path '%s'\n", filePath );
+ goto cleanUp;
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nDirectory of %s\n\n", argv[1] );
+
+ GetTimeZoneInformation( &tzInfo );
+
+ numFiles = 0;
+ numDirs = 0;
+ totalBytes = 0;
+ for ( nPass=0; nPass<2; nPass++ )
+ {
+ for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr )
+ {
+ if ( !nPass && !( nodePtr->attributes & FA_DIRECTORY ) )
+ {
+ // first pass, dirs only
+ continue;
+ }
+ else if ( nPass && ( nodePtr->attributes & FA_DIRECTORY ) )
+ {
+ // second pass, files only
+ continue;
+ }
+
+ Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) );
+
+ if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) )
+ continue;
+
+ FileTimeToSystemTime( &nodePtr->changeTime, &systemTime );
+ SystemTimeToTzSpecificLocalTime( &tzInfo, &systemTime, &localTime );
+ SystemTimeToString( &localTime, dateTimeString, sizeof( dateTimeString ) );
+
+ __int64 fullSize = MAKEINT64( nodePtr->sizeHigh, nodePtr->sizeLow );
+
+ if ( nodePtr->attributes & FA_DIRECTORY )
+ {
+ numDirs++;
+ dirString = "<DIR>";
+ sprintf( sizeString, "%s", " " );
+ }
+ else
+ {
+ numFiles++;
+ dirString = " ";
+ Sys_NumberToCommaString( fullSize, sizeString, sizeof( sizeString ) );
+ totalBytes += fullSize;
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s %12s %s\n", dateTimeString, dirString, sizeString, targetName );
+ }
+ }
+
+ Sys_NumberToCommaString( totalBytes, sizeString, sizeof( sizeString ) );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d File(s) %s bytes\n", " ", numFiles, sizeString );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d Dir(s)\n", " ", numDirs );
+
+ // success
+ errCode = TRUE;
+
+cleanUp:
+ if ( pFileList )
+ FreeTargetFileList( pFileList );
+
+ return errCode;
+}
+
+//-----------------------------------------------------------------------------
+// lc_del
+//
+//-----------------------------------------------------------------------------
+BOOL lc_del( int argc, char* argv[] )
+{
+ HRESULT hr;
+ fileNode_t *nodePtr;
+ fileNode_t *pFileList;
+ int numDeleted;
+ int numErrors;
+ bool recurse;
+ char filePath[MAX_PATH];
+ char fileName[MAX_PATH];
+ char targetName[MAX_PATH];
+ BOOL errCode;
+
+ pFileList = NULL;
+ errCode = FALSE;
+
+ if ( argc < 2 )
+ {
+ char* args[2] = {"*del", argv[0]};
+ lc_help( 2, args );
+ goto cleanUp;
+ }
+
+ // seperate components
+ Sys_StripFilename( argv[1], filePath, sizeof( filePath ) );
+ Sys_StripPath( argv[1], fileName, sizeof( fileName ) );
+
+ bool bQuiet = false;
+ recurse = false;
+ if ( argc >= 3 )
+ {
+ for ( int i = 2; i < argc; i++ )
+ {
+ if ( !V_stricmp( argv[i], "/s" ) )
+ {
+ recurse = true;
+ }
+ else if ( !V_stricmp( argv[i], "/q" ) )
+ {
+ // silence errors
+ bQuiet = true;
+ }
+ }
+ }
+
+ if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_READONLY|FA_DIRECTORY, 0, &pFileList ) )
+ {
+ ConsoleWindowPrintf( XBX_CLR_RED, "Bad Target Path '%s'\n", filePath );
+ goto cleanUp;
+ }
+
+ numErrors = 0;
+ numDeleted = 0;
+ for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr )
+ {
+ Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) );
+
+ if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) )
+ continue;
+
+ hr = DmDeleteFile( nodePtr->filename, ( nodePtr->attributes & FA_DIRECTORY ) != 0 );
+ if ( hr != XBDM_NOERR )
+ {
+ if ( !bQuiet )
+ {
+ ConsoleWindowPrintf( XBX_CLR_RED, "Error Deleting '%s'\n", nodePtr->filename );
+ }
+ numErrors++;
+ }
+ else
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Deleted '%s'\n", nodePtr->filename );
+ numDeleted++;
+ }
+ }
+
+ if ( !numDeleted && !numErrors )
+ {
+ ConsoleWindowPrintf( XBX_CLR_RED, "No Files found for '%s'\n", argv[1] );
+ }
+ else
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%d files deleted.\n", numDeleted );
+ }
+
+ // success
+ errCode = TRUE;
+
+cleanUp:
+ if ( pFileList )
+ FreeTargetFileList( pFileList );
+
+ return errCode;
+}
+
+//-----------------------------------------------------------------------------
+// lc_memory
+//
+//-----------------------------------------------------------------------------
+BOOL lc_memory( int argc, char* argv[] )
+{
+ HRESULT hr;
+
+ hr = DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__", true );
+ if ( FAILED( hr ) )
+ return FALSE;
+
+ // success
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_screenshot
+//
+//-----------------------------------------------------------------------------
+BOOL lc_screenshot( int argc, char* argv[] )
+{
+ char filename[MAX_PATH];
+ char filepath[MAX_PATH];
+ static int shot = 0;
+ struct _stat dummyStat;
+
+ if ( argc <= 1 )
+ {
+ strcpy( filepath, g_localPath );
+ Sys_AddFileSeperator( filepath, sizeof( filepath ) );
+
+ // spin up to available file
+ while ( 1 )
+ {
+ sprintf( filename, "%sscreenshot_%4.4d.bmp", filepath, shot );
+ if ( _stat( filename, &dummyStat ) == -1 )
+ {
+ // filename not in use
+ break;
+ }
+ shot++;
+ }
+ }
+ else if ( argc == 2 )
+ {
+ strcpy( filename, argv[1] );
+ Sys_AddExtension( ".bmp", filename, sizeof( filename ) );
+ }
+ else if ( argc > 2 )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 2, args );
+ goto cleanUp;
+ }
+
+ HRESULT hr = DmScreenShot( filename );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_screenshot(): DmScreenShot() failure", hr );
+ goto cleanUp;
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Screenshot saved to %s\n", filename );
+
+ // advance the shot
+ shot++;
+
+ // success
+ return TRUE;
+
+cleanUp:
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_modules
+//
+//-----------------------------------------------------------------------------
+BOOL lc_modules( int argc, char* argv[] )
+{
+ HRESULT hr;
+ PDM_WALK_MODULES pWalkMod = NULL;
+ CUtlVector< DMN_MODLOAD > list;
+
+ // add a fake module at 0xFFFFFFFF to make sorting simple
+ DMN_MODLOAD modLoad = { 0 };
+ modLoad.BaseAddress = (VOID*)0xFFFFFFFF;
+ list.AddToTail( modLoad );
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Modules:\n" );
+ while ( 1 )
+ {
+ hr = DmWalkLoadedModules( &pWalkMod, &modLoad );
+ if ( hr == XBDM_ENDOFLIST )
+ {
+ hr = XBDM_NOERR;
+ break;
+ }
+ else if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_modules(): DmWalkLoadedModules() failure", hr );
+ break;
+ }
+
+ // add in ascending address order
+ for ( int i = 0; i < list.Count(); i++ )
+ {
+ if ( modLoad.BaseAddress <= list[i].BaseAddress )
+ {
+ list.InsertBefore( i, modLoad );
+ break;
+ }
+ }
+ }
+
+ unsigned int total = 0;
+ for ( int i = 0; i < list.Count()-1; i++ )
+ {
+ DMN_MODLOAD *pModule = &list[i];
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Base: 0x%8.8x, Size: %5.2f MB, [%s]\n", pModule->BaseAddress, pModule->Size/( 1024.0f*1024.0f ), pModule->Name );
+
+ total += pModule->Size;
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Total: %.2f MB\n\n", total/( 1024.0f*1024.0f ) );
+
+ if ( pWalkMod )
+ {
+ DmCloseLoadedModules( pWalkMod );
+ }
+
+ if ( !FAILED( hr ) )
+ {
+ // success
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_sections
+//
+//-----------------------------------------------------------------------------
+BOOL lc_sections( int argc, char* argv[] )
+{
+ char moduleName[MAX_PATH];
+ HRESULT hr;
+ PDM_WALK_MODSECT pWalkModSect = NULL;
+ DMN_SECTIONLOAD sectLoad;
+
+ if ( argc != 2 )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 2, args );
+ goto cleanUp;
+ }
+
+ strcpy( moduleName, argv[1] );
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Sections:\n" );
+ while ( 1 )
+ {
+ hr = DmWalkModuleSections( &pWalkModSect, moduleName, &sectLoad );
+ if ( hr == XBDM_ENDOFLIST )
+ {
+ hr = XBDM_NOERR;
+ break;
+ }
+ else if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_sections(): DmWalkModuleSections() failure", hr );
+ break;
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "[%s]:\n", sectLoad.Name );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Base: 0x%8.8x\n", sectLoad.BaseAddress );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Size: %.2f MB ( %d bytes )\n", sectLoad.Size/( 1024.0f*1024.0f ), sectLoad.Size );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Index: %d\n", sectLoad.Index );
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "End.\n\n" );
+
+ if ( pWalkModSect )
+ DmCloseModuleSections( pWalkModSect );
+
+ if ( !FAILED( hr ) )
+ {
+ // success
+ return TRUE;
+ }
+
+cleanUp:
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_threads
+//
+//-----------------------------------------------------------------------------
+BOOL lc_threads( int argc, char* argv[] )
+{
+ char nameBuff[256];
+ char suspendBuff[32];
+
+ DWORD threadList[256];
+ DWORD numThreads = 256;
+ memset( &threadList, 0, sizeof( threadList ) );
+ HRESULT hr = DmGetThreadList( threadList, &numThreads );
+ if ( FAILED( hr ) )
+ return FALSE;
+
+ // enumerate threads and display sorted by processor
+ DM_THREADINFOEX threadInfoEx;
+ for ( int core = 0; core < 3; core++ )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n--- CORE %d ---\n", core );
+
+ for ( int unit = 0; unit < 2; unit++ )
+ {
+ for ( int i = 0; i < (int)numThreads; i++ )
+ {
+ threadInfoEx.Size = sizeof( DM_THREADINFOEX );
+ hr = DmGetThreadInfoEx( threadList[i], &threadInfoEx );
+ if ( FAILED( hr ) )
+ return FALSE;
+
+ if ( threadInfoEx.CurrentProcessor != core*2 + unit )
+ {
+ continue;
+ }
+
+ nameBuff[0] = '\0';
+ DmGetMemory( threadInfoEx.ThreadNameAddress, threadInfoEx.ThreadNameLength, nameBuff, NULL );
+ if ( !nameBuff[0] )
+ {
+ strcpy( nameBuff, "???" );
+ }
+
+ suspendBuff[0] = '\0';
+ if ( threadInfoEx.SuspendCount )
+ {
+ sprintf( suspendBuff, "(Suspend: %d)", threadInfoEx.SuspendCount );
+ }
+
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Id: 0x%8.8x Pri: %2d Proc: %1d Stack: %7.2f KB [%s] %s\n",
+ threadList[i],
+ threadInfoEx.Priority,
+ threadInfoEx.CurrentProcessor,
+ (float)( (unsigned int)threadInfoEx.StackBase - (unsigned int)threadInfoEx.StackLimit )/1024.0f,
+ nameBuff,
+ suspendBuff );
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_run
+//
+//-----------------------------------------------------------------------------
+BOOL lc_run( int argc, char* argv[] )
+{
+ HRESULT hr;
+ char xexDrive[MAX_PATH];
+ char xexPath[MAX_PATH];
+ char xexName[MAX_PATH];
+ char xexArgs[MAX_PATH];
+
+ if ( !argc )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 2, args );
+ goto cleanUp;
+ }
+
+ // copy args
+ g_rebootArgc = argc-1;
+ for ( int i=1; i<argc; i++ )
+ {
+ if ( i==1 )
+ {
+ strcpy( xexPath, argv[i] );
+ Sys_AddExtension( ".xex", xexPath, sizeof( xexPath ) );
+ _splitpath( xexPath, xexDrive, NULL, NULL, NULL );
+ if ( !xexDrive[0] )
+ {
+ char szTempPath[MAX_PATH];
+ V_strncpy( szTempPath, "e:\\", sizeof( szTempPath ) );
+ V_strncat( szTempPath, xexPath, sizeof( szTempPath ) );
+ V_strncpy( xexPath, szTempPath, sizeof( xexPath ) );
+ }
+
+ g_rebootArgv[i-1] = Sys_CopyString( xexPath );
+ }
+ else
+ {
+ g_rebootArgv[i-1] = Sys_CopyString( argv[i] );
+ }
+ }
+
+ if ( !g_rebootArgc )
+ {
+ // reboot
+ hr = DmReboot( DMBOOT_COLD );
+ }
+ else
+ {
+ DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs );
+
+ // trial set title - ensure title is present
+ hr = DmSetTitle( xexPath, xexName, xexArgs );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_Run(): DmSetTitle() failure", hr );
+ goto cleanUp;
+ }
+
+ // reboot - wait for 15s to connect and run title
+ hr = DmReboot( DMBOOT_WAIT );
+ }
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr );
+ goto cleanUp;
+ }
+
+ // set reboot state
+ g_reboot = true;
+
+ return TRUE;
+
+cleanUp:
+ // free args
+ for ( int i=0; i<g_rebootArgc; i++ )
+ Sys_Free( g_rebootArgv[i] );
+ g_rebootArgc = 0;
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_reset
+//
+//-----------------------------------------------------------------------------
+BOOL lc_reset( int argc, char* argv[] )
+{
+ if ( !argc )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 2, args );
+ return FALSE;
+ }
+
+ HRESULT hr = DmReboot( DMBOOT_COLD );
+
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr );
+ return FALSE;
+ }
+
+ // set reboot state
+ g_reboot = true;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_help
+//
+// Handles the "help" command. If no args, prints a list of built-in
+// and remote commands ( remote only if connected ). If a command
+// is specified, prints detailed help for that command
+//-----------------------------------------------------------------------------
+BOOL lc_help( int argc, char* argv[] )
+{
+ if ( argc <= 1 )
+ {
+ // no arguments - print out our list of commands
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Console Commands:\n" );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "---------------\n" );
+ for ( int i = 0; i < g_numLocalCommands; i++ )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_localCommands[i].strCommand );
+ }
+
+ if ( g_connectedToApp )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Remote Commands: ( %d )\n", g_numRemoteCommands );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "----------------\n" );
+ if ( !g_numRemoteCommands )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "( None )\n" );
+ }
+ else
+ {
+ for ( int i=0; i<g_numRemoteCommands; i++ )
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_remoteCommands[i]->strCommand );
+ }
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
+ }
+ }
+ else
+ {
+ // match as many as possible
+ int cch = lstrlenA( argv[1] );
+
+ // print help description for all local matches
+ for ( int i=0; i<g_numLocalCommands; i++ )
+ {
+ if ( !_strnicmp( g_localCommands[i].strCommand, argv[1], cch ) && g_localCommands[i].strHelp )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_localCommands[i].strCommand, g_localCommands[i].strHelp );
+ }
+ }
+
+ // print help description for all remote matches
+ if ( g_connectedToApp )
+ {
+ for ( int i=0; i<g_numRemoteCommands; i++ )
+ {
+ if ( !_strnicmp( g_remoteCommands[i]->strCommand, argv[1], cch ) && g_remoteCommands[i]->strHelp )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_remoteCommands[i]->strCommand, g_remoteCommands[i]->strHelp );
+ }
+ }
+ }
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
+ }
+
+ return TRUE;
+ }
+
+//-----------------------------------------------------------------------------
+// lc_cls
+//-----------------------------------------------------------------------------
+BOOL lc_cls( int argc, char* argv[] )
+{
+ SetWindowText( g_hwndOutputWindow, "" );
+
+ // non't let the compiler complain about unused parameters
+ ( VOID )argc;
+ ( VOID )argv;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_connect
+//
+// Connect to XBox
+//-----------------------------------------------------------------------------
+BOOL lc_connect( int argc, char* argv[] )
+{
+ HRESULT hr;
+ BOOL connected = FALSE;
+
+ if ( g_connectedToXBox )
+ {
+ if ( !lc_disconnect( 0, NULL ) )
+ return FALSE;
+ }
+
+ if ( argc >= 1 && argv[0][0] )
+ {
+ hr = DmSetXboxName( argv[0] );
+ if ( FAILED( hr ) )
+ {
+ char message[255];
+ sprintf( message, "ConnectToXBox(): DmSetXboxName( %s ) failure", argv[0] );
+ DmAPI_DisplayError( message, hr );
+ goto cleanUp;
+ }
+ }
+
+ // open connection
+ hr = DmOpenConnection( &g_pdmConnection );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "ConnectToXBox(): DmOpenConnection() failure", hr );
+ goto cleanUp;
+ }
+ connected = TRUE;
+
+ DWORD namelen = MAX_XBOXNAMELEN;
+ hr = DmGetXboxName( g_xboxName, &namelen );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "ConnectToXBox(): DmGetXboxName() failure", hr );
+ goto cleanUp;
+ }
+ hr = DmResolveXboxName( &g_xboxAddress );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "ConnectToXBox(): DmResolveXboxName() failure", hr );
+ goto cleanUp;
+ }
+
+ // success
+ g_connectedToXBox = TRUE;
+ g_connectFailure = 0;
+
+ if ( !g_connectCount )
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connected To: '%s'(%d.%d.%d.%d)\n", g_xboxName, ( ( byte* )&g_xboxAddress )[3], ( ( byte* )&g_xboxAddress )[2], ( ( byte* )&g_xboxAddress )[1], ( ( byte* )&g_xboxAddress )[0] );
+ g_connectCount++;
+
+ SetConnectionIcon( ICON_CONNECTED_XBOX );
+
+ if ( g_connectCount == 1 )
+ {
+ // inital connect
+ }
+
+ return TRUE;
+
+cleanUp:
+ if ( connected )
+ DmCloseConnection( g_pdmConnection );
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_listen
+//
+// Open listen session with App
+//-----------------------------------------------------------------------------
+BOOL lc_listen( int argc, char* argv[] )
+{
+ HRESULT hr;
+ BOOL success;
+ BOOL sessionStarted;
+ BOOL sessionValid;
+ char *args[1];
+ char cmdStr[256];
+
+ if ( g_connectedToXBox || g_connectedToApp )
+ {
+ if ( !lc_disconnect( 0, NULL ) )
+ return ( FALSE );
+ }
+
+ if ( !g_connectedToXBox )
+ {
+ // connect to xbox
+ args[0] = g_xboxTargetName;
+ if ( !lc_connect( 1, args ) )
+ return FALSE;
+ }
+
+ // until otherwise
+ success = FALSE;
+ sessionStarted = FALSE;
+ sessionValid = FALSE;
+
+ // init session
+ hr = DmOpenNotificationSession( 0, &g_pdmnSession );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_session(): DmOpenNotificationSession() failure", hr );
+ goto cleanUp;
+ }
+ sessionStarted = TRUE;
+
+ // get notifications of app debugging output
+ hr = DmNotify( g_pdmnSession, DM_DEBUGSTR, Remote_NotifyDebugString );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_session(): DmNotify() failure", hr );
+ goto cleanUp;
+ }
+
+ // get command notifications
+ hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_COMMAND_PREFIX, Remote_NotifyCommandFunc );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr );
+ goto cleanUp;
+ }
+
+ // get print notifications
+ hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_PRINT_PREFIX, Remote_NotifyPrintFunc );
+ if ( FAILED( hr ) )
+ {
+ DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr );
+ goto cleanUp;
+ }
+ sessionValid = TRUE;
+
+ // Send initial connect command to the External Command Processor so it knows we're here
+ sprintf( cmdStr, "%s %d", VXCONSOLE_COMMAND_PREFIX "!" "__connect__", VXCONSOLE_PROTOCOL_VERSION );
+ hr = DmAPI_SendCommand( cmdStr, true );
+ if ( FAILED( hr ) )
+ {
+ if ( !g_autoConnect )
+ ConsoleWindowPrintf( RGB( 255,0,0 ), "Couldn't Find Application\n" );
+ goto cleanUp;
+ }
+ else
+ {
+ // connected
+ success = TRUE;
+ g_connectedToApp = TRUE;
+ g_connectedTime = Sys_GetSystemTime();
+ SetConnectionIcon( ICON_CONNECTED_APP1 );
+
+ if ( g_clsOnConnect )
+ {
+ if ( g_bPlayTestMode )
+ {
+ // demarcate the log
+ ConsoleWindowPrintf( CLR_DEFAULT, "\n******** CONNECTION ********\n" );
+ }
+
+ lc_cls( 0, NULL );
+ CpuProfile_Clear();
+ TimeStampLog_Clear();
+ }
+
+ goto cleanUp;
+ }
+
+cleanUp:
+ if ( !success )
+ {
+ if ( sessionValid )
+ DmNotify( g_pdmnSession, DM_NONE, NULL );
+
+ if ( sessionStarted )
+ DmCloseNotificationSession( g_pdmnSession );
+ }
+
+ return ( success );
+}
+
+//-----------------------------------------------------------------------------
+// AutoConnectTimerProc
+//
+//-----------------------------------------------------------------------------
+void AutoConnectTimerProc( HWND hwnd, UINT_PTR idEvent )
+{
+ static BOOL busy;
+ int icon;
+ char* cmdStr;
+ BOOL bKeepConnection = TRUE;
+
+ // blink the connection icon
+ if ( g_connectedToApp && (! g_bSuppressBlink ) )
+ {
+ if ( g_currentIcon == ICON_CONNECTED_APP0 )
+ icon = ICON_CONNECTED_APP1;
+ else
+ icon = ICON_CONNECTED_APP0;
+ SetConnectionIcon( icon );
+ }
+
+ if ( busy )
+ {
+ // not ready for new tick
+ return;
+ }
+
+ if ( g_bAutoConnectWait > 0 )
+ {
+ if ( g_bAutoConnectWait && !g_bAutoConnectQuiet )
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Waiting... %d seconds remaining\n", g_bAutoConnectWait );
+ g_bAutoConnectWait--;
+ return;
+ }
+
+ // no more ticks until ready
+ busy = TRUE;
+
+ if ( !g_connectedToApp )
+ {
+ // looking for application - must force re-connect every time
+ if ( g_connectedToXBox )
+ {
+ // temporary "partial" disconnect
+ DmCloseConnection( g_pdmConnection );
+ g_connectedToXBox = FALSE;
+ }
+
+ // attempt to start or re-establish connection and session
+ lc_listen( 0, NULL );
+
+ if ( !g_connectedToXBox )
+ {
+ SetConnectionIcon( ICON_DISCONNECTED );
+ g_connectFailure++;
+ }
+
+ if ( g_reboot && g_connectedToXBox )
+ {
+ char xexPath[MAX_PATH];
+ char xexName[MAX_PATH];
+ char xexArgs[MAX_PATH];
+
+ DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs );
+
+ if ( g_rebootArgc )
+ {
+ // free args
+ for ( int i=0; i<g_rebootArgc; i++ )
+ Sys_Free( g_rebootArgv[i] );
+ g_rebootArgc = 0;
+
+ HRESULT hr = DmSetTitle( xexPath, xexName, xexArgs );
+ if ( FAILED( hr ) )
+ DmAPI_DisplayError( "Reboot: DmSetTitle() failure", hr );
+ else
+ {
+ hr = DmGo();
+ if ( FAILED( hr ) )
+ DmAPI_DisplayError( "Reboot: DmGo() failure", hr );
+ }
+ }
+
+ g_reboot = false;
+ }
+
+ if ( !g_connectFailure )
+ {
+ // quietly attempt re-connection or ping every 3 seconds
+ g_bAutoConnectWait = 3;
+ g_bAutoConnectQuiet = TRUE;
+ busy = FALSE;
+ }
+ else
+ {
+ if ( g_connectFailure == 1 )
+ {
+ // console may be rebooting, allow sufficient dvd boot up delay, then attempt re-connection
+ // 5 seconds barely covers the xbox splash
+ g_bAutoConnectWait = 15;
+ g_bAutoConnectQuiet = FALSE;
+ busy = FALSE;
+ }
+ else
+ {
+ // a sustained connection failure means the xbox is just not there
+ // re-trying is too cpu intensive and causes pc to appear locked
+ // warn and stop auto connecting, user must fix
+ bKeepConnection = FALSE;
+ goto disconnect;
+ }
+ }
+ return;
+ }
+ else
+ {
+ // try to send ping across open connection at an idle interval
+ cmdStr = VXCONSOLE_COMMAND_PREFIX "!";
+ HRESULT hr = DmAPI_SendCommand( cmdStr, false );
+ if ( FAILED( hr ) && hr != XBDM_UNDEFINED )
+ goto disconnect;
+
+ // quietly ping
+ g_bAutoConnectWait = 3;
+ g_bAutoConnectQuiet = TRUE;
+ busy = FALSE;
+ return;
+ }
+
+disconnect:
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connection To Xbox Lost.\n" );
+
+ DoDisconnect( bKeepConnection, 3 );
+
+ busy = FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_autoConnect
+//-----------------------------------------------------------------------------
+BOOL lc_autoConnect( int argc, char* argv[] )
+{
+ if ( !g_autoConnect )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Enabling Auto Connect.\n" );
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Looking for Connection...\n" );
+ g_autoConnect = TRUE;
+ }
+ else
+ {
+ // already enabled
+ return ( TRUE );
+ }
+
+ if ( !g_autoConnectTimer )
+ {
+ UINT_PTR timer = TIMERID_AUTOCONNECT;
+ g_autoConnectTimer = SetTimer( g_hDlgMain, timer, 1000, NULL );
+ }
+
+ return ( TRUE );
+}
+
+//-----------------------------------------------------------------------------
+// lc_disconnect
+//-----------------------------------------------------------------------------
+BOOL lc_disconnect( int argc, char* argv[] )
+{
+ if ( g_autoConnect )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Disabling Auto Connect.\n" );
+ if ( g_autoConnectTimer )
+ {
+ UINT_PTR timer = TIMERID_AUTOCONNECT;
+ KillTimer( g_hDlgMain, timer );
+ }
+ g_autoConnectTimer = 0;
+ g_autoConnect = FALSE;
+ }
+
+ if ( g_connectedToApp )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Session.\n" );
+
+ DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__disconnect__", false );
+
+ // close session
+ DmNotify( g_pdmnSession, DM_NONE, NULL );
+ DmCloseNotificationSession( g_pdmnSession );
+
+ g_connectedToApp = FALSE;
+ }
+
+ if ( g_connectedToXBox )
+ {
+ ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Connection.\n" );
+
+ // close connection
+ DmCloseConnection( g_pdmConnection );
+
+ // set the command ready mutex
+ SetEvent( g_hCommandReadyEvent );
+
+ g_connectedToXBox = FALSE;
+ g_xboxName[0] = '\0';
+ g_xboxAddress = 0;
+ }
+
+ SetConnectionIcon( ICON_DISCONNECTED );
+
+ g_connectCount = 0;
+
+ // free remote commands
+ Remote_DeleteCommands();
+
+ // Don't let the compiler complain about unused parameters
+ ( VOID )argc;
+ ( VOID )argv;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_crashdump
+//-----------------------------------------------------------------------------
+BOOL lc_crashdump( int argc, char* argv[] )
+{
+ DmCrashDump();
+
+ // Don't let the compiler complain about unused parameters
+ ( VOID )argc;
+ ( VOID )argv;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_quit
+//-----------------------------------------------------------------------------
+BOOL lc_quit( int argc, char* argv[] )
+{
+ PostMessage( g_hDlgMain, WM_CLOSE, 0, 0 );
+
+ // don't let the compiler complain about unused parameters
+ ( VOID )argc;
+ ( VOID )argv;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// lc_ClearConfigs
+//
+//-----------------------------------------------------------------------------
+BOOL lc_ClearConfigs( int argc, char* argv[] )
+{
+ if ( argc != 1 )
+ {
+ char* args[2] = {"*help", argv[0]};
+ lc_help( 1, args );
+ goto cleanUp;
+ }
+
+ // delete any configurations (ignore errors)
+ char szTempFilename[MAX_PATH];
+ V_ComposeFileName( "HDD:\\Content", "*.*", szTempFilename, sizeof( szTempFilename ) );
+ char *pArgs[4];
+ pArgs[0] = "*del";
+ pArgs[1] = szTempFilename;
+ pArgs[2] = "/s";
+ pArgs[3] = "/q";
+ lc_del( 4, pArgs );
+
+ return TRUE;
+
+cleanUp:
+ return FALSE;
+}