You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1528 lines
41 KiB
1528 lines
41 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// VXCONSOLE.CPP
|
|
//
|
|
// Valve XBox Console.
|
|
//=====================================================================================//
|
|
#include "vxconsole.h"
|
|
|
|
HWND g_hDlgMain;
|
|
HWND g_hwndCommandCombo;
|
|
HWND g_hwndOutputWindow;
|
|
HWND g_hwndCommandHint;
|
|
WNDPROC g_hwndCommandSubclassed;
|
|
BOOL g_connectedToXBox;
|
|
BOOL g_connectedToApp;
|
|
PDMN_SESSION g_pdmnSession;
|
|
PDM_CONNECTION g_pdmConnection;
|
|
printQueue_t g_PrintQueue;
|
|
UINT_PTR g_autoConnectTimer;
|
|
BOOL g_autoConnect;
|
|
BOOL g_debugCommands;
|
|
BOOL g_captureDebugSpew;
|
|
BOOL g_captureGameSpew = TRUE;
|
|
CHAR g_xboxName[MAX_XBOXNAMELEN];
|
|
DWORD g_xboxAddress;
|
|
HINSTANCE g_hInstance;
|
|
HICON g_hIcons[MAX_ICONS];
|
|
HBRUSH g_hBackgroundBrush;
|
|
HFONT g_hFixedFont;
|
|
BOOL g_reboot;
|
|
char* g_rebootArgv[MAX_ARGVELEMS];
|
|
int g_rebootArgc;
|
|
COLORREF g_backgroundColor;
|
|
TEXTMETRIC g_fixedFontMetrics;
|
|
int g_connectCount;
|
|
int g_currentIcon = -1;
|
|
HACCEL g_hAccel;
|
|
HMODULE g_hRichEdit;
|
|
DWORD g_connectedTime;
|
|
RECT g_mainWindowRect;
|
|
HFONT g_hProportionalFont;
|
|
HANDLE g_hCommandReadyEvent;
|
|
int g_currentCommandSelection;
|
|
int g_connectFailure;
|
|
int g_configID;
|
|
bool g_bSuppressBlink = false;
|
|
BOOL g_bPlayTestMode = TRUE;
|
|
|
|
LRESULT CALLBACK Main_DlgProc( HWND, UINT, WPARAM, LPARAM );
|
|
LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
|
|
|
|
bool ParseCommandLineArg( const char *pCmdLine, const char *pKey, char *pValueBuff, int valueBuffSize )
|
|
{
|
|
const char* pArg = V_stristr( (char*)pCmdLine, pKey );
|
|
if ( !pArg )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( pValueBuff )
|
|
{
|
|
// caller wants next token
|
|
pArg += strlen( pKey );
|
|
|
|
int i;
|
|
for ( i=0; i<valueBuffSize; i++ )
|
|
{
|
|
pValueBuff[i] = *pArg;
|
|
if ( *pArg == '\0' || *pArg == ' ' )
|
|
{
|
|
break;
|
|
}
|
|
pArg++;
|
|
}
|
|
pValueBuff[i] = '\0';
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MakeConfigString( const char *pString, int configID, char *pOutBuff, int outBuffSize )
|
|
{
|
|
if ( configID <= 0 )
|
|
{
|
|
// as-is, undecorated
|
|
V_snprintf( pOutBuff, outBuffSize, "%s", pString );
|
|
return;
|
|
}
|
|
|
|
int len = strlen( pString );
|
|
bool bAddTerminalSlash = ( len > 1 && pString[len-1] == '\\' );
|
|
|
|
V_snprintf( pOutBuff, outBuffSize, "%s_%d", pString, configID );
|
|
|
|
if ( bAddTerminalSlash )
|
|
{
|
|
V_strncat( pOutBuff, "\\", outBuffSize );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// LoadConfig
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void LoadConfig()
|
|
{
|
|
char buff[256];
|
|
int numArgs;
|
|
|
|
ConfigDlg_LoadConfig();
|
|
|
|
// initial menu state is from persisted config
|
|
g_captureDebugSpew = g_captureDebugSpew_StartupState;
|
|
|
|
Sys_GetRegistryString( "mainWindowRect", buff, "", sizeof( buff ) );
|
|
numArgs = sscanf( buff, "%d %d %d %d", &g_mainWindowRect.left, &g_mainWindowRect.top, &g_mainWindowRect.right, &g_mainWindowRect.bottom );
|
|
if ( numArgs != 4 || g_mainWindowRect.left < 0 || g_mainWindowRect.top < 0 || g_mainWindowRect.right < 0 || g_mainWindowRect.bottom < 0 )
|
|
memset( &g_mainWindowRect, 0, sizeof( g_mainWindowRect ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SaveConfig
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void SaveConfig()
|
|
{
|
|
char buff[256];
|
|
|
|
// get window placement
|
|
WINDOWPLACEMENT wp;
|
|
memset( &wp, 0, sizeof( wp ) );
|
|
wp.length = sizeof( WINDOWPLACEMENT );
|
|
GetWindowPlacement( g_hDlgMain, &wp );
|
|
g_mainWindowRect = wp.rcNormalPosition;
|
|
|
|
sprintf( buff, "%d %d %d %d", g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right, g_mainWindowRect.bottom );
|
|
Sys_SetRegistryString( "mainWindowRect", buff );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetConnectionIcon
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void SetConnectionIcon( int icon )
|
|
{
|
|
if ( g_currentIcon == icon )
|
|
return;
|
|
|
|
g_currentIcon = icon;
|
|
SetClassLongPtr( g_hDlgMain, GCLP_HICON, ( LONG_PTR )g_hIcons[icon] );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetMainWindowTitle
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void SetMainWindowTitle()
|
|
{
|
|
if ( !g_hDlgMain )
|
|
{
|
|
return;
|
|
}
|
|
|
|
char titleBuff[128];
|
|
if ( !g_xboxTargetName[0] )
|
|
{
|
|
strcpy( titleBuff, VXCONSOLE_TITLE );
|
|
}
|
|
else
|
|
{
|
|
sprintf( titleBuff, "%s: %s", VXCONSOLE_TITLE, g_xboxTargetName );
|
|
if ( g_configID )
|
|
{
|
|
char configBuff[32];
|
|
sprintf( configBuff, " (%d)", g_configID );
|
|
V_strncat( titleBuff, configBuff, sizeof( titleBuff ) );
|
|
}
|
|
}
|
|
SetWindowText( g_hDlgMain, titleBuff );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// DmAPI_DisplayError
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID DmAPI_DisplayError( const CHAR* message, HRESULT hr )
|
|
{
|
|
CHAR strError[128];
|
|
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "%s\n", message );
|
|
|
|
HRESULT hrError = DmTranslateError( hr, strError, sizeof( strError ) );
|
|
if ( !FAILED( hrError ) && strError[0] )
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: '%s'\n", strError );
|
|
else
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: 0x%08lx\n", hr );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// DmAPI_SendCommand
|
|
//
|
|
// Send the specified string across the debugger channel to the application
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT DmAPI_SendCommand( const char* strCommand, bool wait )
|
|
{
|
|
DWORD dwResponseLen;
|
|
CHAR strResponse[MAX_PATH];
|
|
int retval;
|
|
bool bIgnorePingResponse;
|
|
char* ptr;
|
|
|
|
retval = WaitForSingleObject( g_hCommandReadyEvent, wait ? INFINITE : 0 );
|
|
if ( retval != WAIT_OBJECT_0 )
|
|
{
|
|
// cannot send command
|
|
// some other previous command has not responded and signaled the release
|
|
// testing has shown DmSendCommand() is not re-entrant and callers get
|
|
// their responses out of sync
|
|
return XBDM_UNDEFINED;
|
|
}
|
|
|
|
// clear the event mutex until ready
|
|
ResetEvent( g_hCommandReadyEvent );
|
|
|
|
bIgnorePingResponse = false;
|
|
dwResponseLen = sizeof( strResponse );
|
|
strResponse[0] = '\0';
|
|
|
|
if ( strCommand[0] == '*' )
|
|
{
|
|
// skip past internal command identifier
|
|
strCommand++;
|
|
}
|
|
else if ( !stricmp( strCommand, VXCONSOLE_COMMAND_PREFIX "!" ) )
|
|
{
|
|
// empty ping command
|
|
// must be done as a synchronous command with a response because there
|
|
// is no way to bind an asynch response to the owner
|
|
bIgnorePingResponse = true;
|
|
}
|
|
|
|
HRESULT hr = DmSendCommand( g_pdmConnection, strCommand, strResponse, &dwResponseLen );
|
|
if ( !FAILED( hr ) )
|
|
{
|
|
// success
|
|
switch ( hr )
|
|
{
|
|
case XBDM_NOERR:
|
|
if ( !bIgnorePingResponse )
|
|
{
|
|
// skip past possible ack prefix
|
|
ptr = strstr( strResponse, VXCONSOLE_COMMAND_ACK );
|
|
if ( ptr )
|
|
{
|
|
ptr += strlen( VXCONSOLE_COMMAND_ACK );
|
|
|
|
// ignore remote acknowledge response
|
|
if ( !stricmp( ptr, "OK" ) )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ptr = strResponse;
|
|
}
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", ptr );
|
|
}
|
|
break;
|
|
|
|
case XBDM_MULTIRESPONSE:
|
|
// multi-line response - loop, looking for end of response
|
|
while ( 1 )
|
|
{
|
|
dwResponseLen = sizeof( strResponse );
|
|
|
|
hr = DmReceiveSocketLine( g_pdmConnection, strResponse, &dwResponseLen );
|
|
if ( FAILED( hr ) || strResponse[0] == '.' )
|
|
break;
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", strResponse );
|
|
}
|
|
break;
|
|
|
|
case XBDM_BINRESPONSE:
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Binary response - not implemented\n" );
|
|
break;
|
|
|
|
case XBDM_READYFORBIN:
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Ready for binary - not implemented\n" );
|
|
break;
|
|
|
|
default:
|
|
ConsoleWindowPrintf( XBX_CLR_RED, "Unknown Response: ( %s ).\n", strResponse );
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetEvent( g_hCommandReadyEvent );
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PrintToQueue
|
|
//
|
|
// Formats the string and adds it to the print queue
|
|
//-----------------------------------------------------------------------------
|
|
void PrintToQueue( COLORREF rgb, LPCTSTR strFormat, ... )
|
|
{
|
|
char buffer[MAX_QUEUEDSTRINGLEN];
|
|
|
|
// enter critical section so we don't try to process the list
|
|
EnterCriticalSection( &g_PrintQueue.CriticalSection );
|
|
|
|
assert( g_PrintQueue.numMessages <= MAX_QUEUEDSTRINGS );
|
|
|
|
// when the queue is full, the main thread is probably blocked and not dequeing
|
|
if ( !g_captureGameSpew || g_PrintQueue.numMessages == MAX_QUEUEDSTRINGS )
|
|
{
|
|
LeaveCriticalSection( &g_PrintQueue.CriticalSection );
|
|
return;
|
|
}
|
|
|
|
va_list arglist;
|
|
va_start( arglist, strFormat );
|
|
int len = _vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, strFormat, arglist );
|
|
if ( len == -1 )
|
|
{
|
|
buffer[sizeof(buffer)-1] = '\0';
|
|
}
|
|
va_end( arglist );
|
|
|
|
// queue the message into the next slot
|
|
g_PrintQueue.pMessages[g_PrintQueue.numMessages] = Sys_CopyString( buffer );
|
|
g_PrintQueue.aColors[g_PrintQueue.numMessages++] = rgb;
|
|
|
|
// ensure we post a message to process the print queue
|
|
if ( g_PrintQueue.numMessages == 1 )
|
|
PostMessage( g_hDlgMain, WM_USER, 0, 0 );
|
|
|
|
// the main thread can now safely process the list
|
|
LeaveCriticalSection( &g_PrintQueue.CriticalSection );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ProcessPrintQueue
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void ProcessPrintQueue()
|
|
{
|
|
// enter critical section so we don't try to add anything while we're processing
|
|
EnterCriticalSection( &g_PrintQueue.CriticalSection );
|
|
|
|
// dequeue all entries
|
|
for ( int i = 0; i < g_PrintQueue.numMessages; i++ )
|
|
{
|
|
ConsoleWindowPrintf( g_PrintQueue.aColors[i], "%s", g_PrintQueue.pMessages[i] );
|
|
Sys_Free( g_PrintQueue.pMessages[i] );
|
|
}
|
|
|
|
g_PrintQueue.numMessages = 0;
|
|
|
|
// now we can safely add to the list
|
|
LeaveCriticalSection( &g_PrintQueue.CriticalSection );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ConsoleWindowPrintf
|
|
//
|
|
// Writes out a string directly to the console window
|
|
//-----------------------------------------------------------------------------
|
|
int ConsoleWindowPrintf( COLORREF rgb, LPCTSTR strFormat, ... )
|
|
{
|
|
int dwStrLen;
|
|
char strTemp[512];
|
|
va_list arglist;
|
|
CHARRANGE cr = { -1, -2 };
|
|
|
|
if ( rgb != XBX_CLR_DEFAULT )
|
|
{
|
|
// set whatever colors, etc. they want
|
|
CHARFORMAT cf = {0};
|
|
cf.cbSize = sizeof( cf );
|
|
cf.dwMask = CFM_COLOR;
|
|
cf.dwEffects = 0;
|
|
cf.crTextColor = rgb;
|
|
SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&cf );
|
|
}
|
|
|
|
// Get our string to print
|
|
va_start( arglist, strFormat );
|
|
dwStrLen = _vsnprintf( strTemp, sizeof( strTemp ), strFormat, arglist );
|
|
va_end( arglist );
|
|
|
|
// Move the selection to the end
|
|
SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_EXSETSEL, 0, ( LPARAM )&cr );
|
|
|
|
// Add the text and scroll it into view
|
|
SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_REPLACESEL, 0, ( LONG )( LPSTR )strTemp );
|
|
SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SCROLLCARET, 0, 0L );
|
|
|
|
if ( g_bPlayTestMode )
|
|
{
|
|
char szLogPath[MAX_PATH];
|
|
char szLogName[MAX_PATH];
|
|
V_snprintf( szLogName, sizeof( szLogName ), "vxconsole_%s.log", g_xboxTargetName );
|
|
V_ComposeFileName( g_localPath, szLogName, szLogPath, sizeof( szLogPath ) );
|
|
FILE *fp = fopen( szLogPath, "at+" );
|
|
if ( fp )
|
|
{
|
|
fprintf( fp, strTemp );
|
|
fclose( fp );
|
|
}
|
|
}
|
|
|
|
return dwStrLen;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ProcessCommand
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool ProcessCommand( const char* strCmdIn )
|
|
{
|
|
char strRemoteCmd[MAX_PATH + 10];
|
|
TCHAR strCmdBak[MAX_PATH];
|
|
char strCmd[MAX_PATH];
|
|
char* argv[MAX_ARGVELEMS];
|
|
BOOL isXCommand = FALSE;
|
|
BOOL isLocal = FALSE;
|
|
BOOL isRemote = FALSE;
|
|
int iIndex;
|
|
|
|
// local copy for destructive purposes
|
|
strcpy( strCmd, strCmdIn );
|
|
|
|
// copy of the original command string
|
|
lstrcpyA( strCmdBak, strCmdIn );
|
|
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "] %s\n", strCmd );
|
|
|
|
// parse argstring into components
|
|
int argc = CmdToArgv( strCmd, argv, MAX_ARGVELEMS );
|
|
if ( !argc )
|
|
{
|
|
// empty command
|
|
return true;
|
|
}
|
|
|
|
if ( ( iIndex = ComboBox_GetCount( g_hwndCommandCombo ) ) >= MAX_COMMANDHISTORY )
|
|
{
|
|
// Limit the history of items, purge oldest
|
|
ComboBox_DeleteString( g_hwndCommandCombo, 0 );
|
|
}
|
|
|
|
// add to end of list
|
|
iIndex = ComboBox_InsertItemData( g_hwndCommandCombo, -1, strCmdBak );
|
|
ComboBox_SetCurSel( g_hwndCommandCombo, -1 );
|
|
|
|
// find command in local list
|
|
for ( int i=0; i<g_numLocalCommands; i++ )
|
|
{
|
|
if ( lstrcmpiA( g_localCommands[i].strCommand, argv[0] ) )
|
|
{
|
|
// no match
|
|
continue;
|
|
}
|
|
|
|
isLocal = TRUE;
|
|
if ( !g_localCommands[i].pfnHandler )
|
|
{
|
|
// no handler, remote xcommand
|
|
isXCommand = TRUE;
|
|
}
|
|
|
|
if ( ( g_localCommands[i].flags & FN_XBOX ) && !g_connectedToXBox )
|
|
{
|
|
// not allowed yet
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to XBox.\n", argv[0] );
|
|
return true;
|
|
}
|
|
else if ( ( g_localCommands[i].flags & FN_APP ) && !g_connectedToApp )
|
|
{
|
|
// not allowed yet
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] );
|
|
return true;
|
|
}
|
|
|
|
if ( isXCommand )
|
|
break;
|
|
|
|
// do local command
|
|
g_localCommands[i].pfnHandler( argc, argv );
|
|
return true;
|
|
}
|
|
|
|
// find command in remote list
|
|
if ( !isLocal && !isXCommand && g_connectedToApp )
|
|
{
|
|
for ( int i=0; i<g_numRemoteCommands; i++ )
|
|
{
|
|
if ( lstrcmpiA( g_remoteCommands[i]->strCommand, argv[0] ) )
|
|
{
|
|
// no match
|
|
continue;
|
|
}
|
|
|
|
isRemote = TRUE;
|
|
|
|
if ( !g_connectedToApp )
|
|
{
|
|
// not allowed yet
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] );
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !isLocal && !isXCommand && !isRemote )
|
|
{
|
|
if ( !g_connectedToApp || g_numRemoteCommands != 0 )
|
|
{
|
|
// unrecognized
|
|
ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not a recognized command.\n", argv[0] );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ( isXCommand )
|
|
{
|
|
// send the xcommand directly
|
|
lstrcpyA( strRemoteCmd, strCmdBak );
|
|
}
|
|
else
|
|
{
|
|
// add remote command prefix
|
|
lstrcpyA( strRemoteCmd, VXCONSOLE_COMMAND_PREFIX "!" );
|
|
lstrcatA( strRemoteCmd, strCmdBak );
|
|
}
|
|
|
|
// send the command to the Xbox
|
|
HRESULT hr = DmAPI_SendCommand( strRemoteCmd, true );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
DmAPI_DisplayError( "DmSendCommand", hr );
|
|
return false;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CommandWindow_HandleKey
|
|
//
|
|
// Handle a WM_KEYDOWN in our RTF cmd window
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CommandWindow_HandleKey( WPARAM wParam )
|
|
{
|
|
BOOL bHandled = FALSE;
|
|
int curSel;
|
|
int numItems;
|
|
|
|
if ( wParam >= VK_F1 && wParam <= VK_F12 )
|
|
{
|
|
if ( Bindings_TranslateKey( wParam ) )
|
|
{
|
|
// handled
|
|
return true;
|
|
}
|
|
}
|
|
|
|
switch ( wParam )
|
|
{
|
|
case VK_TAB:
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
if ( IsWindowVisible( g_hwndCommandHint ) )
|
|
{
|
|
// hint window open
|
|
char hintCmd[MAX_PATH];
|
|
char userCmd[MAX_PATH];
|
|
|
|
// scroll through the hint selections
|
|
curSel = SendMessage( g_hwndCommandHint, (UINT)LB_GETCURSEL, NULL, NULL );
|
|
SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd );
|
|
|
|
numItems = SendMessage( g_hwndCommandHint, (UINT)LB_GETCOUNT, NULL, NULL );
|
|
if ( numItems < 0 )
|
|
numItems = 0;
|
|
|
|
if ( wParam == VK_TAB )
|
|
{
|
|
// get command typed so far
|
|
ComboBox_GetText( g_hwndCommandCombo, userCmd, MAX_PATH );
|
|
|
|
// strip the auto-space off the end
|
|
int len = Q_strlen(userCmd);
|
|
if ( userCmd[len-1] == ' ' )
|
|
{
|
|
userCmd[len-1] = '\0';
|
|
}
|
|
|
|
if ( !stricmp( userCmd, hintCmd ) )
|
|
{
|
|
// cycle to next or prev command with tab or shift-tab
|
|
if ( GetKeyState(VK_SHIFT) < 0 )
|
|
{
|
|
wParam = VK_UP;
|
|
}
|
|
else
|
|
{
|
|
wParam = VK_DOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
// move the selection
|
|
if ( wParam == VK_UP )
|
|
curSel--;
|
|
else if ( wParam == VK_DOWN )
|
|
curSel++;
|
|
if ( curSel < 0 )
|
|
curSel = numItems - 1;
|
|
else if ( curSel > numItems-1 )
|
|
curSel = 0;
|
|
if ( curSel < 0 )
|
|
curSel = 0;
|
|
|
|
// set the selection and get highlighted command
|
|
SendMessage( g_hwndCommandHint, (UINT)LB_SETCURSEL, (WPARAM)curSel, NULL );
|
|
SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd );
|
|
|
|
// add a space to the end for easier parameter setting
|
|
Q_strncat( hintCmd, " ", sizeof(hintCmd), 1 );
|
|
|
|
// replace command string
|
|
ComboBox_SetText( g_hwndCommandCombo, hintCmd );
|
|
|
|
// set cursor to end of command
|
|
SendMessage( g_hwndCommandCombo, (UINT)CB_SETEDITSEL, (WPARAM)0, MAKELONG( MAX_PATH,MAX_PATH ) );
|
|
|
|
bHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
curSel = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCURSEL, NULL, NULL );
|
|
if ( curSel < 0 )
|
|
{
|
|
// combo box has no selection
|
|
// override combo box behavior and set selection
|
|
numItems = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCOUNT, NULL, NULL );
|
|
if ( numItems > 0 )
|
|
{
|
|
if ( wParam == VK_UP )
|
|
{
|
|
// set to bottom of list
|
|
curSel = numItems-1;
|
|
}
|
|
else if ( wParam == VK_DOWN )
|
|
{
|
|
// set to top of list
|
|
curSel = 0;
|
|
}
|
|
|
|
SendMessage( g_hwndCommandCombo, (UINT)CB_SETCURSEL, (WPARAM)curSel, NULL );
|
|
bHandled = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VK_RETURN:
|
|
// user hit return in the combo box
|
|
if ( ComboBox_GetDroppedState( g_hwndCommandCombo ) )
|
|
{
|
|
ComboBox_ShowDropdown( g_hwndCommandCombo, FALSE );
|
|
}
|
|
else
|
|
{
|
|
PostMessage( g_hDlgMain, WM_APP, 0, 0 );
|
|
bHandled = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return bHandled;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CommandWindow_SubclassedProc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch ( msg )
|
|
{
|
|
case WM_SYSKEYDOWN:
|
|
case WM_KEYDOWN:
|
|
if ( CommandWindow_HandleKey( wParam ) )
|
|
return 0;
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
if ( wParam == VK_RETURN )
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
return CallWindowProc( g_hwndCommandSubclassed, hDlg, msg, wParam, lParam );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Main_SizeWindow
|
|
//
|
|
// Handles a WM_SIZE message by resizing all our child windows to match the main window
|
|
//-----------------------------------------------------------------------------
|
|
void Main_SizeWindow( HWND hDlg, UINT wParam, int cx, int cy )
|
|
{
|
|
if ( cx==0 || cy==0 )
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect( hDlg, &rcClient );
|
|
cx = rcClient.right;
|
|
cy = rcClient.bottom;
|
|
}
|
|
|
|
// if we're big enough, position our child windows
|
|
if ( g_hwndCommandCombo && cx > 64 && cy > 64 )
|
|
{
|
|
RECT rcCmd;
|
|
RECT rcHint;
|
|
RECT rcOut;
|
|
|
|
// fit the "command" combo box into our window
|
|
GetWindowRect( g_hwndCommandCombo, &rcCmd );
|
|
ScreenToClient( hDlg, ( LPPOINT )&rcCmd );
|
|
ScreenToClient( hDlg, ( LPPOINT )&rcCmd + 1 );
|
|
int x = rcCmd.left;
|
|
int dx = cx - 8 - x;
|
|
int dy = rcCmd.bottom - rcCmd.top;
|
|
int y = cy - 8 - dy;
|
|
SetWindowPos(
|
|
g_hwndCommandCombo,
|
|
NULL,
|
|
x,
|
|
y,
|
|
dx,
|
|
dy,
|
|
SWP_NOZORDER );
|
|
|
|
// position the "hint popup" window above the "command" window
|
|
GetWindowRect( g_hwndCommandHint, &rcHint );
|
|
ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint );
|
|
ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint + 1 );
|
|
SetWindowPos(
|
|
g_hwndCommandHint,
|
|
NULL,
|
|
rcCmd.left,
|
|
( rcCmd.top - 4 ) - ( rcHint.bottom - rcHint.top + 1 ),
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER );
|
|
|
|
// position the "Cmd" label
|
|
RECT rcStaticCmd;
|
|
HWND hStaticCmd = GetDlgItem( g_hDlgMain, IDC_LABEL );
|
|
GetWindowRect( hStaticCmd, &rcStaticCmd );
|
|
ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd );
|
|
ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd + 1 );
|
|
SetWindowPos(
|
|
hStaticCmd,
|
|
NULL,
|
|
8,
|
|
y + ( dy - ( rcStaticCmd.bottom - rcStaticCmd.top ) ) / 2 - 1,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER );
|
|
|
|
// position the "output" window
|
|
GetWindowRect( g_hwndOutputWindow, &rcOut );
|
|
ScreenToClient( hDlg, ( LPPOINT )&rcOut );
|
|
int dwWidth = cx - rcOut.left - 8;
|
|
int dwHeight = y - rcOut.top - 8;
|
|
SetWindowPos( g_hwndOutputWindow, NULL, 0, 0, dwWidth, dwHeight, SWP_NOMOVE | SWP_NOZORDER );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// _SortCommands
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
int _SortCommands( const void* a, const void* b )
|
|
{
|
|
const char* strA = *( const char** )a;
|
|
const char* strB = *( const char** )b;
|
|
|
|
return ( stricmp( strA, strB ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// EnableCommandHint
|
|
//
|
|
// Open/Close the command hint popup
|
|
//-----------------------------------------------------------------------------
|
|
void EnableCommandHint( bool enable )
|
|
{
|
|
int w = 0;
|
|
int h = 0;
|
|
int itemHeight;
|
|
int i;
|
|
int maxLen;
|
|
int len;
|
|
const char* cmds[256];
|
|
int numLocalCommands;
|
|
int numRemoteCommands;
|
|
int curSel;
|
|
|
|
if ( !enable )
|
|
goto cleanUp;
|
|
|
|
// get the current command
|
|
char strCmd[MAX_PATH];
|
|
ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH );
|
|
if ( !strCmd[0] )
|
|
{
|
|
// user has typed nothing
|
|
enable = false;
|
|
goto cleanUp;
|
|
}
|
|
|
|
SendMessage( g_hwndCommandHint, ( UINT )LB_RESETCONTENT, NULL, NULL );
|
|
|
|
// get a list of possible matches
|
|
maxLen = 0;
|
|
numLocalCommands = MatchLocalCommands( strCmd, cmds, 256 );
|
|
numRemoteCommands = MatchRemoteCommands( strCmd, cmds+numLocalCommands, 256-numLocalCommands );
|
|
for ( i=0; i<numLocalCommands+numRemoteCommands; i++ )
|
|
{
|
|
len = strlen( cmds[i] );
|
|
if ( maxLen < len )
|
|
maxLen = len;
|
|
}
|
|
if ( !maxLen )
|
|
{
|
|
// no matches
|
|
enable = false;
|
|
goto cleanUp;
|
|
}
|
|
|
|
// sort the list ( eschew listbox's autosorting )
|
|
qsort( cmds, numLocalCommands+numRemoteCommands, sizeof( const char* ), _SortCommands );
|
|
|
|
curSel = -1;
|
|
len = strlen( strCmd );
|
|
for ( i=0; i<numLocalCommands+numRemoteCommands; i++ )
|
|
{
|
|
// populate the listbox
|
|
SendMessage( g_hwndCommandHint, ( UINT )LB_ADDSTRING, 0, ( LPARAM )cmds[i] );
|
|
|
|
// determine first best match
|
|
if ( curSel == -1 && !strnicmp( strCmd, cmds[i], len ) )
|
|
curSel = i;
|
|
}
|
|
|
|
if ( curSel != -1 )
|
|
{
|
|
// set the selection to the first best string
|
|
// ensure the top string is shown ( avoids odd auto-vscroll choices )
|
|
SendMessage( g_hwndCommandHint, ( UINT )LB_SETCURSEL, ( WPARAM )curSel, NULL );
|
|
if ( !curSel )
|
|
SendMessage( g_hwndCommandHint, ( UINT )LB_SETTOPINDEX, 0, NULL );
|
|
}
|
|
|
|
RECT rcCmd;
|
|
GetWindowRect( g_hwndCommandCombo, &rcCmd );
|
|
ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd );
|
|
ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd + 1 );
|
|
|
|
// clamp listbox height to client space
|
|
itemHeight = SendMessage( g_hwndCommandHint, ( UINT )LB_GETITEMHEIGHT, 0, NULL );
|
|
if ( itemHeight <= 0 )
|
|
{
|
|
// oops, shouldn't happen
|
|
enable = false;
|
|
goto cleanUp;
|
|
}
|
|
|
|
h = ( numLocalCommands + numRemoteCommands )*itemHeight + 2;
|
|
if ( h > rcCmd.top - 8)
|
|
{
|
|
h = rcCmd.top - 8;
|
|
}
|
|
|
|
// clamp listbox width
|
|
w = ( maxLen + 5 ) * g_fixedFontMetrics.tmMaxCharWidth;
|
|
|
|
// position the "hint popup" window above the "command" window
|
|
SetWindowPos(
|
|
g_hwndCommandHint,
|
|
NULL,
|
|
rcCmd.left,
|
|
( rcCmd.top - 4 ) - h,
|
|
w,
|
|
h,
|
|
SWP_NOZORDER );
|
|
|
|
cleanUp:
|
|
BOOL isVisible = IsWindowVisible( g_hwndCommandHint );
|
|
if ( !enable && isVisible )
|
|
ShowWindow( g_hwndCommandHint, SW_HIDE );
|
|
else if ( enable && !isVisible )
|
|
ShowWindow( g_hwndCommandHint, SW_SHOWNA );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Main_DlgProc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK Main_DlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
WORD wID = LOWORD( wParam );
|
|
BOOL isConnect;
|
|
|
|
switch ( message )
|
|
{
|
|
case WM_APP:
|
|
// user has pressed enter
|
|
// take the string from the command window and process it
|
|
// extra room for \r\n
|
|
char strCmd[MAX_PATH + 3];
|
|
ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH );
|
|
ProcessCommand( strCmd );
|
|
ComboBox_SetText( g_hwndCommandCombo, "" );
|
|
EnableCommandHint( false );
|
|
break;
|
|
|
|
case WM_USER:
|
|
ProcessPrintQueue();
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
// Don't do auto-connect stuff while the Assert dialog is up
|
|
// (it uses a synchronous command, so calling 'Dm' funcs here can cause a lockup)
|
|
if ( !g_AssertDialogActive )
|
|
{
|
|
if ( wID == TIMERID_AUTOCONNECT )
|
|
{
|
|
AutoConnectTimerProc( hDlg, TIMERID_AUTOCONNECT );
|
|
return 0L;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_CTLCOLORLISTBOX:
|
|
case WM_CTLCOLOREDIT:
|
|
SetBkColor( ( HDC )wParam,g_backgroundColor );
|
|
return ( BOOL )g_hBackgroundBrush;
|
|
|
|
case WM_SIZE:
|
|
Main_SizeWindow( hDlg, wParam, LOWORD( lParam ), HIWORD( lParam ) );
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
if ( wID == SC_CLOSE )
|
|
{
|
|
PostMessage( hDlg, WM_CLOSE, 0, 0 );
|
|
return 0L;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
// disconnect before closing
|
|
lc_disconnect( 0, NULL );
|
|
|
|
SaveConfig();
|
|
DestroyWindow( hDlg );
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
SubclassWindow( g_hwndCommandCombo, g_hwndCommandSubclassed );
|
|
PostQuitMessage( 0 );
|
|
return 0L;
|
|
|
|
case WM_INITMENU:
|
|
isConnect = g_connectedToXBox || g_connectedToApp;
|
|
CheckMenuItem( ( HMENU )wParam, IDM_AUTOCONNECT, MF_BYCOMMAND | ( g_autoConnect ? MF_CHECKED : MF_UNCHECKED ) );
|
|
CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREGAMESPEW, MF_BYCOMMAND | ( g_captureGameSpew ? MF_CHECKED : MF_UNCHECKED ) );
|
|
CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREDEBUGSPEW, MF_BYCOMMAND | ( g_captureDebugSpew ? MF_CHECKED : MF_UNCHECKED ) );
|
|
CheckMenuItem( ( HMENU )wParam, IDM_DEBUGCOMMANDS, MF_BYCOMMAND | ( g_debugCommands ? MF_CHECKED : MF_UNCHECKED ) );
|
|
CheckMenuItem( ( HMENU )wParam, IDM_PLAYTESTMODE, MF_BYCOMMAND | ( g_bPlayTestMode ? MF_CHECKED : MF_UNCHECKED ) );
|
|
EnableMenuItem( ( HMENU )wParam, IDM_SYNCFILES, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) );
|
|
EnableMenuItem( ( HMENU )wParam, IDM_SYNCINSTALL, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) );
|
|
return 0L;
|
|
|
|
case WM_COMMAND:
|
|
switch ( wID )
|
|
{
|
|
case IDC_COMMAND:
|
|
switch ( HIWORD( wParam ) )
|
|
{
|
|
case CBN_EDITCHANGE:
|
|
case CBN_SETFOCUS:
|
|
EnableCommandHint( true );
|
|
break;
|
|
|
|
case CBN_KILLFOCUS:
|
|
EnableCommandHint( false );
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDM_CONFIG:
|
|
ConfigDlg_Open();
|
|
return 0L;
|
|
|
|
case IDM_CAPTUREGAMESPEW:
|
|
g_captureGameSpew ^= 1;
|
|
return 0L;
|
|
|
|
case IDM_CAPTUREDEBUGSPEW:
|
|
g_captureDebugSpew ^= 1;
|
|
return 0L;
|
|
|
|
case IDM_DEBUGCOMMANDS:
|
|
g_debugCommands ^= 1;
|
|
return 0L;
|
|
|
|
case IDM_BUG:
|
|
BugDlg_Open();
|
|
return 0L;
|
|
|
|
case IDM_MEMORYDUMP:
|
|
ShowMemDump_Open();
|
|
return 0L;
|
|
|
|
case IDM_TIMESTAMPLOG:
|
|
TimeStampLog_Open();
|
|
return 0L;
|
|
|
|
case IDM_SYNCFILES:
|
|
SyncFilesDlg_Open();
|
|
return 0L;
|
|
|
|
case IDM_SYNCINSTALL:
|
|
InstallDlg_Open();
|
|
return 0L;
|
|
|
|
case IDM_EXCLUDEPATHS:
|
|
ExcludePathsDlg_Open();
|
|
return 0L;
|
|
|
|
case IDM_CPU_SAMPLES:
|
|
CpuProfileSamples_Open();
|
|
return 0L;
|
|
|
|
case IDM_CPU_HISTORY:
|
|
CpuProfileHistory_Open();
|
|
return 0L;
|
|
|
|
case IDM_D3D_SAMPLES:
|
|
TexProfileSamples_Open();
|
|
return 0L;
|
|
|
|
case IDM_D3D_HISTORY:
|
|
TexProfileHistory_Open();
|
|
return 0L;
|
|
|
|
case IDM_SHOWMEMORYUSAGE:
|
|
MemProfile_Open();
|
|
return 0L;
|
|
|
|
case IDM_PLAYTESTMODE:
|
|
g_bPlayTestMode ^= 1;
|
|
return 0L;
|
|
|
|
case IDM_SHOWRESOURCES_TEXTURES:
|
|
ShowTextures_Open();
|
|
return 0L;
|
|
|
|
case IDM_SHOWRESOURCES_MATERIALS:
|
|
ShowMaterials_Open();
|
|
return 0L;
|
|
|
|
case IDM_SHOWRESOURCES_SOUNDS:
|
|
ShowSounds_Open();
|
|
return 0L;
|
|
|
|
case IDM_SHOWRESOURCES_MODELS:
|
|
NotImplementedYet();
|
|
return 0L;
|
|
|
|
case IDM_AUTOCONNECT:
|
|
if ( g_connectedToXBox || g_connectedToApp || g_autoConnect )
|
|
lc_disconnect( 0, NULL );
|
|
else
|
|
lc_autoConnect( 0, NULL );
|
|
return 0L;
|
|
|
|
case IDM_BINDINGS_EDIT:
|
|
Bindings_Open();
|
|
return 0L;
|
|
|
|
case IDM_BINDINGS_BIND1:
|
|
case IDM_BINDINGS_BIND2:
|
|
case IDM_BINDINGS_BIND3:
|
|
case IDM_BINDINGS_BIND4:
|
|
case IDM_BINDINGS_BIND5:
|
|
case IDM_BINDINGS_BIND6:
|
|
case IDM_BINDINGS_BIND7:
|
|
case IDM_BINDINGS_BIND8:
|
|
case IDM_BINDINGS_BIND9:
|
|
case IDM_BINDINGS_BIND10:
|
|
case IDM_BINDINGS_BIND11:
|
|
case IDM_BINDINGS_BIND12:
|
|
Bindings_MenuSelection( wID );
|
|
return 0L;
|
|
|
|
case IDM_EXIT:
|
|
PostMessage( hDlg, WM_CLOSE, 0, 0 );
|
|
return 0L;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ( DefDlgProc( hDlg, message, wParam, lParam ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CmdToArgv
|
|
//
|
|
// Parses a string into argv and return # of args.
|
|
//-----------------------------------------------------------------------------
|
|
int CmdToArgv( char* str, char* argv[], int maxargs )
|
|
{
|
|
int argc = 0;
|
|
int argcT = 0;
|
|
char* strNil = str + lstrlenA( str );
|
|
|
|
while ( argcT < maxargs )
|
|
{
|
|
// Eat whitespace
|
|
while ( *str && ( *str==' ' ) )
|
|
str++;
|
|
|
|
if ( !*str )
|
|
{
|
|
argv[argcT++] = strNil;
|
|
}
|
|
else
|
|
{
|
|
// Find the end of this arg
|
|
char chEnd = ( *str == '"' || *str == '\'' ) ? *str++ : ' ';
|
|
char* strArgEnd = str;
|
|
while ( *strArgEnd && ( *strArgEnd != chEnd ) )
|
|
strArgEnd++;
|
|
|
|
// Record this argument
|
|
argv[argcT++] = str;
|
|
argc = argcT;
|
|
|
|
// Move strArg to the next argument ( or not, if we hit the end )
|
|
str = *strArgEnd ? strArgEnd + 1 : strArgEnd;
|
|
*strArgEnd = 0;
|
|
}
|
|
}
|
|
|
|
return argc;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateCommandHint
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void CreateCommandHint()
|
|
{
|
|
// create the "hint" popup
|
|
g_hwndCommandHint = CreateWindowEx(
|
|
WS_EX_NOPARENTNOTIFY,
|
|
"LISTBOX",
|
|
"",
|
|
WS_BORDER|WS_CHILD|LBS_HASSTRINGS|WS_VSCROLL,
|
|
0, 0, 100, 0,
|
|
g_hDlgMain,
|
|
( HMENU )IDC_COMMANDHINT,
|
|
g_hInstance,
|
|
NULL );
|
|
|
|
// force the popup to head of z-order
|
|
// to draw over all other children
|
|
BringWindowToTop( g_hwndCommandHint );
|
|
|
|
// set font
|
|
SendDlgItemMessage( g_hDlgMain, IDC_COMMANDHINT, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateResources
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool CreateResources()
|
|
{
|
|
LOGFONT lf;
|
|
HFONT hFontOld;
|
|
HDC hDC;
|
|
int i;
|
|
|
|
// pull in common controls
|
|
INITCOMMONCONTROLSEX initCommon;
|
|
initCommon.dwSize = sizeof( INITCOMMONCONTROLSEX );
|
|
initCommon.dwICC = ICC_LISTVIEW_CLASSES|ICC_USEREX_CLASSES;
|
|
if ( !InitCommonControlsEx( &initCommon ) )
|
|
return false;
|
|
|
|
// pull in rich edit controls
|
|
g_hRichEdit = LoadLibrary( "Riched32.dll" );
|
|
if ( !g_hRichEdit )
|
|
return false;
|
|
|
|
g_backgroundColor = XBX_CLR_LTGREY;
|
|
g_hBackgroundBrush = CreateSolidBrush( g_backgroundColor );
|
|
|
|
// get icons
|
|
g_hIcons[ICON_APPLICATION] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_VXCONSOLE ) );
|
|
g_hIcons[ICON_DISCONNECTED] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_DISCONNECTED ) );
|
|
g_hIcons[ICON_CONNECTED_XBOX] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT1_ON ) );
|
|
g_hIcons[ICON_CONNECTED_APP0] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_OFF ) );
|
|
g_hIcons[ICON_CONNECTED_APP1] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_ON ) );
|
|
for ( i=0; i<MAX_ICONS; i++ )
|
|
{
|
|
if ( !g_hIcons[i] )
|
|
return false;
|
|
}
|
|
|
|
// get the font feight
|
|
hDC = GetWindowDC( NULL );
|
|
int nHeight = -MulDiv( VXCONSOLE_FONTSIZE, GetDeviceCaps( hDC, LOGPIXELSY ), 72 );
|
|
ReleaseDC( NULL, hDC );
|
|
|
|
// create fixed font
|
|
memset( &lf, 0, sizeof( LOGFONT ) );
|
|
lf.lfHeight = nHeight;
|
|
lf.lfWeight = 400;
|
|
strcpy( lf.lfFaceName, VXCONSOLE_FONT );
|
|
g_hFixedFont = CreateFontIndirect( &lf );
|
|
if ( !g_hFixedFont )
|
|
return false;
|
|
|
|
// create proportional font
|
|
memset( &lf, 0, sizeof( LOGFONT ) );
|
|
lf.lfHeight = -11;
|
|
lf.lfWeight = 400;
|
|
strcpy( lf.lfFaceName, "Tahoma" );
|
|
g_hProportionalFont = CreateFontIndirect( &lf );
|
|
if ( !g_hProportionalFont )
|
|
return false;
|
|
|
|
// get the font metrics
|
|
hDC = GetWindowDC( NULL );
|
|
hFontOld = ( HFONT )SelectObject( hDC, g_hFixedFont );
|
|
GetTextMetrics( hDC, &g_fixedFontMetrics );
|
|
SelectObject( hDC, hFontOld );
|
|
ReleaseDC( NULL, hDC );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Shutdown
|
|
//
|
|
// Free all resources
|
|
//-----------------------------------------------------------------------------
|
|
void Shutdown()
|
|
{
|
|
BugReporter_FreeInterfaces();
|
|
|
|
if ( g_PrintQueue.bInit )
|
|
{
|
|
DeleteCriticalSection( &g_PrintQueue.CriticalSection );
|
|
g_PrintQueue.bInit = false;
|
|
}
|
|
|
|
if ( g_hCommandReadyEvent )
|
|
{
|
|
CloseHandle( g_hCommandReadyEvent );
|
|
g_hCommandReadyEvent = 0;
|
|
}
|
|
|
|
if ( g_hRichEdit )
|
|
{
|
|
FreeLibrary( g_hRichEdit );
|
|
g_hRichEdit = 0;
|
|
}
|
|
|
|
if ( g_hBackgroundBrush )
|
|
{
|
|
DeleteObject( g_hBackgroundBrush );
|
|
g_hBackgroundBrush = 0;
|
|
}
|
|
|
|
if ( g_hFixedFont )
|
|
{
|
|
DeleteObject( g_hFixedFont );
|
|
g_hFixedFont = 0;
|
|
}
|
|
|
|
if ( g_hProportionalFont )
|
|
{
|
|
DeleteObject( g_hProportionalFont );
|
|
g_hProportionalFont = 0;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Startup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool Startup()
|
|
{
|
|
// Load the xenon debugging dll (xbdm.dll) manually due to its absence from system path
|
|
const char *pPath = getenv( "path" );
|
|
const char *pXEDKDir = getenv( "xedk" );
|
|
if ( !pXEDKDir )
|
|
pXEDKDir = "";
|
|
|
|
int len = strlen( pPath ) + strlen( pXEDKDir ) + 256;
|
|
char *pNewPath = (char*)_alloca( len );
|
|
sprintf( pNewPath, "path=%s;%s\\bin\\win32", pPath, pXEDKDir );
|
|
_putenv( pNewPath );
|
|
|
|
HMODULE hXBDM = LoadLibrary( TEXT( "xbdm.dll" ) );
|
|
if ( !hXBDM )
|
|
{
|
|
if ( pXEDKDir[0] )
|
|
Sys_Error( "Couldn't load xbdm.dll" );
|
|
else
|
|
Sys_Error( "Couldn't load xbdm.dll\nXEDK environment variable not set." );
|
|
}
|
|
|
|
LoadConfig();
|
|
|
|
if ( !CreateResources() )
|
|
return false;
|
|
|
|
// set up our print queue
|
|
InitializeCriticalSection( &g_PrintQueue.CriticalSection );
|
|
g_PrintQueue.bInit = true;
|
|
|
|
// manual reset, initially signaled
|
|
g_hCommandReadyEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
|
|
|
|
// set up our window class
|
|
WNDCLASS wndclass;
|
|
memset( &wndclass, 0, sizeof( wndclass ) );
|
|
wndclass.style = 0;
|
|
wndclass.lpfnWndProc = Main_DlgProc;
|
|
wndclass.cbClsExtra = 0;
|
|
wndclass.cbWndExtra = VXCONSOLE_WINDOWBYTES;
|
|
wndclass.hInstance = g_hInstance;
|
|
wndclass.hIcon = g_hIcons[ICON_DISCONNECTED];
|
|
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
|
|
wndclass.hbrBackground = g_hBackgroundBrush;
|
|
wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_VXCONSOLE );
|
|
wndclass.lpszClassName = VXCONSOLE_CLASSNAME;
|
|
if ( !RegisterClass( &wndclass ) )
|
|
return false;
|
|
|
|
g_hAccel = LoadAccelerators( g_hInstance, MAKEINTRESOURCE( IDR_MAIN_ACCEL ) );
|
|
if ( !g_hAccel )
|
|
return false;
|
|
|
|
// Create our main dialog
|
|
g_hDlgMain = CreateDialog( g_hInstance, MAKEINTRESOURCE( IDD_VXCONSOLE ), 0, NULL );
|
|
if ( !g_hDlgMain )
|
|
return false;
|
|
SetWindowLong( g_hDlgMain, VXCONSOLE_CONFIGID, g_configID );
|
|
|
|
if ( !BugDlg_Init() )
|
|
return false;
|
|
|
|
if ( !CpuProfile_Init() )
|
|
return false;
|
|
|
|
if ( !TexProfile_Init() )
|
|
return false;
|
|
|
|
if ( !MemProfile_Init() )
|
|
return false;
|
|
|
|
if ( !Bindings_Init() )
|
|
return false;
|
|
|
|
if ( !SyncFilesDlg_Init() )
|
|
return false;
|
|
|
|
if ( !ShowMaterials_Init() )
|
|
return false;
|
|
|
|
if ( !ShowTextures_Init() )
|
|
return false;
|
|
|
|
if ( !ShowSounds_Init() )
|
|
return false;
|
|
|
|
if ( !ShowMemDump_Init() )
|
|
return false;
|
|
|
|
if ( !TimeStampLog_Init() )
|
|
return false;
|
|
|
|
if ( !ExcludePathsDlg_Init() )
|
|
return false;
|
|
|
|
g_hwndOutputWindow = GetDlgItem( g_hDlgMain, IDC_OUTPUT );
|
|
g_hwndCommandCombo = GetDlgItem( g_hDlgMain, IDC_COMMAND );
|
|
|
|
CreateCommandHint();
|
|
|
|
// subclass our dropdown command listbox to handle return key
|
|
g_hwndCommandSubclassed = SubclassWindow( GetWindow( g_hwndCommandCombo, GW_CHILD ), CommandWindow_SubclassedProc );
|
|
|
|
// Change the font type of the output window to courier
|
|
CHARFORMAT cf;
|
|
cf.cbSize = sizeof( CHARFORMAT );
|
|
SendMessage( g_hwndOutputWindow, EM_GETCHARFORMAT, 0, ( LPARAM )&cf );
|
|
cf.dwMask &= ~CFM_COLOR;
|
|
cf.yHeight = VXCONSOLE_FONTSIZE*20;
|
|
lstrcpyA( cf.szFaceName, VXCONSOLE_FONT );
|
|
SendMessage( g_hwndOutputWindow, EM_SETCHARFORMAT, SCF_ALL, ( LPARAM )&cf );
|
|
SendMessage( g_hwndOutputWindow, EM_SETBKGNDCOLOR, 0, g_backgroundColor );
|
|
|
|
// ensure the output window adheres to its z ordering
|
|
LONG style = GetWindowLong( g_hwndOutputWindow, GWL_STYLE );
|
|
style |= WS_CLIPSIBLINGS;
|
|
SetWindowLong( g_hwndOutputWindow, GWL_STYLE, style );
|
|
|
|
// change the font of the command and its hint window to courier
|
|
SendDlgItemMessage( g_hDlgMain, IDC_COMMAND, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE );
|
|
|
|
// set the window title
|
|
SetMainWindowTitle();
|
|
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "VXConsole %s [%s Build: %s %s] [Protocol: %d]\n", VXCONSOLE_VERSION, VXCONSOLE_BUILDTYPE, __DATE__, __TIME__, VXCONSOLE_PROTOCOL_VERSION );
|
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "type '*help' for list of commands...\n\n" );
|
|
|
|
g_currentIcon = -1;
|
|
SetConnectionIcon( ICON_DISCONNECTED );
|
|
|
|
if ( g_alwaysAutoConnect)
|
|
{
|
|
// user wants to auto-connect at startup
|
|
lc_autoConnect( 0, NULL );
|
|
}
|
|
|
|
if ( g_mainWindowRect.right && g_mainWindowRect.bottom )
|
|
MoveWindow( g_hDlgMain, g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right-g_mainWindowRect.left, g_mainWindowRect.bottom-g_mainWindowRect.top, FALSE );
|
|
|
|
// ready for display
|
|
int cmdShow = SW_SHOWNORMAL;
|
|
if ( g_startMinimized )
|
|
cmdShow = SW_SHOWMINIMIZED;
|
|
ShowWindow( g_hDlgMain, cmdShow );
|
|
|
|
// success
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// WinMain
|
|
//
|
|
// Entry point for program
|
|
//-----------------------------------------------------------------------------
|
|
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow )
|
|
{
|
|
bool error = true;
|
|
MSG msg = {0};
|
|
|
|
g_hInstance = hInstance;
|
|
|
|
g_bSuppressBlink = ParseCommandLineArg( pCmdLine, "-noblink", NULL, 0 );
|
|
|
|
// optional -config <ID> can specify a specific configuration
|
|
char buff[128];
|
|
buff[0] = '\0';
|
|
ParseCommandLineArg( pCmdLine, "-config ", buff, sizeof( buff ) );
|
|
g_configID = atoi( buff );
|
|
|
|
MakeConfigString( VXCONSOLE_REGISTRY, g_configID, buff, sizeof( buff ) );
|
|
Sys_SetRegistryPrefix( buff );
|
|
|
|
HWND hwnd = FindWindow( VXCONSOLE_CLASSNAME, NULL );
|
|
if ( hwnd && GetWindowLong( hwnd, VXCONSOLE_CONFIGID ) == g_configID )
|
|
{
|
|
// single instance only
|
|
// bring other version to foreground
|
|
if ( IsIconic( hwnd ) )
|
|
ShowWindow( hwnd, SW_RESTORE );
|
|
SetForegroundWindow( hwnd );
|
|
return ( FALSE );
|
|
}
|
|
|
|
if ( !Startup() )
|
|
goto cleanUp;
|
|
|
|
// message pump
|
|
while ( GetMessage( &msg, NULL, 0, 0 ) )
|
|
{
|
|
if ( !TranslateAccelerator( g_hDlgMain, g_hAccel, &msg ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
}
|
|
|
|
// no-error, end of app
|
|
error = false;
|
|
|
|
cleanUp:
|
|
if ( error )
|
|
{
|
|
char str[255];
|
|
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL );
|
|
MessageBox( NULL, str, NULL, MB_OK );
|
|
}
|
|
|
|
Shutdown();
|
|
|
|
return ( msg.wParam );
|
|
}
|
|
|
|
|