home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / Maze / MazeConsoleClient / ConsoleGraphics.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  36.8 KB  |  1,118 lines

  1. //----------------------------------------------------------------------------
  2. // File: consolegraphics.cpp
  3. //
  4. // Desc: see main.cpp
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #define D3D_OVERLOADS
  10. #include <windows.h>
  11. #include <d3dx.h>
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <mmsystem.h>
  15. #include <process.h>
  16. #include <dxerr8.h>
  17. #include <tchar.h>
  18. #include <dplay8.h>
  19. #include "SyncObjects.h"
  20. #include "DummyConnector.h"
  21. #include "MazeApp.h"
  22. #include "IMazeGraphics.h"
  23. #include "ConsoleGraphics.h"
  24.  
  25. static CConsoleGraphics* s_pGraphics = NULL;
  26.  
  27.  
  28.  
  29. //-----------------------------------------------------------------------------
  30. // Name:
  31. // Desc:
  32. //-----------------------------------------------------------------------------
  33. CConsoleGraphics::CConsoleGraphics()
  34. {
  35.     s_pGraphics         = this;
  36.  
  37.     m_bQuitThread       = FALSE;
  38.     m_pMazeApp          = NULL;
  39.     m_dwNextOutput      = 0;
  40.     m_hStdOut           = NULL;
  41.     m_dwNumCmdLines     = 11;
  42.     m_dwSeperatorLine   = 0;
  43.     m_dwNumLogLines     = 0;
  44.     m_dwWindowSizeY     = 0;
  45.     m_bLocalLoopback    = TRUE;
  46. }
  47.  
  48.  
  49.  
  50.  
  51. //-----------------------------------------------------------------------------
  52. // Name:
  53. // Desc:
  54. //-----------------------------------------------------------------------------
  55. CConsoleGraphics::~CConsoleGraphics()
  56. {
  57. }
  58.  
  59.  
  60.  
  61.  
  62. //-----------------------------------------------------------------------------
  63. // Name:
  64. // Desc:
  65. //-----------------------------------------------------------------------------
  66. VOID CConsoleGraphics::Init( CMazeApp* pMazeApp, CDPlay8Client* pDP8Client, 
  67.                              CMazeClient* pMazeClient )
  68. {
  69.     m_pMazeApp      = pMazeApp;
  70.     m_pMazeClient   = pMazeClient;
  71.     m_pDP8Client    = pDP8Client;
  72. }
  73.  
  74.  
  75.  
  76.  
  77. //-----------------------------------------------------------------------------
  78. // Name:
  79. // Desc:
  80. //-----------------------------------------------------------------------------
  81. HRESULT CConsoleGraphics::Create( HINSTANCE hInstance )
  82. {
  83.     // Set a console control handler so we can clean 
  84.     // up gracefully if we're forcibly shut down
  85.     SetConsoleCtrlHandler( CtrlHandler, TRUE );
  86.     m_hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
  87.  
  88.     m_pConfig = m_pMazeApp->GetConfig();
  89.  
  90.     if( FALSE == ParseCommandLine() )
  91.         return E_FAIL; // stop the app now
  92.  
  93.     if( m_pConfig->bAutoConnnect )
  94.     {
  95.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Type 'AUTOCONNECT OFF' to stop automatically connecting upon startup.") );
  96.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Type 'SETUP' to change current connections settings.") );
  97.     }
  98.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Type 'HELP' for a list of commands.") );
  99.     
  100.     // Set up the console
  101.     SetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), 
  102.                     ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT );
  103.  
  104.     m_dwLogBufferNext = 0;
  105.     m_dwCmdBufferNext = 0;
  106.     m_dwLastPrompt    = 0;
  107.     m_dwCaretPos      = 9;
  108.     m_dwNumProcessed  = 0;
  109.  
  110.     ZeroMemory( m_szCmdBuffer, sizeof(TCHAR)*MAX_CMD_LINES*256 );
  111.     ZeroMemory( m_szLogBuffer, sizeof(TCHAR)*MAX_LOG_LINES*256 );
  112.  
  113.     GetConsoleScreenBufferInfo( m_hStdOut, &m_SavedConsoleInfo );
  114.  
  115.     m_dwWindowSizeY   = 30;
  116.     m_dwSeperatorLine = m_dwWindowSizeY - m_dwNumCmdLines - 2;
  117.     m_dwNumLogLines   = m_dwWindowSizeY - m_dwNumCmdLines - 3;
  118.         
  119.     SetupConsole( m_dwWindowSizeY );
  120.     ClearScreen();
  121.  
  122.     return S_OK;
  123. }
  124.  
  125.  
  126.  
  127.  
  128. //-----------------------------------------------------------------------------
  129. // Name:
  130. // Desc:
  131. //-----------------------------------------------------------------------------
  132. INT CConsoleGraphics::Run()
  133. {
  134.     BOOL bHaveConnectSettings = m_pConfig->bAutoConnnect;
  135.  
  136.     // Allow immediate connect only if we already have the
  137.     // connection settings
  138.     m_pMazeApp->SetAllowConnect( bHaveConnectSettings );
  139.  
  140.     // Spin up a thread to record/display the output
  141.     UINT dwPromptThreadID;
  142.     m_hPromptThread = (HANDLE)_beginthreadex( NULL, 0, StaticPromptThread, 
  143.                                               NULL, 0, &dwPromptThreadID );
  144.  
  145.     FLOAT fElapsedTime;
  146.     while( !m_bQuitThread )
  147.     {
  148.         fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  149.         m_pMazeApp->FrameMove( fElapsedTime );
  150.  
  151.         // Sleep for a little bit to avoid maxing out CPU
  152.         Sleep( 30 );
  153.     };
  154.  
  155.     // Wait for threads to shutdown
  156.     WaitForSingleObject( m_hPromptThread, INFINITE );
  157.     CloseHandle( m_hPromptThread );
  158.  
  159.     return 0;
  160. }
  161.  
  162.  
  163.  
  164.  
  165. //-----------------------------------------------------------------------------
  166. // Name:
  167. // Desc:
  168. //-----------------------------------------------------------------------------
  169. void CConsoleGraphics::Shutdown()
  170. {
  171.     RestoreOldConsoleSettings();
  172. }
  173.  
  174.  
  175.  
  176. //-----------------------------------------------------------------------------
  177. // Name: 
  178. // Desc: 
  179. //-----------------------------------------------------------------------------
  180. WCHAR** CConsoleGraphics::ConvertCommandLineToArgvW( WCHAR* strCommandLine, int* argc )
  181. {
  182.     WCHAR** argv = new WCHAR*[100];
  183.     WCHAR* wstrTemp;
  184.     WCHAR* wstrLast;
  185.     int i = 0;
  186.     
  187.     wstrLast = strCommandLine;
  188.     while( i < 100 )
  189.     {
  190.         argv[i] = new WCHAR[MAX_PATH];
  191.         wcscpy( argv[i], wstrLast );
  192.         wstrTemp = wcschr( argv[i], L' ' );
  193.         if( wstrTemp )
  194.         {
  195.             wstrLast = wstrTemp + 1;
  196.             *wstrTemp = 0;
  197.             i++;
  198.         }
  199.         else
  200.         {
  201.             break;
  202.         }
  203.     }
  204.  
  205.     *argc = i + 1;
  206.     return argv;
  207. }
  208.  
  209.  
  210.  
  211.  
  212. //-----------------------------------------------------------------------------
  213. // Name: 
  214. // Desc: 
  215. //-----------------------------------------------------------------------------
  216. BOOL CConsoleGraphics::ParseCommandLine()
  217. {
  218.     int argc = 0;
  219.     int i;
  220.     WCHAR** argv;
  221.  
  222.     argv = ConvertCommandLineToArgvW( GetCommandLineW(), &argc );
  223.  
  224.     BOOL bParamFound = FALSE;
  225.     BOOL bContinue   = TRUE;
  226.  
  227.     for ( i = 1 ; i < argc ; i++ )
  228.     {
  229.         const WCHAR* arg = argv[i];
  230.  
  231.         if( arg[0] == L'/' || arg[0] == L'-' )
  232.         {
  233.             if( _wcsicmp( arg+1, L"m" ) == 0 )
  234.             {
  235.                 m_pConfig->bConnectToMicrosoftSite = TRUE;
  236.                 m_pConfig->bConnectToLocalServer   = FALSE;
  237.                 m_pConfig->bConnectToRemoteServer  = FALSE;
  238.                 m_pConfig->dwStressConnect = FALSE;
  239.  
  240.                 bParamFound = TRUE;
  241.             }
  242.             else if( _wcsicmp( arg+1, L"l" ) == 0 )
  243.             {
  244.                 m_pConfig->bConnectToMicrosoftSite = FALSE;
  245.                 m_pConfig->bConnectToLocalServer   = TRUE;
  246.                 m_pConfig->bConnectToRemoteServer  = FALSE;
  247.                 m_pConfig->dwStressConnect = FALSE;
  248.  
  249.                 bParamFound = TRUE;
  250.             }
  251.             else if( arg[1] == L'r' || arg[1] == L'R' )
  252.             {
  253.                 m_pConfig->bConnectToMicrosoftSite = FALSE;
  254.                 m_pConfig->bConnectToLocalServer   = FALSE;
  255.                 m_pConfig->bConnectToRemoteServer  = TRUE;
  256.                 m_pConfig->dwStressConnect = FALSE;
  257.                     
  258.                 bParamFound = TRUE;
  259.  
  260.                 if( arg[2] == L':' )
  261.                 {
  262.                     DXUtil_ConvertWideStringToGeneric( m_pConfig->szIPAddress, arg+3 );
  263.                 }
  264.             }   
  265.             else if( _wcsnicmp( arg+1, L"SPThreads:", 8 ) == 0 )
  266.             {
  267.                 // Points to the number of SP threads the user wants to use.
  268.                 m_pConfig->dwSPThreads = _wtoi( arg+11 ); 
  269.                 bParamFound = TRUE;
  270.  
  271.                 if(m_pConfig->dwSPThreads > MAX_SP_THREADS || m_pConfig->dwSPThreads < MIN_SP_THREADS)
  272.                 {
  273.                     printf( "Invalid SPThreads Value \n" );
  274.                     printf( "  SPThreads Value must be between %i and %i.\n",MIN_SP_THREADS, MAX_SP_THREADS);
  275.                     printf( "  Format: MazeConsoleClient.exe [/SPThreads:n] : Sets number of SP Threads to n \n\n" );
  276.  
  277.                     bContinue = FALSE;
  278.                 }
  279.             }
  280.             else if( _wcsnicmp( arg+1, L"SPBuffer:", 8 ) == 0 )
  281.             {
  282.                 // Points to the size of the SP Buffer user wants to use.
  283.                 DWORD spBufferSize = _wtoi( arg+10 );
  284.                 bParamFound = TRUE;
  285.  
  286.                 if( spBufferSize > MAX_SP_BUFFER )
  287.                 {
  288.                     printf( "Invalid SPBuffer Value \n" );
  289.                     printf( "  SPBuffer Value must be between 0 and %i.\n", MAX_SP_BUFFER);
  290.                     printf( "  Format: MazeConsoleClient.exe [/SPBuffer:n] : Sets SP Buffer Size to n \n\n" );
  291.  
  292.                     bContinue = FALSE;
  293.                 }
  294.  
  295.                 // Wait to assign since our buffer size is initialized to f's
  296.                 m_pConfig->dwSPBufferSize = spBufferSize;
  297.                 
  298.             }
  299.             else if( _wcsnicmp( arg+1, L"StressConnect:", 7 ) == 0 )
  300.             {
  301.                 m_pConfig->bConnectToMicrosoftSite = FALSE;
  302.                 m_pConfig->bConnectToLocalServer   = FALSE;
  303.                 m_pConfig->bConnectToRemoteServer  = FALSE;
  304.  
  305.                 // Points to the first connection attempt.
  306.                 m_pConfig->dwStressConnect = 1;
  307.                 bParamFound = TRUE;
  308.  
  309.                 if( arg[14] == L':' )
  310.                 {
  311.                     DXUtil_ConvertWideStringToGeneric( m_pConfig->szIPAddress, arg+15 );
  312.                 }
  313.             }   
  314.             else if( _wcsicmp( arg+1, L"d" ) == 0 || 
  315.                 _wcsicmp( arg+1, L"d+" ) == 0 )
  316.             {
  317.                 m_pConfig->bAutoDisconnnect = TRUE;
  318.                 bParamFound = TRUE;
  319.             }   
  320.             else if( _wcsicmp( arg+1, L"d-" ) == 0 )
  321.             {
  322.                 m_pConfig->bAutoDisconnnect = FALSE;
  323.                 bParamFound = TRUE;
  324.             }   
  325.             if( _wcsicmp( arg+1, L"f" ) == 0 || 
  326.                 _wcsicmp( arg+1, L"f+" ) == 0 )
  327.             {
  328.                 m_pConfig->bFileLogging = TRUE;
  329.                 bParamFound = TRUE;
  330.             }   
  331.             else if( _wcsicmp( arg+1, L"f-" ) == 0 )
  332.             {
  333.                 m_pConfig->bFileLogging = FALSE;
  334.                 bParamFound = TRUE;
  335.             }
  336.             else if( _wcsnicmp( arg+1, L"log:", 2 ) == 0 )
  337.             {
  338.                 m_pConfig->dwLogLevel = _wtoi( arg+5 );
  339.                 bParamFound = TRUE;
  340.             }
  341.             else if( _wcsicmp( arg+1, L"?" ) == 0 )
  342.             {
  343.                 printf( "MazeConsoleClient\n" );
  344.                 printf( "  Format: MazeConsoleClient.exe [/M] [/L] [/R[:ipaddress]] [/D] [/F] [/LOG]\n" );
  345.                 printf( "\n" );
  346.                 printf( "  Options:\n" );
  347.                 printf( "           /M  : connects to Microsoft server\n" );
  348.                 printf( "           /L  : connects to local server\n" );
  349.                 printf( "           /R[:ipaddress] : connects to remote server at [ipaddress]\n" );
  350.                 printf( "           /D+ : turns on auto-disconnecting\n" );
  351.                 printf( "           /D- : turns off auto-disconnecting\n" );
  352.                 printf( "           /F+ : turns on file logging\n" );
  353.                 printf( "           /F- : turns off file logging\n" );
  354.                 printf( "           /Log:n : sets the log level to n\n" );
  355.                 printf( "           /SPThreads:n : SP threads to n. Range %d - %d\n", MIN_SP_THREADS, MAX_SP_THREADS );
  356.                 printf( "           /SPBuffer:n : SP buffer size to n. Range 0 - %d\n", MAX_SP_BUFFER );
  357.                 printf( "           /StressConnect[:ipaddress] : tries [ipaddress], then local server.\n" );
  358.                 printf( "\n" );
  359.                 printf( "  Examples: \n" );
  360.                 printf( "       MazeConsoleClient /F /LOG:1\n" );
  361.                 printf( "       MazeConsoleClient /M /D+\n" );
  362.                 printf( "       MazeConsoleClient /R:myserver.myip.com /F-\n" );
  363.  
  364.                 bContinue = FALSE;
  365.             }   
  366.         }
  367.     }
  368.  
  369.     if( bParamFound )
  370.     {
  371.         m_pConfig->bAutoConnnect = TRUE;
  372.         m_pMazeApp->SetSaveSettings( FALSE );
  373.     }
  374.     
  375.     for ( i = 1 ; i < argc ; i++ )
  376.     {
  377.         SAFE_DELETE_ARRAY( argv[i] );    
  378.     }
  379.     SAFE_DELETE_ARRAY( argv );
  380.     
  381.     return bContinue;
  382. }
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389. //-----------------------------------------------------------------------------
  390. // Name: 
  391. // Desc: 
  392. //-----------------------------------------------------------------------------
  393. BOOL WINAPI CConsoleGraphics::CtrlHandler( DWORD type )
  394. {
  395.     switch ( type )
  396.     {
  397.         case CTRL_C_EVENT:
  398.         case CTRL_BREAK_EVENT:
  399.         case CTRL_CLOSE_EVENT:
  400.         case CTRL_LOGOFF_EVENT:
  401.         case CTRL_SHUTDOWN_EVENT:
  402.             // Signal thread to quit
  403.             FreeConsole();
  404.             s_pGraphics->m_bQuitThread = TRUE;
  405.             return TRUE;
  406.     }
  407.  
  408.     return FALSE;
  409. }
  410.  
  411.  
  412.  
  413.  
  414. //-----------------------------------------------------------------------------
  415. // Name: 
  416. // Desc: 
  417. //-----------------------------------------------------------------------------
  418. VOID CConsoleGraphics::HandleOutputMsg( EnumLineType enumLineType, TCHAR* strLine )
  419. {
  420.     DWORD i;
  421.     DWORD dwCoordY;
  422.  
  423.     switch( enumLineType )
  424.     {
  425.         case LINE_LOG:
  426.         {
  427.             _tcscpy( m_szLogBuffer[m_dwLogBufferNext], strLine );
  428.  
  429.             m_dwLogBufferNext++;
  430.             m_dwLogBufferNext %= m_dwNumLogLines;
  431.             dwCoordY = 0;
  432.  
  433.             for( i=m_dwLogBufferNext; i<m_dwNumLogLines; i++ )
  434.             {
  435.                 dwCoordY++;
  436.                 WriteLine( dwCoordY, m_szLogBuffer[i] );
  437.             }
  438.  
  439.             for( i=0; i<m_dwLogBufferNext; i++ )
  440.             {
  441.                 dwCoordY++;
  442.                 WriteLine( dwCoordY, m_szLogBuffer[i] );
  443.             }
  444.             break;
  445.         }
  446.  
  447.         case LINE_PROMPT:
  448.         case LINE_CMD:
  449.         {
  450.             // Add m_szOutputBuffer[m_dwNextOutput] to szCmdBuffer array,
  451.             // and redisplay the array on the top half of the screen
  452.             _tcscpy( m_szCmdBuffer[m_dwCmdBufferNext], strLine );
  453.  
  454. #ifdef _DEBUG
  455.             if( enumLineType != LINE_PROMPT )
  456.             {
  457.                 OutputDebugString( m_szCmdBuffer[m_dwCmdBufferNext] );
  458.                 OutputDebugString( TEXT("\n") );
  459.             }
  460. #endif
  461.  
  462.             if( enumLineType == LINE_PROMPT )
  463.             {
  464.                 m_dwLastPrompt = m_dwCmdBufferNext;
  465.                 m_dwCaretPos = _tcslen( m_szCmdBuffer[m_dwCmdBufferNext] );
  466.             }
  467.  
  468.             m_dwCmdBufferNext++;
  469.             m_dwCmdBufferNext %= m_dwNumCmdLines;
  470.             dwCoordY = m_dwSeperatorLine;
  471.  
  472.             for( i=m_dwCmdBufferNext; i<m_dwNumCmdLines; i++ )
  473.             {
  474.                 dwCoordY++;
  475.                 WriteLine( dwCoordY, m_szCmdBuffer[i] );
  476.             }
  477.  
  478.             for( i=0; i<m_dwCmdBufferNext; i++ )
  479.             {
  480.                 dwCoordY++;
  481.                 WriteLine( dwCoordY, m_szCmdBuffer[i] );
  482.             }
  483.             break;
  484.         }
  485.  
  486.         case LINE_INPUT:
  487.         {
  488.             // Update the last prompt line in the szCmdBuffer array with this
  489.             // string of input, so what was typed in is displayed as it scrolls
  490.             _tcscpy( &m_szCmdBuffer[m_dwLastPrompt][m_dwCaretPos], strLine );
  491.             break;
  492.         }
  493.     }
  494.  
  495.     if( enumLineType == LINE_PROMPT )
  496.     {                 
  497.         // Reset the cursor position if this is a cmd prompt line
  498.         COORD coord = { (WORD)m_dwCaretPos, (WORD)m_dwWindowSizeY-2 };
  499.         SetConsoleCursorPosition( m_hStdOut, coord );
  500.     }
  501. }
  502.  
  503.  
  504.  
  505.  
  506. //-----------------------------------------------------------------------------
  507. // Name: 
  508. // Desc: 
  509. //-----------------------------------------------------------------------------
  510. VOID CConsoleGraphics::SetupConsole( DWORD dwWindowSizeY )
  511. {
  512.     static TCHAR strEmpty[255] = TEXT("                                                                                                                                                                                                                                                              ");
  513.     DWORD dwWritten;
  514.     COORD coord = { 0, 0 };
  515.     SMALL_RECT rcWindow = { 0, 0, 79, (WORD)dwWindowSizeY-1 };
  516.  
  517.     SetConsoleWindowInfo( m_hStdOut, TRUE, &rcWindow );
  518.  
  519.     COORD crdBufferSize;
  520.     crdBufferSize.X = 80;
  521.     crdBufferSize.Y = (WORD)dwWindowSizeY;
  522.     SetConsoleScreenBufferSize( m_hStdOut, crdBufferSize );
  523.  
  524.     // Write a blank string first
  525.     for( int i=rcWindow.Top; i<rcWindow.Bottom; i++ )
  526.     {
  527.         coord.Y = (WORD)i;
  528.         SetConsoleCursorPosition( m_hStdOut, coord );
  529.         WriteConsole( m_hStdOut, strEmpty, rcWindow.Right + 1, &dwWritten, NULL );
  530.     }
  531. }
  532.  
  533.  
  534.  
  535.  
  536. //-----------------------------------------------------------------------------
  537. // Name: 
  538. // Desc: 
  539. //-----------------------------------------------------------------------------
  540. VOID CConsoleGraphics::RestoreOldConsoleSettings()
  541. {
  542.     static TCHAR strEmpty[255] = TEXT("                                                                                                                                                                                                                                                              ");
  543.     DWORD dwWritten;
  544.     COORD coord = { 0, 0 };
  545.  
  546.     SetConsoleScreenBufferSize( m_hStdOut, m_SavedConsoleInfo.dwSize );
  547.     SetConsoleWindowInfo( m_hStdOut, TRUE, &m_SavedConsoleInfo.srWindow );
  548.  
  549.     // Write a blank string first
  550.     for( int i=m_SavedConsoleInfo.srWindow.Top; 
  551.          i<m_SavedConsoleInfo.srWindow.Bottom;
  552.          i++ )
  553.     {
  554.         coord.Y = (WORD)i;
  555.         SetConsoleCursorPosition( m_hStdOut, coord );
  556.         WriteConsole( m_hStdOut, strEmpty, m_SavedConsoleInfo.srWindow.Right + 1, &dwWritten, NULL );
  557.     }
  558. }
  559.  
  560.  
  561.  
  562.  
  563. //-----------------------------------------------------------------------------
  564. // Name: 
  565. // Desc: 
  566. //-----------------------------------------------------------------------------
  567. VOID CConsoleGraphics::WriteLine( DWORD nCoordY, TCHAR* strBuffer )
  568. {
  569.     // Write blanks to make all strings 80 TCHARs long so that
  570.     // the old text is erased as this one is displayed
  571.     for( DWORD dwIndex = _tcslen(strBuffer); dwIndex<80; dwIndex++ )
  572.         strBuffer[dwIndex] = ' ';
  573.     strBuffer[dwIndex] = 0;
  574.  
  575.     // Write strBuffer at (0,nCoordY)
  576.     DWORD dwWritten;
  577.     COORD coord = { 0, (WORD) nCoordY };
  578.     WriteConsoleOutputCharacter( m_hStdOut, strBuffer, 80, coord, &dwWritten ); 
  579. }
  580.  
  581.  
  582.  
  583.  
  584. //-----------------------------------------------------------------------------
  585. // Name: 
  586. // Desc: 
  587. //-----------------------------------------------------------------------------
  588. void CConsoleGraphics::PrintHelp()
  589. {
  590.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Commands:") );
  591.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("    SETUP, EXIT, LOGLEVEL, CONNECTIONINFO") ); 
  592.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("    FILELOG, CONNECT, DISCONNECT") );
  593.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("    AUTOCONNECT, AUTODISCONNECT") );
  594.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("    SETSTATRATE, SETRETRYDELAY") );
  595.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("    SPTHREADS, SPBUFFER") );
  596. }
  597.  
  598.  
  599.  
  600.  
  601. //-----------------------------------------------------------------------------
  602. // Name: 
  603. // Desc: 
  604. //-----------------------------------------------------------------------------
  605. void CConsoleGraphics::ClearScreen()
  606. {
  607.     static TCHAR strEmpty[255] = TEXT("                                                                                                                                                                                                                                                              ");
  608.     DWORD dwWritten;
  609.     DWORD i;
  610.     COORD coord = { 0, 0 };
  611.     DWORD dwCoordY;
  612.  
  613.     // Write a blank string first
  614.     for( i=0; i<m_dwWindowSizeY; i++ )
  615.     {
  616.         coord.Y = (WORD)i;
  617.         SetConsoleCursorPosition( m_hStdOut, coord );
  618.         WriteConsole( m_hStdOut, strEmpty, m_SavedConsoleInfo.srWindow.Right + 1, &dwWritten, NULL );
  619.     }
  620.  
  621.     // Display a seperator between the two areas of the console window
  622.     TCHAR strBuffer[200];
  623.     _tcscpy( strBuffer, TEXT("-------------------------------------------------------------------------------") );
  624.     WriteLine( m_dwSeperatorLine, strBuffer );
  625.  
  626.     dwCoordY = 0; 
  627.     for( i=m_dwLogBufferNext; i<m_dwNumLogLines; i++ )
  628.     {
  629.         dwCoordY++;
  630.         WriteLine( dwCoordY, m_szLogBuffer[i] );
  631.     }
  632.  
  633.     for( i=0; i<m_dwLogBufferNext; i++ )
  634.     {
  635.         dwCoordY++;
  636.         WriteLine( dwCoordY, m_szLogBuffer[i] );
  637.     }
  638.  
  639.     dwCoordY = m_dwSeperatorLine;
  640.  
  641.     for( i=m_dwCmdBufferNext; i<m_dwNumCmdLines; i++ )
  642.     {
  643.         dwCoordY++;
  644.         WriteLine( dwCoordY, m_szCmdBuffer[i] );
  645.     }
  646.  
  647.     for( i=0; i<m_dwCmdBufferNext; i++ )
  648.     {
  649.         dwCoordY++;
  650.         WriteLine( dwCoordY, m_szCmdBuffer[i] );
  651.     }
  652.  
  653. }
  654.  
  655.  
  656.  
  657.  
  658. //-----------------------------------------------------------------------------
  659. // Name: 
  660. // Desc: 
  661. //-----------------------------------------------------------------------------
  662. void CConsoleGraphics::DoPrompt( TCHAR* strPromptString, TCHAR* strBuffer )
  663. {
  664.     m_pMazeApp->ConsolePrintf( LINE_PROMPT, strPromptString );
  665.     DWORD dwRead;
  666.     BOOL bSuccess;
  667.     bSuccess = ReadConsole( GetStdHandle(STD_INPUT_HANDLE), strBuffer, 128, &dwRead, NULL );
  668.  
  669.     if( !bSuccess || dwRead < 2 )
  670.     {
  671.         _tcscpy( strBuffer, TEXT("") );
  672.         return;
  673.     }
  674.         
  675.     strBuffer[dwRead-2]=0;
  676.     m_pMazeApp->ConsolePrintf( LINE_INPUT, strBuffer );
  677. }
  678.  
  679.  
  680.  
  681.  
  682. //-----------------------------------------------------------------------------
  683. // Name: 
  684. // Desc: 
  685. //-----------------------------------------------------------------------------
  686. void CConsoleGraphics::RunSetupWizard()
  687. {
  688.     BOOL bWrongToken;
  689.     TCHAR buffer[512];
  690.  
  691.     m_pConfig->bConnectToMicrosoftSite = FALSE;
  692.     m_pConfig->bConnectToLocalServer   = FALSE;
  693.     m_pConfig->bConnectToRemoteServer  = FALSE;
  694.  
  695.     bWrongToken = TRUE;
  696.     while( bWrongToken ) 
  697.     {
  698.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  699.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Do you want to connect to DirectPlayMaze.rte.microsoft.com? (YES/NO)") );
  700.         DoPrompt( TEXT("(Default:YES) > "), buffer );
  701.  
  702.         TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  703.         if( token != NULL )
  704.         {
  705.             _tcsupr( token );
  706.             if( !_tcscmp( token, TEXT("Y") ) || !_tcscmp( token, TEXT("YES") ) )
  707.             {
  708.                 m_pConfig->bConnectToMicrosoftSite = TRUE;
  709.                 bWrongToken = FALSE;
  710.             }
  711.             else if( !_tcscmp( token, TEXT("N") ) || !_tcscmp( token, TEXT("NO") ) )
  712.             {
  713.                 bWrongToken = FALSE;
  714.             }
  715.         }
  716.         else
  717.         {
  718.             m_pConfig->bConnectToMicrosoftSite = TRUE;
  719.             bWrongToken = FALSE;
  720.         }
  721.     }
  722.  
  723.     if( m_pConfig->bConnectToMicrosoftSite == FALSE )
  724.     {
  725.         bWrongToken = TRUE;
  726.         while( bWrongToken ) 
  727.         {
  728.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  729.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Do you want to connect to a local server (searches local subnet)? (YES/NO)") );
  730.             DoPrompt( TEXT("(Default:YES) > "), buffer );
  731.  
  732.             TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  733.             if( token != NULL )
  734.             {
  735.                 _tcsupr( token );
  736.                 if( !_tcscmp( token, TEXT("Y") ) || !_tcscmp( token, TEXT("YES") ) )
  737.                 {
  738.                     m_pConfig->bConnectToLocalServer   = TRUE;
  739.                     bWrongToken = FALSE;
  740.                 }
  741.                 else if( !_tcscmp( token, TEXT("N") ) || !_tcscmp( token, TEXT("NO") ) )
  742.                 {
  743.                     bWrongToken = FALSE;
  744.                 }
  745.             }
  746.             else
  747.             {
  748.                 m_pConfig->bConnectToLocalServer   = TRUE;
  749.                 bWrongToken = FALSE;
  750.             }
  751.         }
  752.  
  753.         if( m_pConfig->bConnectToLocalServer == FALSE )
  754.         {
  755.             bWrongToken = TRUE;
  756.             while( bWrongToken ) 
  757.             {
  758.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  759.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("What IP address do you want to connect to? ") );
  760.                 DoPrompt( TEXT("> "), buffer );
  761.  
  762.                 TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  763.                 if( token != NULL )
  764.                 {
  765.                     _tcscpy( m_pConfig->szIPAddress, token );
  766.                     m_pConfig->bConnectToRemoteServer = TRUE;
  767.                     bWrongToken = FALSE;
  768.                 }
  769.             }
  770.         }
  771.     }
  772.  
  773.     bWrongToken = TRUE;
  774.     while( bWrongToken ) 
  775.     {
  776.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  777.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Turn file logging on? (YES/NO)") );
  778.         DoPrompt( TEXT("(Default:YES) > "), buffer );
  779.  
  780.         TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  781.         if( token != NULL )
  782.         {
  783.             _tcsupr( token );
  784.             if( !_tcscmp( token, TEXT("Y") ) || !_tcscmp( token, TEXT("YES") ) )
  785.             {
  786.                 m_pConfig->bFileLogging = TRUE;
  787.                 bWrongToken = FALSE;
  788.             }
  789.             else if( !_tcscmp( token, TEXT("N") ) || !_tcscmp( token, TEXT("NO") ) )
  790.             {
  791.                 m_pConfig->bFileLogging = FALSE;
  792.                 bWrongToken = FALSE;
  793.             }
  794.         }
  795.         else
  796.         {
  797.             m_pConfig->bFileLogging = TRUE;
  798.             bWrongToken = FALSE;
  799.         }
  800.     }
  801.  
  802.     bWrongToken = TRUE;
  803.     while( bWrongToken ) 
  804.     {
  805.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  806.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Use these settings when disconnected and when the app starts? (YES/NO)") );
  807.         DoPrompt( TEXT("(Default:YES) > "), buffer );
  808.  
  809.         TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  810.         if( token != NULL )
  811.         {
  812.             _tcsupr( token );
  813.             if( !_tcscmp( token, TEXT("Y") ) || !_tcscmp( token, TEXT("YES") ) )
  814.             {
  815.                 m_pConfig->bAutoConnnect = TRUE;
  816.                 bWrongToken = FALSE;
  817.             }
  818.             else if( !_tcscmp( token, TEXT("N") ) || !_tcscmp( token, TEXT("NO") ) )
  819.             {
  820.                 m_pConfig->bAutoConnnect = FALSE;
  821.                 bWrongToken = FALSE;
  822.             }
  823.         }
  824.         else
  825.         {
  826.             m_pConfig->bAutoConnnect = TRUE;
  827.             bWrongToken = FALSE;
  828.         }
  829.     }
  830.  
  831.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  832.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Type 'SETUP' anytime to change these connections settings.") );
  833.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Type 'HELP' for a list of commands.") );
  834.     m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("") );
  835.  
  836.     m_pMazeApp->SetSaveSettings( TRUE );
  837.     m_pMazeApp->WriteConfig();
  838. }
  839.  
  840.  
  841.  
  842.  
  843. //-----------------------------------------------------------------------------
  844. // Name: 
  845. // Desc: 
  846. //-----------------------------------------------------------------------------
  847. void CConsoleGraphics::ParseInput( TCHAR* buffer )
  848. {
  849.     // Strip first token from the buffer and pull to upper case
  850.     TCHAR* token = _tcstok( buffer, TEXT(" \t") );
  851.     if( token == NULL )
  852.         return;
  853.  
  854.     _tcsupr( token );
  855.  
  856.     // See what it is and act accordingly
  857.     if( !_tcscmp( token, TEXT("STOP") ) || 
  858.         !_tcscmp( token, TEXT("QUIT") ) || 
  859.         !_tcscmp( token, TEXT("EXIT") ) )
  860.     {
  861.         m_bQuitThread = TRUE;
  862.     } 
  863.     else if( !_tcscmp( token, TEXT("CONNECT") ) )
  864.     {
  865.         m_pMazeApp->SetConnectNow( TRUE );
  866.     } 
  867.     else if( !_tcscmp( token, TEXT("DISCONNECT") ) )
  868.     {
  869.         m_pMazeApp->SetDisconnectNow( TRUE );
  870.     } 
  871.     else if( !_tcscmp( token, TEXT("AUTOCONNECT") ) )
  872.     {
  873.         token = _tcstok( NULL, TEXT(" \t") );
  874.         if( token )
  875.         {
  876.             _tcsupr( token );
  877.             if( !_tcscmp( token, TEXT("ON") ) )
  878.                 m_pConfig->bAutoConnnect = TRUE;
  879.             else if( !_tcscmp( token, TEXT("OFF") ) )
  880.                 m_pConfig->bAutoConnnect = FALSE;
  881.             m_pMazeApp->WriteConfig();
  882.         }
  883.  
  884.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Auto-Connect set to %s"), (m_pConfig->bAutoConnnect) ? TEXT("ON") : TEXT("OFF") );
  885.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("  If ON, MazeConsoleClient connects automatically reconnects") );
  886.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("         when disconnected, and connects when loading app.") );
  887.     } 
  888.     else if( !_tcscmp( token, TEXT("SETRETRYDELAY") ) )
  889.     {
  890.         token = _tcstok( NULL, TEXT(" \t") );
  891.         if( token )
  892.         {
  893.             DWORD dwDelay = _ttol( token );
  894.             if( m_pConfig->dwNetworkRetryDelay < 1 || m_pConfig->dwNetworkRetryDelay > 300 )
  895.             {
  896.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Must enter a value between 1 and 300") );
  897.             }
  898.             else
  899.             {           
  900.                 m_pConfig->dwNetworkRetryDelay = dwDelay;
  901.             }
  902.         }
  903.  
  904.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Retry Delay set to %d"), m_pConfig->dwNetworkRetryDelay );
  905.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("  Sets how long the app waits between attempts to connect to the server.") );
  906.     }     
  907.     else if( !_tcscmp( token, TEXT("LOGLEVEL") ) )
  908.     {
  909.         token = _tcstok( NULL, TEXT(" \t") );
  910.         if( token )
  911.         {
  912.             DWORD dwLevel = _ttol( token );
  913.             if( dwLevel > 3 )
  914.             {
  915.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Must enter a value between 0 and 3") );
  916.             }
  917.             else
  918.             {
  919.                 m_pConfig->dwLogLevel = dwLevel;
  920.             }
  921.         }
  922.  
  923.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Log level set to %d"), m_pConfig->dwLogLevel );
  924.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("     Level 1: No client position ") );
  925.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("     Level 2: Client position every 10 seconds") );
  926.     }
  927.     else if( !_tcscmp( token, TEXT("SETSTATRATE") ) )
  928.     {
  929.         token = _tcstok( NULL, TEXT(" \t") );
  930.         if( token )
  931.         {
  932.             DWORD dwLevel = _ttol( token );
  933.             m_pConfig->dwAutoPrintStats = dwLevel;
  934.         }
  935.  
  936.         if( m_pConfig->dwAutoPrintStats != 0 )
  937.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Auto-displaying stats every %d mins"), m_pConfig->dwAutoPrintStats );
  938.         else
  939.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Not auto-displaying stats") );
  940.  
  941.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("     Controls how often the connection stats are auto-displayed") );
  942.     }
  943.     else if( !_tcscmp( token, TEXT("SETUP") ) )
  944.     {
  945.         m_pMazeApp->SetAllowConnect( FALSE );
  946.         m_pMazeApp->SetDisconnectNow( TRUE );
  947.         RunSetupWizard();
  948.  
  949.         if( m_pConfig->bFileLogging )
  950.             m_pMazeApp->CreateTempLogFile();
  951.         else
  952.             m_pMazeApp->CloseTempLogFile();
  953.  
  954.         m_pMazeApp->SetConnectNow( TRUE );
  955.         m_pMazeApp->SetAllowConnect( TRUE );
  956.     }
  957.     else if( !_tcscmp( token, TEXT("FILELOG") ) )
  958.     {
  959.         m_pMazeApp->ConsolePrintf( LINE_LOG, TEXT("Log Directory: '%s'"), m_pMazeApp->GetLogDir() );
  960.         m_pMazeApp->ConsolePrintf( LINE_LOG, TEXT("Logging to temp file: '%s'"), m_pMazeApp->GetLogFile() );
  961.     }
  962.     else if( !_tcscmp( token, TEXT("AUTODISCONNECT") ) )
  963.     {
  964.         token = _tcstok( NULL, TEXT(" \t") );
  965.         if( token )
  966.         {
  967.             _tcsupr( token );
  968.             if( !_tcscmp( token, TEXT("ON") ) )
  969.                 m_pConfig->bAutoDisconnnect = TRUE;
  970.             else if( !_tcscmp( token, TEXT("OFF") ) )
  971.                 m_pConfig->bAutoDisconnnect = FALSE;
  972.             m_pMazeApp->WriteConfig();
  973.         }
  974.  
  975.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Auto-Disconnect set to %s"), (m_pConfig->bAutoDisconnnect) ? TEXT("ON") : TEXT("OFF") );
  976.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("  If ON, app disconnects randomly") );
  977.     } 
  978.     else if( !_tcscmp( token, TEXT("CONNECTIONINFO") ) || !_tcscmp( token, TEXT("CI") ) )
  979.     {
  980.         TCHAR strInfo[5000];
  981.         TCHAR* strEndOfLine;
  982.         TCHAR* strStartOfLine;
  983.  
  984.         // Query the IOutboudNet for info about the connection to this user
  985.         m_pDP8Client->GetConnectionInfo( strInfo );
  986.  
  987.         m_pMazeApp->ConsolePrintf( LINE_LOG, TEXT("Displaying connection info for 0x%0.8x"), m_pMazeClient->GetLocalClientID() );
  988.         m_pMazeApp->ConsolePrintf( LINE_LOG, TEXT("(Key: G=Guaranteed NG=Non-Guaranteed B=Bytes P=Packets)") );
  989.  
  990.         // Display each line seperately
  991.         strStartOfLine = strInfo;
  992.         while( TRUE )
  993.         {
  994.             strEndOfLine = _tcschr( strStartOfLine, '\n' );
  995.             if( strEndOfLine == NULL )
  996.                 break;
  997.  
  998.             *strEndOfLine = 0;
  999.             m_pMazeApp->ConsolePrintf( LINE_LOG, strStartOfLine );
  1000.             strStartOfLine = strEndOfLine + 1;
  1001.         }
  1002.     }
  1003.     else if( !_tcscmp( token, TEXT("SPTHREADS") ) || !_tcscmp( token, TEXT("SPT") ) )
  1004.     {
  1005.         DWORD currentthreads = m_pDP8Client->GetNumSPThreads();
  1006.  
  1007.         token = _tcstok( NULL, TEXT(" \t") );
  1008.         if( token )
  1009.         {
  1010.             DWORD threads = _ttol( token );
  1011.             if( (threads > MAX_SP_THREADS) || (threads <= currentthreads) )
  1012.             {
  1013.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Must enter a value between %d and %d"), 
  1014.                                                             currentthreads, MAX_SP_THREADS );
  1015.             }
  1016.             else
  1017.             {
  1018.                 m_pDP8Client->SetNumSPThreads( threads );
  1019.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("SP Threads Set to %d"), threads );
  1020.             }
  1021.         }
  1022.         else
  1023.         {
  1024.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("SP Threads set to %d"), 
  1025.                                                        m_pDP8Client->GetNumSPThreads() );
  1026.         }
  1027.     }
  1028.     else if( !_tcscmp( token, TEXT("SPBUFFER") ) || !_tcscmp( token, TEXT("SPB") ) )
  1029.     {
  1030.         token = _tcstok( NULL, TEXT(" \t") );
  1031.         if( token )
  1032.         {
  1033.             DWORD buffer = _ttol( token );
  1034.             if( (buffer > MAX_SP_BUFFER) )
  1035.             {
  1036.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Must enter a value between 0 and %d"), 
  1037.                                                                                     MAX_SP_BUFFER );
  1038.             }
  1039.             else
  1040.             {
  1041.                 m_pDP8Client->SetSPBuffer( buffer );
  1042.                 m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("SP Buffer Size Set to %d"),
  1043.                                                                     m_pDP8Client->GetSPBuffer() );
  1044.             }
  1045.         }
  1046.         else
  1047.         {
  1048.             m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("SP Buffer Size set to %d"), 
  1049.                                                                     m_pDP8Client->GetSPBuffer() );
  1050.         }
  1051.     }
  1052.     else if( !_tcscmp( token, TEXT("HELP") ) || !_tcscmp( token, TEXT("?") ) )
  1053.     {
  1054.         PrintHelp();
  1055.     }
  1056.     else if( !_tcscmp( token, TEXT("CLS") ) )
  1057.     {
  1058.         ClearScreen();
  1059.     }
  1060.     else
  1061.     {
  1062.         m_pMazeApp->ConsolePrintf( LINE_CMD, TEXT("Unknown command. Type HELP for list of commands") );
  1063.     }
  1064. }
  1065.  
  1066.  
  1067.  
  1068.  
  1069. //-----------------------------------------------------------------------------
  1070. // Name: 
  1071. // Desc: 
  1072. //-----------------------------------------------------------------------------
  1073. UINT WINAPI CConsoleGraphics::StaticPromptThread( LPVOID pParam )
  1074. {
  1075.     return s_pGraphics->PromptThread( pParam );
  1076. }
  1077.  
  1078.  
  1079.  
  1080.  
  1081. //-----------------------------------------------------------------------------
  1082. // Name: 
  1083. // Desc: 
  1084. //-----------------------------------------------------------------------------
  1085. UINT WINAPI CConsoleGraphics::PromptThread( LPVOID pParam )
  1086. {
  1087.     BOOL bHaveConnectSettings = m_pConfig->bAutoConnnect;
  1088.  
  1089.     // Loop around getting and dealing with keyboard input
  1090.     TCHAR buffer[512];
  1091.     while( !m_bQuitThread )
  1092.     {
  1093.         if( !bHaveConnectSettings )
  1094.         {
  1095.             // If we don't have the connection settings yet, 
  1096.             // then prompt for where to connect to
  1097.             RunSetupWizard();
  1098.  
  1099.             if( m_pConfig->bFileLogging )
  1100.                 m_pMazeApp->CreateTempLogFile();
  1101.             else
  1102.                 m_pMazeApp->CloseTempLogFile();
  1103.  
  1104.             m_pMazeApp->SetAllowConnect( TRUE );
  1105.             bHaveConnectSettings = TRUE;
  1106.         }
  1107.         else
  1108.         {
  1109.             DoPrompt( TEXT("Command> "), buffer );
  1110.             ParseInput( buffer );
  1111.         }
  1112.     };
  1113.  
  1114.     _tprintf( TEXT("Stopping...") );
  1115.  
  1116.     return 0;
  1117. }
  1118.