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