Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // VXCONSOLE.CPP
  4. //
  5. // Valve XBox Console.
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. HWND g_hDlgMain;
  9. HWND g_hwndCommandCombo;
  10. HWND g_hwndOutputWindow;
  11. HWND g_hwndCommandHint;
  12. WNDPROC g_hwndCommandSubclassed;
  13. BOOL g_connectedToXBox;
  14. BOOL g_connectedToApp;
  15. PDMN_SESSION g_pdmnSession;
  16. PDM_CONNECTION g_pdmConnection;
  17. printQueue_t g_PrintQueue;
  18. UINT_PTR g_autoConnectTimer;
  19. BOOL g_autoConnect;
  20. BOOL g_debugCommands;
  21. BOOL g_captureDebugSpew;
  22. BOOL g_captureGameSpew = TRUE;
  23. CHAR g_xboxName[MAX_XBOXNAMELEN];
  24. DWORD g_xboxAddress;
  25. HINSTANCE g_hInstance;
  26. HICON g_hIcons[MAX_ICONS];
  27. HBRUSH g_hBackgroundBrush;
  28. HFONT g_hFixedFont;
  29. BOOL g_reboot;
  30. char* g_rebootArgv[MAX_ARGVELEMS];
  31. int g_rebootArgc;
  32. COLORREF g_backgroundColor;
  33. TEXTMETRIC g_fixedFontMetrics;
  34. int g_connectCount;
  35. int g_currentIcon = -1;
  36. HACCEL g_hAccel;
  37. HMODULE g_hRichEdit;
  38. DWORD g_connectedTime;
  39. RECT g_mainWindowRect;
  40. HFONT g_hProportionalFont;
  41. HANDLE g_hCommandReadyEvent;
  42. int g_currentCommandSelection;
  43. int g_connectFailure;
  44. int g_configID;
  45. bool g_bSuppressBlink = false;
  46. BOOL g_bPlayTestMode = TRUE;
  47. LRESULT CALLBACK Main_DlgProc( HWND, UINT, WPARAM, LPARAM );
  48. LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  49. bool ParseCommandLineArg( const char *pCmdLine, const char *pKey, char *pValueBuff, int valueBuffSize )
  50. {
  51. const char* pArg = V_stristr( (char*)pCmdLine, pKey );
  52. if ( !pArg )
  53. {
  54. return false;
  55. }
  56. if ( pValueBuff )
  57. {
  58. // caller wants next token
  59. pArg += strlen( pKey );
  60. int i;
  61. for ( i=0; i<valueBuffSize; i++ )
  62. {
  63. pValueBuff[i] = *pArg;
  64. if ( *pArg == '\0' || *pArg == ' ' )
  65. {
  66. break;
  67. }
  68. pArg++;
  69. }
  70. pValueBuff[i] = '\0';
  71. }
  72. return true;
  73. }
  74. void MakeConfigString( const char *pString, int configID, char *pOutBuff, int outBuffSize )
  75. {
  76. if ( configID <= 0 )
  77. {
  78. // as-is, undecorated
  79. V_snprintf( pOutBuff, outBuffSize, "%s", pString );
  80. return;
  81. }
  82. int len = strlen( pString );
  83. bool bAddTerminalSlash = ( len > 1 && pString[len-1] == '\\' );
  84. V_snprintf( pOutBuff, outBuffSize, "%s_%d", pString, configID );
  85. if ( bAddTerminalSlash )
  86. {
  87. V_strncat( pOutBuff, "\\", outBuffSize );
  88. }
  89. }
  90. //-----------------------------------------------------------------------------
  91. // LoadConfig
  92. //
  93. //-----------------------------------------------------------------------------
  94. void LoadConfig()
  95. {
  96. char buff[256];
  97. int numArgs;
  98. ConfigDlg_LoadConfig();
  99. // initial menu state is from persisted config
  100. g_captureDebugSpew = g_captureDebugSpew_StartupState;
  101. Sys_GetRegistryString( "mainWindowRect", buff, "", sizeof( buff ) );
  102. numArgs = sscanf( buff, "%d %d %d %d", &g_mainWindowRect.left, &g_mainWindowRect.top, &g_mainWindowRect.right, &g_mainWindowRect.bottom );
  103. if ( numArgs != 4 || g_mainWindowRect.left < 0 || g_mainWindowRect.top < 0 || g_mainWindowRect.right < 0 || g_mainWindowRect.bottom < 0 )
  104. memset( &g_mainWindowRect, 0, sizeof( g_mainWindowRect ) );
  105. }
  106. //-----------------------------------------------------------------------------
  107. // SaveConfig
  108. //
  109. //-----------------------------------------------------------------------------
  110. void SaveConfig()
  111. {
  112. char buff[256];
  113. // get window placement
  114. WINDOWPLACEMENT wp;
  115. memset( &wp, 0, sizeof( wp ) );
  116. wp.length = sizeof( WINDOWPLACEMENT );
  117. GetWindowPlacement( g_hDlgMain, &wp );
  118. g_mainWindowRect = wp.rcNormalPosition;
  119. sprintf( buff, "%d %d %d %d", g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right, g_mainWindowRect.bottom );
  120. Sys_SetRegistryString( "mainWindowRect", buff );
  121. }
  122. //-----------------------------------------------------------------------------
  123. // SetConnectionIcon
  124. //
  125. //-----------------------------------------------------------------------------
  126. void SetConnectionIcon( int icon )
  127. {
  128. if ( g_currentIcon == icon )
  129. return;
  130. g_currentIcon = icon;
  131. SetClassLongPtr( g_hDlgMain, GCLP_HICON, ( LONG_PTR )g_hIcons[icon] );
  132. }
  133. //-----------------------------------------------------------------------------
  134. // SetMainWindowTitle
  135. //
  136. //-----------------------------------------------------------------------------
  137. void SetMainWindowTitle()
  138. {
  139. if ( !g_hDlgMain )
  140. {
  141. return;
  142. }
  143. char titleBuff[128];
  144. if ( !g_xboxTargetName[0] )
  145. {
  146. strcpy( titleBuff, VXCONSOLE_TITLE );
  147. }
  148. else
  149. {
  150. sprintf( titleBuff, "%s: %s", VXCONSOLE_TITLE, g_xboxTargetName );
  151. if ( g_configID )
  152. {
  153. char configBuff[32];
  154. sprintf( configBuff, " (%d)", g_configID );
  155. V_strncat( titleBuff, configBuff, sizeof( titleBuff ) );
  156. }
  157. }
  158. SetWindowText( g_hDlgMain, titleBuff );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // DmAPI_DisplayError
  162. //
  163. //-----------------------------------------------------------------------------
  164. VOID DmAPI_DisplayError( const CHAR* message, HRESULT hr )
  165. {
  166. CHAR strError[128];
  167. ConsoleWindowPrintf( RGB( 255,0,0 ), "%s\n", message );
  168. HRESULT hrError = DmTranslateError( hr, strError, sizeof( strError ) );
  169. if ( !FAILED( hrError ) && strError[0] )
  170. ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: '%s'\n", strError );
  171. else
  172. ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: 0x%08lx\n", hr );
  173. }
  174. //-----------------------------------------------------------------------------
  175. // DmAPI_SendCommand
  176. //
  177. // Send the specified string across the debugger channel to the application
  178. //-----------------------------------------------------------------------------
  179. HRESULT DmAPI_SendCommand( const char* strCommand, bool wait )
  180. {
  181. DWORD dwResponseLen;
  182. CHAR strResponse[MAX_PATH];
  183. int retval;
  184. bool bIgnorePingResponse;
  185. char* ptr;
  186. retval = WaitForSingleObject( g_hCommandReadyEvent, wait ? INFINITE : 0 );
  187. if ( retval != WAIT_OBJECT_0 )
  188. {
  189. // cannot send command
  190. // some other previous command has not responded and signaled the release
  191. // testing has shown DmSendCommand() is not re-entrant and callers get
  192. // their responses out of sync
  193. return XBDM_UNDEFINED;
  194. }
  195. // clear the event mutex until ready
  196. ResetEvent( g_hCommandReadyEvent );
  197. bIgnorePingResponse = false;
  198. dwResponseLen = sizeof( strResponse );
  199. strResponse[0] = '\0';
  200. if ( strCommand[0] == '*' )
  201. {
  202. // skip past internal command identifier
  203. strCommand++;
  204. }
  205. else if ( !stricmp( strCommand, VXCONSOLE_COMMAND_PREFIX "!" ) )
  206. {
  207. // empty ping command
  208. // must be done as a synchronous command with a response because there
  209. // is no way to bind an asynch response to the owner
  210. bIgnorePingResponse = true;
  211. }
  212. HRESULT hr = DmSendCommand( g_pdmConnection, strCommand, strResponse, &dwResponseLen );
  213. if ( !FAILED( hr ) )
  214. {
  215. // success
  216. switch ( hr )
  217. {
  218. case XBDM_NOERR:
  219. if ( !bIgnorePingResponse )
  220. {
  221. // skip past possible ack prefix
  222. ptr = strstr( strResponse, VXCONSOLE_COMMAND_ACK );
  223. if ( ptr )
  224. {
  225. ptr += strlen( VXCONSOLE_COMMAND_ACK );
  226. // ignore remote acknowledge response
  227. if ( !stricmp( ptr, "OK" ) )
  228. break;
  229. }
  230. else
  231. {
  232. ptr = strResponse;
  233. }
  234. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", ptr );
  235. }
  236. break;
  237. case XBDM_MULTIRESPONSE:
  238. // multi-line response - loop, looking for end of response
  239. while ( 1 )
  240. {
  241. dwResponseLen = sizeof( strResponse );
  242. hr = DmReceiveSocketLine( g_pdmConnection, strResponse, &dwResponseLen );
  243. if ( FAILED( hr ) || strResponse[0] == '.' )
  244. break;
  245. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", strResponse );
  246. }
  247. break;
  248. case XBDM_BINRESPONSE:
  249. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Binary response - not implemented\n" );
  250. break;
  251. case XBDM_READYFORBIN:
  252. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Ready for binary - not implemented\n" );
  253. break;
  254. default:
  255. ConsoleWindowPrintf( XBX_CLR_RED, "Unknown Response: ( %s ).\n", strResponse );
  256. break;
  257. }
  258. }
  259. SetEvent( g_hCommandReadyEvent );
  260. return hr;
  261. }
  262. //-----------------------------------------------------------------------------
  263. // PrintToQueue
  264. //
  265. // Formats the string and adds it to the print queue
  266. //-----------------------------------------------------------------------------
  267. void PrintToQueue( COLORREF rgb, LPCTSTR strFormat, ... )
  268. {
  269. char buffer[MAX_QUEUEDSTRINGLEN];
  270. // enter critical section so we don't try to process the list
  271. EnterCriticalSection( &g_PrintQueue.CriticalSection );
  272. assert( g_PrintQueue.numMessages <= MAX_QUEUEDSTRINGS );
  273. // when the queue is full, the main thread is probably blocked and not dequeing
  274. if ( !g_captureGameSpew || g_PrintQueue.numMessages == MAX_QUEUEDSTRINGS )
  275. {
  276. LeaveCriticalSection( &g_PrintQueue.CriticalSection );
  277. return;
  278. }
  279. va_list arglist;
  280. va_start( arglist, strFormat );
  281. int len = _vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, strFormat, arglist );
  282. if ( len == -1 )
  283. {
  284. buffer[sizeof(buffer)-1] = '\0';
  285. }
  286. va_end( arglist );
  287. // queue the message into the next slot
  288. g_PrintQueue.pMessages[g_PrintQueue.numMessages] = Sys_CopyString( buffer );
  289. g_PrintQueue.aColors[g_PrintQueue.numMessages++] = rgb;
  290. // ensure we post a message to process the print queue
  291. if ( g_PrintQueue.numMessages == 1 )
  292. PostMessage( g_hDlgMain, WM_USER, 0, 0 );
  293. // the main thread can now safely process the list
  294. LeaveCriticalSection( &g_PrintQueue.CriticalSection );
  295. }
  296. //-----------------------------------------------------------------------------
  297. // ProcessPrintQueue
  298. //
  299. //-----------------------------------------------------------------------------
  300. void ProcessPrintQueue()
  301. {
  302. // enter critical section so we don't try to add anything while we're processing
  303. EnterCriticalSection( &g_PrintQueue.CriticalSection );
  304. // dequeue all entries
  305. for ( int i = 0; i < g_PrintQueue.numMessages; i++ )
  306. {
  307. ConsoleWindowPrintf( g_PrintQueue.aColors[i], "%s", g_PrintQueue.pMessages[i] );
  308. Sys_Free( g_PrintQueue.pMessages[i] );
  309. }
  310. g_PrintQueue.numMessages = 0;
  311. // now we can safely add to the list
  312. LeaveCriticalSection( &g_PrintQueue.CriticalSection );
  313. }
  314. //-----------------------------------------------------------------------------
  315. // ConsoleWindowPrintf
  316. //
  317. // Writes out a string directly to the console window
  318. //-----------------------------------------------------------------------------
  319. int ConsoleWindowPrintf( COLORREF rgb, LPCTSTR strFormat, ... )
  320. {
  321. int dwStrLen;
  322. char strTemp[512];
  323. va_list arglist;
  324. CHARRANGE cr = { -1, -2 };
  325. if ( rgb != XBX_CLR_DEFAULT )
  326. {
  327. // set whatever colors, etc. they want
  328. CHARFORMAT cf = {0};
  329. cf.cbSize = sizeof( cf );
  330. cf.dwMask = CFM_COLOR;
  331. cf.dwEffects = 0;
  332. cf.crTextColor = rgb;
  333. SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&cf );
  334. }
  335. // Get our string to print
  336. va_start( arglist, strFormat );
  337. dwStrLen = _vsnprintf( strTemp, sizeof( strTemp ), strFormat, arglist );
  338. va_end( arglist );
  339. // Move the selection to the end
  340. SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_EXSETSEL, 0, ( LPARAM )&cr );
  341. // Add the text and scroll it into view
  342. SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_REPLACESEL, 0, ( LONG )( LPSTR )strTemp );
  343. SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SCROLLCARET, 0, 0L );
  344. if ( g_bPlayTestMode )
  345. {
  346. char szLogPath[MAX_PATH];
  347. char szLogName[MAX_PATH];
  348. V_snprintf( szLogName, sizeof( szLogName ), "vxconsole_%s.log", g_xboxTargetName );
  349. V_ComposeFileName( g_localPath, szLogName, szLogPath, sizeof( szLogPath ) );
  350. FILE *fp = fopen( szLogPath, "at+" );
  351. if ( fp )
  352. {
  353. fprintf( fp, strTemp );
  354. fclose( fp );
  355. }
  356. }
  357. return dwStrLen;
  358. }
  359. //-----------------------------------------------------------------------------
  360. // ProcessCommand
  361. //
  362. //-----------------------------------------------------------------------------
  363. bool ProcessCommand( const char* strCmdIn )
  364. {
  365. char strRemoteCmd[MAX_PATH + 10];
  366. TCHAR strCmdBak[MAX_PATH];
  367. char strCmd[MAX_PATH];
  368. char* argv[MAX_ARGVELEMS];
  369. BOOL isXCommand = FALSE;
  370. BOOL isLocal = FALSE;
  371. BOOL isRemote = FALSE;
  372. int iIndex;
  373. // local copy for destructive purposes
  374. strcpy( strCmd, strCmdIn );
  375. // copy of the original command string
  376. lstrcpyA( strCmdBak, strCmdIn );
  377. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "] %s\n", strCmd );
  378. // parse argstring into components
  379. int argc = CmdToArgv( strCmd, argv, MAX_ARGVELEMS );
  380. if ( !argc )
  381. {
  382. // empty command
  383. return true;
  384. }
  385. if ( ( iIndex = ComboBox_GetCount( g_hwndCommandCombo ) ) >= MAX_COMMANDHISTORY )
  386. {
  387. // Limit the history of items, purge oldest
  388. ComboBox_DeleteString( g_hwndCommandCombo, 0 );
  389. }
  390. // add to end of list
  391. iIndex = ComboBox_InsertItemData( g_hwndCommandCombo, -1, strCmdBak );
  392. ComboBox_SetCurSel( g_hwndCommandCombo, -1 );
  393. // find command in local list
  394. for ( int i=0; i<g_numLocalCommands; i++ )
  395. {
  396. if ( lstrcmpiA( g_localCommands[i].strCommand, argv[0] ) )
  397. {
  398. // no match
  399. continue;
  400. }
  401. isLocal = TRUE;
  402. if ( !g_localCommands[i].pfnHandler )
  403. {
  404. // no handler, remote xcommand
  405. isXCommand = TRUE;
  406. }
  407. if ( ( g_localCommands[i].flags & FN_XBOX ) && !g_connectedToXBox )
  408. {
  409. // not allowed yet
  410. ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to XBox.\n", argv[0] );
  411. return true;
  412. }
  413. else if ( ( g_localCommands[i].flags & FN_APP ) && !g_connectedToApp )
  414. {
  415. // not allowed yet
  416. ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] );
  417. return true;
  418. }
  419. if ( isXCommand )
  420. break;
  421. // do local command
  422. g_localCommands[i].pfnHandler( argc, argv );
  423. return true;
  424. }
  425. // find command in remote list
  426. if ( !isLocal && !isXCommand && g_connectedToApp )
  427. {
  428. for ( int i=0; i<g_numRemoteCommands; i++ )
  429. {
  430. if ( lstrcmpiA( g_remoteCommands[i]->strCommand, argv[0] ) )
  431. {
  432. // no match
  433. continue;
  434. }
  435. isRemote = TRUE;
  436. if ( !g_connectedToApp )
  437. {
  438. // not allowed yet
  439. ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] );
  440. return true;
  441. }
  442. break;
  443. }
  444. }
  445. if ( !isLocal && !isXCommand && !isRemote )
  446. {
  447. if ( !g_connectedToApp || g_numRemoteCommands != 0 )
  448. {
  449. // unrecognized
  450. ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not a recognized command.\n", argv[0] );
  451. return true;
  452. }
  453. }
  454. if ( isXCommand )
  455. {
  456. // send the xcommand directly
  457. lstrcpyA( strRemoteCmd, strCmdBak );
  458. }
  459. else
  460. {
  461. // add remote command prefix
  462. lstrcpyA( strRemoteCmd, VXCONSOLE_COMMAND_PREFIX "!" );
  463. lstrcatA( strRemoteCmd, strCmdBak );
  464. }
  465. // send the command to the Xbox
  466. HRESULT hr = DmAPI_SendCommand( strRemoteCmd, true );
  467. if ( FAILED( hr ) )
  468. {
  469. DmAPI_DisplayError( "DmSendCommand", hr );
  470. return false;
  471. }
  472. return TRUE;
  473. }
  474. //-----------------------------------------------------------------------------
  475. // CommandWindow_HandleKey
  476. //
  477. // Handle a WM_KEYDOWN in our RTF cmd window
  478. //-----------------------------------------------------------------------------
  479. BOOL CommandWindow_HandleKey( WPARAM wParam )
  480. {
  481. BOOL bHandled = FALSE;
  482. int curSel;
  483. int numItems;
  484. if ( wParam >= VK_F1 && wParam <= VK_F12 )
  485. {
  486. if ( Bindings_TranslateKey( wParam ) )
  487. {
  488. // handled
  489. return true;
  490. }
  491. }
  492. switch ( wParam )
  493. {
  494. case VK_TAB:
  495. case VK_UP:
  496. case VK_DOWN:
  497. if ( IsWindowVisible( g_hwndCommandHint ) )
  498. {
  499. // hint window open
  500. char hintCmd[MAX_PATH];
  501. char userCmd[MAX_PATH];
  502. // scroll through the hint selections
  503. curSel = SendMessage( g_hwndCommandHint, (UINT)LB_GETCURSEL, NULL, NULL );
  504. SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd );
  505. numItems = SendMessage( g_hwndCommandHint, (UINT)LB_GETCOUNT, NULL, NULL );
  506. if ( numItems < 0 )
  507. numItems = 0;
  508. if ( wParam == VK_TAB )
  509. {
  510. // get command typed so far
  511. ComboBox_GetText( g_hwndCommandCombo, userCmd, MAX_PATH );
  512. // strip the auto-space off the end
  513. int len = Q_strlen(userCmd);
  514. if ( userCmd[len-1] == ' ' )
  515. {
  516. userCmd[len-1] = '\0';
  517. }
  518. if ( !stricmp( userCmd, hintCmd ) )
  519. {
  520. // cycle to next or prev command with tab or shift-tab
  521. if ( GetKeyState(VK_SHIFT) < 0 )
  522. {
  523. wParam = VK_UP;
  524. }
  525. else
  526. {
  527. wParam = VK_DOWN;
  528. }
  529. }
  530. }
  531. // move the selection
  532. if ( wParam == VK_UP )
  533. curSel--;
  534. else if ( wParam == VK_DOWN )
  535. curSel++;
  536. if ( curSel < 0 )
  537. curSel = numItems - 1;
  538. else if ( curSel > numItems-1 )
  539. curSel = 0;
  540. if ( curSel < 0 )
  541. curSel = 0;
  542. // set the selection and get highlighted command
  543. SendMessage( g_hwndCommandHint, (UINT)LB_SETCURSEL, (WPARAM)curSel, NULL );
  544. SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd );
  545. // add a space to the end for easier parameter setting
  546. Q_strncat( hintCmd, " ", sizeof(hintCmd), 1 );
  547. // replace command string
  548. ComboBox_SetText( g_hwndCommandCombo, hintCmd );
  549. // set cursor to end of command
  550. SendMessage( g_hwndCommandCombo, (UINT)CB_SETEDITSEL, (WPARAM)0, MAKELONG( MAX_PATH,MAX_PATH ) );
  551. bHandled = TRUE;
  552. }
  553. else
  554. {
  555. curSel = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCURSEL, NULL, NULL );
  556. if ( curSel < 0 )
  557. {
  558. // combo box has no selection
  559. // override combo box behavior and set selection
  560. numItems = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCOUNT, NULL, NULL );
  561. if ( numItems > 0 )
  562. {
  563. if ( wParam == VK_UP )
  564. {
  565. // set to bottom of list
  566. curSel = numItems-1;
  567. }
  568. else if ( wParam == VK_DOWN )
  569. {
  570. // set to top of list
  571. curSel = 0;
  572. }
  573. SendMessage( g_hwndCommandCombo, (UINT)CB_SETCURSEL, (WPARAM)curSel, NULL );
  574. bHandled = TRUE;
  575. }
  576. }
  577. }
  578. break;
  579. case VK_RETURN:
  580. // user hit return in the combo box
  581. if ( ComboBox_GetDroppedState( g_hwndCommandCombo ) )
  582. {
  583. ComboBox_ShowDropdown( g_hwndCommandCombo, FALSE );
  584. }
  585. else
  586. {
  587. PostMessage( g_hDlgMain, WM_APP, 0, 0 );
  588. bHandled = TRUE;
  589. }
  590. break;
  591. }
  592. return bHandled;
  593. }
  594. //-----------------------------------------------------------------------------
  595. // CommandWindow_SubclassedProc
  596. //
  597. //-----------------------------------------------------------------------------
  598. LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  599. {
  600. switch ( msg )
  601. {
  602. case WM_SYSKEYDOWN:
  603. case WM_KEYDOWN:
  604. if ( CommandWindow_HandleKey( wParam ) )
  605. return 0;
  606. break;
  607. case WM_CHAR:
  608. if ( wParam == VK_RETURN )
  609. return 0;
  610. break;
  611. }
  612. return CallWindowProc( g_hwndCommandSubclassed, hDlg, msg, wParam, lParam );
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Main_SizeWindow
  616. //
  617. // Handles a WM_SIZE message by resizing all our child windows to match the main window
  618. //-----------------------------------------------------------------------------
  619. void Main_SizeWindow( HWND hDlg, UINT wParam, int cx, int cy )
  620. {
  621. if ( cx==0 || cy==0 )
  622. {
  623. RECT rcClient;
  624. GetClientRect( hDlg, &rcClient );
  625. cx = rcClient.right;
  626. cy = rcClient.bottom;
  627. }
  628. // if we're big enough, position our child windows
  629. if ( g_hwndCommandCombo && cx > 64 && cy > 64 )
  630. {
  631. RECT rcCmd;
  632. RECT rcHint;
  633. RECT rcOut;
  634. // fit the "command" combo box into our window
  635. GetWindowRect( g_hwndCommandCombo, &rcCmd );
  636. ScreenToClient( hDlg, ( LPPOINT )&rcCmd );
  637. ScreenToClient( hDlg, ( LPPOINT )&rcCmd + 1 );
  638. int x = rcCmd.left;
  639. int dx = cx - 8 - x;
  640. int dy = rcCmd.bottom - rcCmd.top;
  641. int y = cy - 8 - dy;
  642. SetWindowPos(
  643. g_hwndCommandCombo,
  644. NULL,
  645. x,
  646. y,
  647. dx,
  648. dy,
  649. SWP_NOZORDER );
  650. // position the "hint popup" window above the "command" window
  651. GetWindowRect( g_hwndCommandHint, &rcHint );
  652. ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint );
  653. ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint + 1 );
  654. SetWindowPos(
  655. g_hwndCommandHint,
  656. NULL,
  657. rcCmd.left,
  658. ( rcCmd.top - 4 ) - ( rcHint.bottom - rcHint.top + 1 ),
  659. 0,
  660. 0,
  661. SWP_NOSIZE | SWP_NOZORDER );
  662. // position the "Cmd" label
  663. RECT rcStaticCmd;
  664. HWND hStaticCmd = GetDlgItem( g_hDlgMain, IDC_LABEL );
  665. GetWindowRect( hStaticCmd, &rcStaticCmd );
  666. ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd );
  667. ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd + 1 );
  668. SetWindowPos(
  669. hStaticCmd,
  670. NULL,
  671. 8,
  672. y + ( dy - ( rcStaticCmd.bottom - rcStaticCmd.top ) ) / 2 - 1,
  673. 0,
  674. 0,
  675. SWP_NOSIZE | SWP_NOZORDER );
  676. // position the "output" window
  677. GetWindowRect( g_hwndOutputWindow, &rcOut );
  678. ScreenToClient( hDlg, ( LPPOINT )&rcOut );
  679. int dwWidth = cx - rcOut.left - 8;
  680. int dwHeight = y - rcOut.top - 8;
  681. SetWindowPos( g_hwndOutputWindow, NULL, 0, 0, dwWidth, dwHeight, SWP_NOMOVE | SWP_NOZORDER );
  682. }
  683. }
  684. //-----------------------------------------------------------------------------
  685. // _SortCommands
  686. //
  687. //-----------------------------------------------------------------------------
  688. int _SortCommands( const void* a, const void* b )
  689. {
  690. const char* strA = *( const char** )a;
  691. const char* strB = *( const char** )b;
  692. return ( stricmp( strA, strB ) );
  693. }
  694. //-----------------------------------------------------------------------------
  695. // EnableCommandHint
  696. //
  697. // Open/Close the command hint popup
  698. //-----------------------------------------------------------------------------
  699. void EnableCommandHint( bool enable )
  700. {
  701. int w = 0;
  702. int h = 0;
  703. int itemHeight;
  704. int i;
  705. int maxLen;
  706. int len;
  707. const char* cmds[256];
  708. int numLocalCommands;
  709. int numRemoteCommands;
  710. int curSel;
  711. if ( !enable )
  712. goto cleanUp;
  713. // get the current command
  714. char strCmd[MAX_PATH];
  715. ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH );
  716. if ( !strCmd[0] )
  717. {
  718. // user has typed nothing
  719. enable = false;
  720. goto cleanUp;
  721. }
  722. SendMessage( g_hwndCommandHint, ( UINT )LB_RESETCONTENT, NULL, NULL );
  723. // get a list of possible matches
  724. maxLen = 0;
  725. numLocalCommands = MatchLocalCommands( strCmd, cmds, 256 );
  726. numRemoteCommands = MatchRemoteCommands( strCmd, cmds+numLocalCommands, 256-numLocalCommands );
  727. for ( i=0; i<numLocalCommands+numRemoteCommands; i++ )
  728. {
  729. len = strlen( cmds[i] );
  730. if ( maxLen < len )
  731. maxLen = len;
  732. }
  733. if ( !maxLen )
  734. {
  735. // no matches
  736. enable = false;
  737. goto cleanUp;
  738. }
  739. // sort the list ( eschew listbox's autosorting )
  740. qsort( cmds, numLocalCommands+numRemoteCommands, sizeof( const char* ), _SortCommands );
  741. curSel = -1;
  742. len = strlen( strCmd );
  743. for ( i=0; i<numLocalCommands+numRemoteCommands; i++ )
  744. {
  745. // populate the listbox
  746. SendMessage( g_hwndCommandHint, ( UINT )LB_ADDSTRING, 0, ( LPARAM )cmds[i] );
  747. // determine first best match
  748. if ( curSel == -1 && !strnicmp( strCmd, cmds[i], len ) )
  749. curSel = i;
  750. }
  751. if ( curSel != -1 )
  752. {
  753. // set the selection to the first best string
  754. // ensure the top string is shown ( avoids odd auto-vscroll choices )
  755. SendMessage( g_hwndCommandHint, ( UINT )LB_SETCURSEL, ( WPARAM )curSel, NULL );
  756. if ( !curSel )
  757. SendMessage( g_hwndCommandHint, ( UINT )LB_SETTOPINDEX, 0, NULL );
  758. }
  759. RECT rcCmd;
  760. GetWindowRect( g_hwndCommandCombo, &rcCmd );
  761. ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd );
  762. ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd + 1 );
  763. // clamp listbox height to client space
  764. itemHeight = SendMessage( g_hwndCommandHint, ( UINT )LB_GETITEMHEIGHT, 0, NULL );
  765. if ( itemHeight <= 0 )
  766. {
  767. // oops, shouldn't happen
  768. enable = false;
  769. goto cleanUp;
  770. }
  771. h = ( numLocalCommands + numRemoteCommands )*itemHeight + 2;
  772. if ( h > rcCmd.top - 8)
  773. {
  774. h = rcCmd.top - 8;
  775. }
  776. // clamp listbox width
  777. w = ( maxLen + 5 ) * g_fixedFontMetrics.tmMaxCharWidth;
  778. // position the "hint popup" window above the "command" window
  779. SetWindowPos(
  780. g_hwndCommandHint,
  781. NULL,
  782. rcCmd.left,
  783. ( rcCmd.top - 4 ) - h,
  784. w,
  785. h,
  786. SWP_NOZORDER );
  787. cleanUp:
  788. BOOL isVisible = IsWindowVisible( g_hwndCommandHint );
  789. if ( !enable && isVisible )
  790. ShowWindow( g_hwndCommandHint, SW_HIDE );
  791. else if ( enable && !isVisible )
  792. ShowWindow( g_hwndCommandHint, SW_SHOWNA );
  793. }
  794. //-----------------------------------------------------------------------------
  795. // Main_DlgProc
  796. //
  797. //-----------------------------------------------------------------------------
  798. LRESULT CALLBACK Main_DlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
  799. {
  800. WORD wID = LOWORD( wParam );
  801. BOOL isConnect;
  802. switch ( message )
  803. {
  804. case WM_APP:
  805. // user has pressed enter
  806. // take the string from the command window and process it
  807. // extra room for \r\n
  808. char strCmd[MAX_PATH + 3];
  809. ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH );
  810. ProcessCommand( strCmd );
  811. ComboBox_SetText( g_hwndCommandCombo, "" );
  812. EnableCommandHint( false );
  813. break;
  814. case WM_USER:
  815. ProcessPrintQueue();
  816. break;
  817. case WM_TIMER:
  818. // Don't do auto-connect stuff while the Assert dialog is up
  819. // (it uses a synchronous command, so calling 'Dm' funcs here can cause a lockup)
  820. if ( !g_AssertDialogActive )
  821. {
  822. if ( wID == TIMERID_AUTOCONNECT )
  823. {
  824. AutoConnectTimerProc( hDlg, TIMERID_AUTOCONNECT );
  825. return 0L;
  826. }
  827. }
  828. break;
  829. case WM_CTLCOLORLISTBOX:
  830. case WM_CTLCOLOREDIT:
  831. SetBkColor( ( HDC )wParam,g_backgroundColor );
  832. return ( BOOL )g_hBackgroundBrush;
  833. case WM_SIZE:
  834. Main_SizeWindow( hDlg, wParam, LOWORD( lParam ), HIWORD( lParam ) );
  835. break;
  836. case WM_SYSCOMMAND:
  837. if ( wID == SC_CLOSE )
  838. {
  839. PostMessage( hDlg, WM_CLOSE, 0, 0 );
  840. return 0L;
  841. }
  842. break;
  843. case WM_CLOSE:
  844. // disconnect before closing
  845. lc_disconnect( 0, NULL );
  846. SaveConfig();
  847. DestroyWindow( hDlg );
  848. break;
  849. case WM_DESTROY:
  850. SubclassWindow( g_hwndCommandCombo, g_hwndCommandSubclassed );
  851. PostQuitMessage( 0 );
  852. return 0L;
  853. case WM_INITMENU:
  854. isConnect = g_connectedToXBox || g_connectedToApp;
  855. CheckMenuItem( ( HMENU )wParam, IDM_AUTOCONNECT, MF_BYCOMMAND | ( g_autoConnect ? MF_CHECKED : MF_UNCHECKED ) );
  856. CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREGAMESPEW, MF_BYCOMMAND | ( g_captureGameSpew ? MF_CHECKED : MF_UNCHECKED ) );
  857. CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREDEBUGSPEW, MF_BYCOMMAND | ( g_captureDebugSpew ? MF_CHECKED : MF_UNCHECKED ) );
  858. CheckMenuItem( ( HMENU )wParam, IDM_DEBUGCOMMANDS, MF_BYCOMMAND | ( g_debugCommands ? MF_CHECKED : MF_UNCHECKED ) );
  859. CheckMenuItem( ( HMENU )wParam, IDM_PLAYTESTMODE, MF_BYCOMMAND | ( g_bPlayTestMode ? MF_CHECKED : MF_UNCHECKED ) );
  860. EnableMenuItem( ( HMENU )wParam, IDM_SYNCFILES, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) );
  861. EnableMenuItem( ( HMENU )wParam, IDM_SYNCINSTALL, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) );
  862. return 0L;
  863. case WM_COMMAND:
  864. switch ( wID )
  865. {
  866. case IDC_COMMAND:
  867. switch ( HIWORD( wParam ) )
  868. {
  869. case CBN_EDITCHANGE:
  870. case CBN_SETFOCUS:
  871. EnableCommandHint( true );
  872. break;
  873. case CBN_KILLFOCUS:
  874. EnableCommandHint( false );
  875. break;
  876. }
  877. break;
  878. case IDM_CONFIG:
  879. ConfigDlg_Open();
  880. return 0L;
  881. case IDM_CAPTUREGAMESPEW:
  882. g_captureGameSpew ^= 1;
  883. return 0L;
  884. case IDM_CAPTUREDEBUGSPEW:
  885. g_captureDebugSpew ^= 1;
  886. return 0L;
  887. case IDM_DEBUGCOMMANDS:
  888. g_debugCommands ^= 1;
  889. return 0L;
  890. case IDM_BUG:
  891. BugDlg_Open();
  892. return 0L;
  893. case IDM_MEMORYDUMP:
  894. ShowMemDump_Open();
  895. return 0L;
  896. case IDM_TIMESTAMPLOG:
  897. TimeStampLog_Open();
  898. return 0L;
  899. case IDM_SYNCFILES:
  900. SyncFilesDlg_Open();
  901. return 0L;
  902. case IDM_SYNCINSTALL:
  903. InstallDlg_Open();
  904. return 0L;
  905. case IDM_EXCLUDEPATHS:
  906. ExcludePathsDlg_Open();
  907. return 0L;
  908. case IDM_CPU_SAMPLES:
  909. CpuProfileSamples_Open();
  910. return 0L;
  911. case IDM_CPU_HISTORY:
  912. CpuProfileHistory_Open();
  913. return 0L;
  914. case IDM_D3D_SAMPLES:
  915. TexProfileSamples_Open();
  916. return 0L;
  917. case IDM_D3D_HISTORY:
  918. TexProfileHistory_Open();
  919. return 0L;
  920. case IDM_SHOWMEMORYUSAGE:
  921. MemProfile_Open();
  922. return 0L;
  923. case IDM_PLAYTESTMODE:
  924. g_bPlayTestMode ^= 1;
  925. return 0L;
  926. case IDM_SHOWRESOURCES_TEXTURES:
  927. ShowTextures_Open();
  928. return 0L;
  929. case IDM_SHOWRESOURCES_MATERIALS:
  930. ShowMaterials_Open();
  931. return 0L;
  932. case IDM_SHOWRESOURCES_SOUNDS:
  933. ShowSounds_Open();
  934. return 0L;
  935. case IDM_SHOWRESOURCES_MODELS:
  936. NotImplementedYet();
  937. return 0L;
  938. case IDM_AUTOCONNECT:
  939. if ( g_connectedToXBox || g_connectedToApp || g_autoConnect )
  940. lc_disconnect( 0, NULL );
  941. else
  942. lc_autoConnect( 0, NULL );
  943. return 0L;
  944. case IDM_BINDINGS_EDIT:
  945. Bindings_Open();
  946. return 0L;
  947. case IDM_BINDINGS_BIND1:
  948. case IDM_BINDINGS_BIND2:
  949. case IDM_BINDINGS_BIND3:
  950. case IDM_BINDINGS_BIND4:
  951. case IDM_BINDINGS_BIND5:
  952. case IDM_BINDINGS_BIND6:
  953. case IDM_BINDINGS_BIND7:
  954. case IDM_BINDINGS_BIND8:
  955. case IDM_BINDINGS_BIND9:
  956. case IDM_BINDINGS_BIND10:
  957. case IDM_BINDINGS_BIND11:
  958. case IDM_BINDINGS_BIND12:
  959. Bindings_MenuSelection( wID );
  960. return 0L;
  961. case IDM_EXIT:
  962. PostMessage( hDlg, WM_CLOSE, 0, 0 );
  963. return 0L;
  964. }
  965. break;
  966. }
  967. return ( DefDlgProc( hDlg, message, wParam, lParam ) );
  968. }
  969. //-----------------------------------------------------------------------------
  970. // CmdToArgv
  971. //
  972. // Parses a string into argv and return # of args.
  973. //-----------------------------------------------------------------------------
  974. int CmdToArgv( char* str, char* argv[], int maxargs )
  975. {
  976. int argc = 0;
  977. int argcT = 0;
  978. char* strNil = str + lstrlenA( str );
  979. while ( argcT < maxargs )
  980. {
  981. // Eat whitespace
  982. while ( *str && ( *str==' ' ) )
  983. str++;
  984. if ( !*str )
  985. {
  986. argv[argcT++] = strNil;
  987. }
  988. else
  989. {
  990. // Find the end of this arg
  991. char chEnd = ( *str == '"' || *str == '\'' ) ? *str++ : ' ';
  992. char* strArgEnd = str;
  993. while ( *strArgEnd && ( *strArgEnd != chEnd ) )
  994. strArgEnd++;
  995. // Record this argument
  996. argv[argcT++] = str;
  997. argc = argcT;
  998. // Move strArg to the next argument ( or not, if we hit the end )
  999. str = *strArgEnd ? strArgEnd + 1 : strArgEnd;
  1000. *strArgEnd = 0;
  1001. }
  1002. }
  1003. return argc;
  1004. }
  1005. //-----------------------------------------------------------------------------
  1006. // CreateCommandHint
  1007. //
  1008. //-----------------------------------------------------------------------------
  1009. void CreateCommandHint()
  1010. {
  1011. // create the "hint" popup
  1012. g_hwndCommandHint = CreateWindowEx(
  1013. WS_EX_NOPARENTNOTIFY,
  1014. "LISTBOX",
  1015. "",
  1016. WS_BORDER|WS_CHILD|LBS_HASSTRINGS|WS_VSCROLL,
  1017. 0, 0, 100, 0,
  1018. g_hDlgMain,
  1019. ( HMENU )IDC_COMMANDHINT,
  1020. g_hInstance,
  1021. NULL );
  1022. // force the popup to head of z-order
  1023. // to draw over all other children
  1024. BringWindowToTop( g_hwndCommandHint );
  1025. // set font
  1026. SendDlgItemMessage( g_hDlgMain, IDC_COMMANDHINT, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE );
  1027. }
  1028. //-----------------------------------------------------------------------------
  1029. // CreateResources
  1030. //
  1031. //-----------------------------------------------------------------------------
  1032. bool CreateResources()
  1033. {
  1034. LOGFONT lf;
  1035. HFONT hFontOld;
  1036. HDC hDC;
  1037. int i;
  1038. // pull in common controls
  1039. INITCOMMONCONTROLSEX initCommon;
  1040. initCommon.dwSize = sizeof( INITCOMMONCONTROLSEX );
  1041. initCommon.dwICC = ICC_LISTVIEW_CLASSES|ICC_USEREX_CLASSES;
  1042. if ( !InitCommonControlsEx( &initCommon ) )
  1043. return false;
  1044. // pull in rich edit controls
  1045. g_hRichEdit = LoadLibrary( "Riched32.dll" );
  1046. if ( !g_hRichEdit )
  1047. return false;
  1048. g_backgroundColor = XBX_CLR_LTGREY;
  1049. g_hBackgroundBrush = CreateSolidBrush( g_backgroundColor );
  1050. // get icons
  1051. g_hIcons[ICON_APPLICATION] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_VXCONSOLE ) );
  1052. g_hIcons[ICON_DISCONNECTED] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_DISCONNECTED ) );
  1053. g_hIcons[ICON_CONNECTED_XBOX] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT1_ON ) );
  1054. g_hIcons[ICON_CONNECTED_APP0] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_OFF ) );
  1055. g_hIcons[ICON_CONNECTED_APP1] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_ON ) );
  1056. for ( i=0; i<MAX_ICONS; i++ )
  1057. {
  1058. if ( !g_hIcons[i] )
  1059. return false;
  1060. }
  1061. // get the font feight
  1062. hDC = GetWindowDC( NULL );
  1063. int nHeight = -MulDiv( VXCONSOLE_FONTSIZE, GetDeviceCaps( hDC, LOGPIXELSY ), 72 );
  1064. ReleaseDC( NULL, hDC );
  1065. // create fixed font
  1066. memset( &lf, 0, sizeof( LOGFONT ) );
  1067. lf.lfHeight = nHeight;
  1068. lf.lfWeight = 400;
  1069. strcpy( lf.lfFaceName, VXCONSOLE_FONT );
  1070. g_hFixedFont = CreateFontIndirect( &lf );
  1071. if ( !g_hFixedFont )
  1072. return false;
  1073. // create proportional font
  1074. memset( &lf, 0, sizeof( LOGFONT ) );
  1075. lf.lfHeight = -11;
  1076. lf.lfWeight = 400;
  1077. strcpy( lf.lfFaceName, "Tahoma" );
  1078. g_hProportionalFont = CreateFontIndirect( &lf );
  1079. if ( !g_hProportionalFont )
  1080. return false;
  1081. // get the font metrics
  1082. hDC = GetWindowDC( NULL );
  1083. hFontOld = ( HFONT )SelectObject( hDC, g_hFixedFont );
  1084. GetTextMetrics( hDC, &g_fixedFontMetrics );
  1085. SelectObject( hDC, hFontOld );
  1086. ReleaseDC( NULL, hDC );
  1087. return true;
  1088. }
  1089. //-----------------------------------------------------------------------------
  1090. // Shutdown
  1091. //
  1092. // Free all resources
  1093. //-----------------------------------------------------------------------------
  1094. void Shutdown()
  1095. {
  1096. BugReporter_FreeInterfaces();
  1097. if ( g_PrintQueue.bInit )
  1098. {
  1099. DeleteCriticalSection( &g_PrintQueue.CriticalSection );
  1100. g_PrintQueue.bInit = false;
  1101. }
  1102. if ( g_hCommandReadyEvent )
  1103. {
  1104. CloseHandle( g_hCommandReadyEvent );
  1105. g_hCommandReadyEvent = 0;
  1106. }
  1107. if ( g_hRichEdit )
  1108. {
  1109. FreeLibrary( g_hRichEdit );
  1110. g_hRichEdit = 0;
  1111. }
  1112. if ( g_hBackgroundBrush )
  1113. {
  1114. DeleteObject( g_hBackgroundBrush );
  1115. g_hBackgroundBrush = 0;
  1116. }
  1117. if ( g_hFixedFont )
  1118. {
  1119. DeleteObject( g_hFixedFont );
  1120. g_hFixedFont = 0;
  1121. }
  1122. if ( g_hProportionalFont )
  1123. {
  1124. DeleteObject( g_hProportionalFont );
  1125. g_hProportionalFont = 0;
  1126. }
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. // Startup
  1130. //
  1131. //-----------------------------------------------------------------------------
  1132. bool Startup()
  1133. {
  1134. // Load the xenon debugging dll (xbdm.dll) manually due to its absence from system path
  1135. const char *pPath = getenv( "path" );
  1136. const char *pXEDKDir = getenv( "xedk" );
  1137. if ( !pXEDKDir )
  1138. pXEDKDir = "";
  1139. int len = strlen( pPath ) + strlen( pXEDKDir ) + 256;
  1140. char *pNewPath = (char*)_alloca( len );
  1141. sprintf( pNewPath, "path=%s;%s\\bin\\win32", pPath, pXEDKDir );
  1142. _putenv( pNewPath );
  1143. HMODULE hXBDM = LoadLibrary( TEXT( "xbdm.dll" ) );
  1144. if ( !hXBDM )
  1145. {
  1146. if ( pXEDKDir[0] )
  1147. Sys_Error( "Couldn't load xbdm.dll" );
  1148. else
  1149. Sys_Error( "Couldn't load xbdm.dll\nXEDK environment variable not set." );
  1150. }
  1151. LoadConfig();
  1152. if ( !CreateResources() )
  1153. return false;
  1154. // set up our print queue
  1155. InitializeCriticalSection( &g_PrintQueue.CriticalSection );
  1156. g_PrintQueue.bInit = true;
  1157. // manual reset, initially signaled
  1158. g_hCommandReadyEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
  1159. // set up our window class
  1160. WNDCLASS wndclass;
  1161. memset( &wndclass, 0, sizeof( wndclass ) );
  1162. wndclass.style = 0;
  1163. wndclass.lpfnWndProc = Main_DlgProc;
  1164. wndclass.cbClsExtra = 0;
  1165. wndclass.cbWndExtra = VXCONSOLE_WINDOWBYTES;
  1166. wndclass.hInstance = g_hInstance;
  1167. wndclass.hIcon = g_hIcons[ICON_DISCONNECTED];
  1168. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  1169. wndclass.hbrBackground = g_hBackgroundBrush;
  1170. wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_VXCONSOLE );
  1171. wndclass.lpszClassName = VXCONSOLE_CLASSNAME;
  1172. if ( !RegisterClass( &wndclass ) )
  1173. return false;
  1174. g_hAccel = LoadAccelerators( g_hInstance, MAKEINTRESOURCE( IDR_MAIN_ACCEL ) );
  1175. if ( !g_hAccel )
  1176. return false;
  1177. // Create our main dialog
  1178. g_hDlgMain = CreateDialog( g_hInstance, MAKEINTRESOURCE( IDD_VXCONSOLE ), 0, NULL );
  1179. if ( !g_hDlgMain )
  1180. return false;
  1181. SetWindowLong( g_hDlgMain, VXCONSOLE_CONFIGID, g_configID );
  1182. if ( !BugDlg_Init() )
  1183. return false;
  1184. if ( !CpuProfile_Init() )
  1185. return false;
  1186. if ( !TexProfile_Init() )
  1187. return false;
  1188. if ( !MemProfile_Init() )
  1189. return false;
  1190. if ( !Bindings_Init() )
  1191. return false;
  1192. if ( !SyncFilesDlg_Init() )
  1193. return false;
  1194. if ( !ShowMaterials_Init() )
  1195. return false;
  1196. if ( !ShowTextures_Init() )
  1197. return false;
  1198. if ( !ShowSounds_Init() )
  1199. return false;
  1200. if ( !ShowMemDump_Init() )
  1201. return false;
  1202. if ( !TimeStampLog_Init() )
  1203. return false;
  1204. if ( !ExcludePathsDlg_Init() )
  1205. return false;
  1206. g_hwndOutputWindow = GetDlgItem( g_hDlgMain, IDC_OUTPUT );
  1207. g_hwndCommandCombo = GetDlgItem( g_hDlgMain, IDC_COMMAND );
  1208. CreateCommandHint();
  1209. // subclass our dropdown command listbox to handle return key
  1210. g_hwndCommandSubclassed = SubclassWindow( GetWindow( g_hwndCommandCombo, GW_CHILD ), CommandWindow_SubclassedProc );
  1211. // Change the font type of the output window to courier
  1212. CHARFORMAT cf;
  1213. cf.cbSize = sizeof( CHARFORMAT );
  1214. SendMessage( g_hwndOutputWindow, EM_GETCHARFORMAT, 0, ( LPARAM )&cf );
  1215. cf.dwMask &= ~CFM_COLOR;
  1216. cf.yHeight = VXCONSOLE_FONTSIZE*20;
  1217. lstrcpyA( cf.szFaceName, VXCONSOLE_FONT );
  1218. SendMessage( g_hwndOutputWindow, EM_SETCHARFORMAT, SCF_ALL, ( LPARAM )&cf );
  1219. SendMessage( g_hwndOutputWindow, EM_SETBKGNDCOLOR, 0, g_backgroundColor );
  1220. // ensure the output window adheres to its z ordering
  1221. LONG style = GetWindowLong( g_hwndOutputWindow, GWL_STYLE );
  1222. style |= WS_CLIPSIBLINGS;
  1223. SetWindowLong( g_hwndOutputWindow, GWL_STYLE, style );
  1224. // change the font of the command and its hint window to courier
  1225. SendDlgItemMessage( g_hDlgMain, IDC_COMMAND, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE );
  1226. // set the window title
  1227. SetMainWindowTitle();
  1228. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "VXConsole %s [%s Build: %s %s] [Protocol: %d]\n", VXCONSOLE_VERSION, VXCONSOLE_BUILDTYPE, __DATE__, __TIME__, VXCONSOLE_PROTOCOL_VERSION );
  1229. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "type '*help' for list of commands...\n\n" );
  1230. g_currentIcon = -1;
  1231. SetConnectionIcon( ICON_DISCONNECTED );
  1232. if ( g_alwaysAutoConnect)
  1233. {
  1234. // user wants to auto-connect at startup
  1235. lc_autoConnect( 0, NULL );
  1236. }
  1237. if ( g_mainWindowRect.right && g_mainWindowRect.bottom )
  1238. MoveWindow( g_hDlgMain, g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right-g_mainWindowRect.left, g_mainWindowRect.bottom-g_mainWindowRect.top, FALSE );
  1239. // ready for display
  1240. int cmdShow = SW_SHOWNORMAL;
  1241. if ( g_startMinimized )
  1242. cmdShow = SW_SHOWMINIMIZED;
  1243. ShowWindow( g_hDlgMain, cmdShow );
  1244. // success
  1245. return true;
  1246. }
  1247. //-----------------------------------------------------------------------------
  1248. // WinMain
  1249. //
  1250. // Entry point for program
  1251. //-----------------------------------------------------------------------------
  1252. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow )
  1253. {
  1254. bool error = true;
  1255. MSG msg = {0};
  1256. g_hInstance = hInstance;
  1257. g_bSuppressBlink = ParseCommandLineArg( pCmdLine, "-noblink", NULL, 0 );
  1258. // optional -config <ID> can specify a specific configuration
  1259. char buff[128];
  1260. buff[0] = '\0';
  1261. ParseCommandLineArg( pCmdLine, "-config ", buff, sizeof( buff ) );
  1262. g_configID = atoi( buff );
  1263. MakeConfigString( VXCONSOLE_REGISTRY, g_configID, buff, sizeof( buff ) );
  1264. Sys_SetRegistryPrefix( buff );
  1265. HWND hwnd = FindWindow( VXCONSOLE_CLASSNAME, NULL );
  1266. if ( hwnd && GetWindowLong( hwnd, VXCONSOLE_CONFIGID ) == g_configID )
  1267. {
  1268. // single instance only
  1269. // bring other version to foreground
  1270. if ( IsIconic( hwnd ) )
  1271. ShowWindow( hwnd, SW_RESTORE );
  1272. SetForegroundWindow( hwnd );
  1273. return ( FALSE );
  1274. }
  1275. if ( !Startup() )
  1276. goto cleanUp;
  1277. // message pump
  1278. while ( GetMessage( &msg, NULL, 0, 0 ) )
  1279. {
  1280. if ( !TranslateAccelerator( g_hDlgMain, g_hAccel, &msg ) )
  1281. {
  1282. TranslateMessage( &msg );
  1283. DispatchMessage( &msg );
  1284. }
  1285. }
  1286. // no-error, end of app
  1287. error = false;
  1288. cleanUp:
  1289. if ( error )
  1290. {
  1291. char str[255];
  1292. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL );
  1293. MessageBox( NULL, str, NULL, MB_OK );
  1294. }
  1295. Shutdown();
  1296. return ( msg.wParam );
  1297. }