source-engine/utils/xbox/vxconsole/local_cmds.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

1308 lines
33 KiB
C++

//========= 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;
}