summaryrefslogtreecommitdiff
path: root/utils/xbox/vxconsole/vxconsole.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/vxconsole.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/xbox/vxconsole/vxconsole.cpp')
-rw-r--r--utils/xbox/vxconsole/vxconsole.cpp1528
1 files changed, 1528 insertions, 0 deletions
diff --git a/utils/xbox/vxconsole/vxconsole.cpp b/utils/xbox/vxconsole/vxconsole.cpp
new file mode 100644
index 0000000..976f3da
--- /dev/null
+++ b/utils/xbox/vxconsole/vxconsole.cpp
@@ -0,0 +1,1528 @@
+//========= 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 );
+}
+
+