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 ); |
|
} |
|
|
|
|
|
|