home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / common / src / netconnect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  60.3 KB  |  1,610 lines

  1. //-----------------------------------------------------------------------------
  2. // File: NetConnect.cpp
  3. //
  4. // Desc: This is a class that given a IDirectPlay8Peer, then DoConnectWizard()
  5. //       will enumerate service providers, enumerate hosts, and allow the
  6. //       user to either join or host a session.  The class uses
  7. //       dialog boxes and GDI for the interactive UI.  Most games will
  8. //       want to change the graphics to use Direct3D or another graphics
  9. //       layer, but this simplistic sample uses dialog boxes.  Feel 
  10. //       free to use this class as a starting point for adding extra 
  11. //       functionality.
  12. //
  13. //
  14. // Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. #define STRICT
  17. #include <windows.h>
  18. #include <basetsd.h>
  19. #include <stdio.h>
  20. #include <mmsystem.h>
  21. #include <dxerr8.h>
  22. #include <dplay8.h>
  23. #include <dpaddr.h>
  24. #include <dplobby8.h>
  25. #include "NetConnect.h"
  26. #include "NetConnectRes.h"
  27. #include "DXUtil.h"
  28.  
  29.  
  30.  
  31.  
  32. //-----------------------------------------------------------------------------
  33. // Global variables
  34. //-----------------------------------------------------------------------------
  35. CNetConnectWizard* g_pNCW = NULL;           // Pointer to the net connect wizard
  36.  
  37.  
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Name: CNetConnectWizard
  42. // Desc: Init the class
  43. //-----------------------------------------------------------------------------
  44. CNetConnectWizard::CNetConnectWizard( HINSTANCE hInst, TCHAR* strAppName,
  45.                                       GUID* pGuidApp )
  46. {
  47.     g_pNCW              = this;
  48.     m_hInst             = hInst;
  49.     m_pDP               = NULL;
  50.     m_pLobbiedApp       = NULL;
  51.     m_bHaveConnectionSettingsFromLobby = FALSE;
  52.     m_hLobbyClient      = NULL;
  53.     m_guidApp           = *pGuidApp;
  54.     m_hDlg              = NULL;
  55.     m_bConnecting       = FALSE;
  56.     m_hConnectAsyncOp   = NULL;
  57.     m_pDeviceAddress    = NULL;
  58.     m_pHostAddress      = NULL;
  59.     m_hEnumAsyncOp      = NULL;
  60.     m_dwEnumHostExpireInterval = 0;
  61.  
  62.     // Set the max players unlimited by default.  This can be changed by the app
  63.     // by calling SetMaxPlayers()
  64.     m_dwMaxPlayers   = 0;
  65.  
  66.     _tcscpy( m_strAppName, strAppName );
  67.     _tcscpy( m_strPreferredProvider, TEXT("DirectPlay8 TCP/IP Service Provider") );
  68.  
  69.     InitializeCriticalSection( &m_csHostEnum );
  70.     m_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  71.     m_hLobbyConnectionEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  72.  
  73.     // Setup the m_DPHostEnumHead circular linked list
  74.     ZeroMemory( &m_DPHostEnumHead, sizeof( DPHostEnumInfo ) );
  75.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  76. }
  77.  
  78.  
  79.  
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Name: ~CNetConnectWizard
  83. // Desc: Cleanup the class
  84. //-----------------------------------------------------------------------------
  85. CNetConnectWizard::~CNetConnectWizard()
  86. {
  87.     DeleteCriticalSection( &m_csHostEnum );
  88.     CloseHandle( m_hConnectCompleteEvent );
  89.     CloseHandle( m_hLobbyConnectionEvent );
  90. }
  91.  
  92.  
  93.  
  94. //-----------------------------------------------------------------------------
  95. // Name: Init
  96. // Desc:
  97. //-----------------------------------------------------------------------------
  98. VOID CNetConnectWizard::Init( IDirectPlay8Peer* pDP,
  99.                               IDirectPlay8LobbiedApplication* pLobbiedApp )
  100. {
  101.     m_pDP               = pDP;
  102.     m_pLobbiedApp       = pLobbiedApp;
  103.     m_bHaveConnectionSettingsFromLobby = FALSE;
  104.     m_hLobbyClient      = NULL;
  105. }
  106.  
  107.  
  108.  
  109. //-----------------------------------------------------------------------------
  110. // Name: Shutdown
  111. // Desc: Releases the DirectPlay interfaces
  112. //-----------------------------------------------------------------------------
  113. VOID CNetConnectWizard::Shutdown()
  114. {
  115.     SAFE_RELEASE( m_pDeviceAddress );
  116.     SAFE_RELEASE( m_pHostAddress );
  117. }
  118.  
  119.  
  120.  
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Name: DoConnectWizard
  124. // Desc: This is the main external function.  This will launch a series of
  125. //       dialog boxes that enumerate service providers, enumerate hosts,
  126. //       and allow the user to either join or host a session
  127. //-----------------------------------------------------------------------------
  128. HRESULT CNetConnectWizard::DoConnectWizard( BOOL bBackTrack )
  129. {
  130.     if( m_pDP == NULL )
  131.         return E_INVALIDARG;
  132.  
  133.     int nStep;
  134.  
  135.     // If the back track flag is true, then the user has already been through
  136.     // the connect process once, and has back tracked out of the main game
  137.     // so start at the last dialog box
  138.     if( bBackTrack )
  139.         nStep = 1;
  140.     else
  141.         nStep = 0;
  142.  
  143.     // Show the dialog boxes to connect
  144.     while( TRUE )
  145.     {
  146.         m_hrDialog = S_OK;
  147.  
  148.         switch( nStep )
  149.         {
  150.             case 0:
  151.                 // Display the multiplayer connect dialog box.
  152.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CONNECT),
  153.                            NULL, (DLGPROC) StaticConnectionsDlgProc );
  154.                 break;
  155.  
  156.             case 1:
  157.                 // Display the multiplayer games dialog box.
  158.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_GAMES),
  159.                            NULL, (DLGPROC) StaticSessionsDlgProc );
  160.                 break;
  161.         }
  162.  
  163.         if( FAILED( m_hrDialog ) ||
  164.             m_hrDialog == NCW_S_QUIT ||
  165.             m_hrDialog == NCW_S_LOBBYCONNECT )
  166.             break;
  167.  
  168.         if( m_hrDialog == NCW_S_BACKUP )
  169.             nStep--;
  170.         else
  171.             nStep++;
  172.  
  173.         // If we go beyond the last step in the wizard, then stop
  174.         // and return.
  175.         if( nStep == 2 )
  176.             break;
  177.     }
  178.  
  179.     // Depending upon a successful m_hrDialog the user has
  180.     // either successfully join or created a game, depending on m_bHostPlayer
  181.     m_pDP = NULL;
  182.     return m_hrDialog;
  183. }
  184.  
  185.  
  186.  
  187.  
  188. //-----------------------------------------------------------------------------
  189. // Name: StaticConnectionsDlgProc()
  190. // Desc: Static msg handler which passes messages
  191. //-----------------------------------------------------------------------------
  192. INT_PTR CALLBACK CNetConnectWizard::StaticConnectionsDlgProc( HWND hDlg, UINT uMsg,
  193.                                                               WPARAM wParam, LPARAM lParam )
  194. {
  195.     if( g_pNCW )
  196.         return g_pNCW->ConnectionsDlgProc( hDlg, uMsg, wParam, lParam );
  197.  
  198.     return FALSE; // Message not handled
  199. }
  200.  
  201.  
  202.  
  203.  
  204. //-----------------------------------------------------------------------------
  205. // Name: ConnectionsDlgProc()
  206. // Desc: Handles messages for the multiplayer connect dialog
  207. //-----------------------------------------------------------------------------
  208. INT_PTR CALLBACK CNetConnectWizard::ConnectionsDlgProc( HWND hDlg, UINT msg,
  209.                                                         WPARAM wParam, LPARAM lParam )
  210. {
  211.     switch( msg )
  212.     {
  213.         case WM_INITDIALOG:
  214.             {
  215.                 SetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName );
  216.  
  217.                 // Load and set the icon
  218.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  219.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  220.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  221.  
  222.                 // Set the window title
  223.                 TCHAR strWindowTitle[256];
  224.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Connect"), m_strAppName );
  225.                 SetWindowText( hDlg, strWindowTitle );
  226.  
  227.                 // Fill the list box with the service providers
  228.                 if( FAILED( m_hrDialog = ConnectionsDlgFillListBox( hDlg ) ) )
  229.                 {
  230.                     DXTRACE_ERR( TEXT("ConnectionsDlgFillListBox"), m_hrDialog );
  231.                     EndDialog( hDlg, 0 );
  232.                 }
  233.             }
  234.             break;
  235.  
  236.         case WM_COMMAND:
  237.             switch( LOWORD(wParam) )
  238.             {
  239.                 case IDC_CONNECTION_LIST:
  240.                     if( HIWORD(wParam) != LBN_DBLCLK )
  241.                         break;
  242.                     // Fall through
  243.  
  244.                 case IDOK:
  245.                     if( FAILED( m_hrDialog = ConnectionsDlgOnOK( hDlg ) ) )
  246.                     {
  247.                         DXTRACE_ERR( TEXT("ConnectionsDlgOnOK"), m_hrDialog );
  248.                         EndDialog( hDlg, 0 );
  249.                     }
  250.  
  251.                     if( m_hrDialog == NCW_S_LOBBYCONNECT )
  252.                     {
  253.                         EndDialog( hDlg, 0 );
  254.                     }
  255.                     break;
  256.  
  257.                 case IDCANCEL:
  258.                     m_hrDialog = NCW_S_QUIT;
  259.                     EndDialog( hDlg, 0 );
  260.                     break;
  261.  
  262.                 default:
  263.                     return FALSE; // Message not handled
  264.             }
  265.             break;
  266.  
  267.         case WM_DESTROY:
  268.             ConnectionsDlgCleanup( hDlg );
  269.             break;
  270.  
  271.         default:
  272.             return FALSE; // Message not handled
  273.     }
  274.  
  275.     // Message was handled
  276.     return TRUE;
  277. }
  278.  
  279.  
  280.  
  281.  
  282. //-----------------------------------------------------------------------------
  283. // Name: ConnectionsDlgFillListBox()
  284. // Desc: Fills the DirectPlay connection listbox with service providers,
  285. //       and also adds a "Wait for Lobby" connection option.
  286. //-----------------------------------------------------------------------------
  287. HRESULT CNetConnectWizard::ConnectionsDlgFillListBox( HWND hDlg )
  288. {
  289.     HRESULT                     hr;
  290.     int                         iLBIndex;
  291.     DWORD                       dwItems     = 0;
  292.     DPN_SERVICE_PROVIDER_INFO*  pdnSPInfo   = NULL;
  293.     DWORD                       dwSize      = 0;
  294.     HWND                        hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  295.     TCHAR                       strName[MAX_PATH];
  296.  
  297.     // Enumerate all DirectPlay service providers, and store them in the listbox
  298.     hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
  299.                                       &dwItems, 0 );
  300.     if( hr != DPNERR_BUFFERTOOSMALL )
  301.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  302.  
  303.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  304.     if( FAILED( hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
  305.                                                   &dwSize, &dwItems, 0 ) ) )
  306.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  307.  
  308.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  309.     for ( DWORD i = 0; i < dwItems; i++ )
  310.     {
  311.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  312.  
  313.         // Found a service provider, so put it in the listbox
  314.         iLBIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  315.                                      (LPARAM)strName );
  316.         if( iLBIndex == CB_ERR )
  317.             return E_FAIL; // Error, stop enumerating
  318.  
  319.         // Store pointer to GUID in listbox
  320.         GUID* pGuid = new GUID;
  321.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  322.         SendMessage( hWndListBox, LB_SETITEMDATA, iLBIndex,
  323.                      (LPARAM)pGuid );
  324.  
  325.         pdnSPInfoEnum++;
  326.     }
  327.  
  328.     SAFE_DELETE( pdnSPInfo );
  329.  
  330.     // Add "Wait for Lobby Connection" selection in list box
  331.     SendMessage( hWndListBox, LB_ADDSTRING, 0,
  332.                  (LPARAM) TEXT("Wait for Lobby Connection") );
  333.  
  334.     SetFocus( hWndListBox );
  335.  
  336.     // Try to select the default preferred provider
  337.     iLBIndex = (int)SendMessage( hWndListBox, LB_FINDSTRINGEXACT, (WPARAM)-1,
  338.                                 (LPARAM)m_strPreferredProvider );
  339.     if( iLBIndex != LB_ERR )
  340.         SendMessage( hWndListBox, LB_SETCURSEL, iLBIndex, 0 );
  341.     else
  342.         SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  343.  
  344.  
  345.     return S_OK;
  346. }
  347.  
  348.  
  349.  
  350.  
  351. //-----------------------------------------------------------------------------
  352. // Name: ConnectionsDlgOnOK()
  353. // Desc: Stores the player name m_strPlayerName, and in creates a IDirectPlay
  354. //       object based on the connection type the user selected.
  355. //-----------------------------------------------------------------------------
  356. HRESULT CNetConnectWizard::ConnectionsDlgOnOK( HWND hDlg )
  357. {
  358.     LRESULT iIndex;
  359.     HRESULT hr;
  360.  
  361.     GetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName, MAX_PATH );
  362.  
  363.     if( _tcslen( m_strLocalPlayerName ) == 0 )
  364.     {
  365.         MessageBox( hDlg, TEXT("You must enter a valid player name."),
  366.                     TEXT("DirectPlay Sample"), MB_OK );
  367.         return S_OK;
  368.     }
  369.  
  370.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  371.  
  372.     iIndex = SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  373.     SendMessage( hWndListBox, LB_GETTEXT, iIndex, (LPARAM)m_strPreferredProvider );
  374.  
  375.     GUID* pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA, iIndex, 0 );
  376.     if( NULL == pGuid )
  377.     {
  378.         // 'Wait for lobby launch' SP has been selected, so wait for a connection
  379.         if( FAILED( hr = m_pLobbiedApp->SetAppAvailable( TRUE, 0 ) ) )
  380.             return DXTRACE_ERR( TEXT("SetAppAvailable"), hr );
  381.  
  382.         // Display the multiplayer connect dialog box.
  383.         DialogBox( m_hInst, MAKEINTRESOURCE(IDD_LOBBY_WAIT_STATUS),
  384.                    hDlg, (DLGPROC) StaticLobbyWaitDlgProc );
  385.  
  386.         if( m_bHaveConnectionSettingsFromLobby )
  387.         {
  388.             if( FAILED( hr = ConnectUsingLobbySettings() ) )
  389.                 return DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  390.  
  391.             return NCW_S_LOBBYCONNECT;
  392.         }
  393.  
  394.         return S_OK;
  395.     }
  396.  
  397.     // Query for the enum host timeout for this SP
  398.     DPN_SP_CAPS dpspCaps;
  399.     ZeroMemory( &dpspCaps, sizeof(DPN_SP_CAPS) );
  400.     dpspCaps.dwSize = sizeof(DPN_SP_CAPS);
  401.     if( FAILED( hr = m_pDP->GetSPCaps( pGuid, &dpspCaps, 0 ) ) )
  402.         return DXTRACE_ERR( TEXT("GetSPCaps"), hr );
  403.  
  404.     // Set the host expire time to around 3 times
  405.     // length of the dwDefaultEnumRetryInterval
  406.     m_dwEnumHostExpireInterval = dpspCaps.dwDefaultEnumRetryInterval * 3;
  407.  
  408.     // Create a device address
  409.     SAFE_RELEASE( m_pDeviceAddress );
  410.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER,
  411.                            IID_IDirectPlay8Address, (LPVOID*) &m_pDeviceAddress );
  412.     if( FAILED(hr) )
  413.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  414.  
  415.     if( FAILED( hr = m_pDeviceAddress->SetSP( pGuid ) ) )
  416.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  417.  
  418.     // Create a host address
  419.     SAFE_RELEASE( m_pHostAddress );
  420.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER,
  421.                            IID_IDirectPlay8Address, (LPVOID*) &m_pHostAddress );
  422.     if( FAILED(hr) )
  423.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  424.  
  425.     if( FAILED( hr = m_pHostAddress->SetSP( pGuid ) ) )
  426.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  427.  
  428.     // The SP has been chosen, so move forward in the wizard
  429.     m_hrDialog = NCW_S_FORWARD;
  430.     EndDialog( hDlg, 0 );
  431.  
  432.     return S_OK;
  433. }
  434.  
  435.  
  436.  
  437.  
  438. //-----------------------------------------------------------------------------
  439. // Name: ConnectionsDlgCleanup()
  440. // Desc: Deletes the connection buffers from the listbox
  441. //-----------------------------------------------------------------------------
  442. VOID CNetConnectWizard::ConnectionsDlgCleanup( HWND hDlg )
  443. {
  444.     GUID*   pGuid = NULL;
  445.     DWORD   iIndex;
  446.     DWORD   dwCount;
  447.  
  448.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  449.  
  450.     dwCount = (DWORD)SendMessage( hWndListBox, LB_GETCOUNT, 0, 0 );
  451.     for( iIndex = 0; iIndex < dwCount; iIndex++ )
  452.     {
  453.         pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA,
  454.                                      iIndex, 0 );
  455.         SAFE_DELETE( pGuid );
  456.     }
  457. }
  458.  
  459.  
  460.  
  461.  
  462. //-----------------------------------------------------------------------------
  463. // Name: StaticSessionsDlgProc()
  464. // Desc: Static msg handler which passes messages
  465. //-----------------------------------------------------------------------------
  466. INT_PTR CALLBACK CNetConnectWizard::StaticSessionsDlgProc( HWND hDlg, UINT uMsg,
  467.                                                            WPARAM wParam, LPARAM lParam )
  468. {
  469.     if( g_pNCW )
  470.         return g_pNCW->SessionsDlgProc( hDlg, uMsg, wParam, lParam );
  471.  
  472.     return FALSE; // Message not handled
  473. }
  474.  
  475.  
  476.  
  477.  
  478. //-----------------------------------------------------------------------------
  479. // Name: SessionsDlgProc()
  480. // Desc: Handles messages fro the multiplayer games dialog
  481. //-----------------------------------------------------------------------------
  482. INT_PTR CALLBACK CNetConnectWizard::SessionsDlgProc( HWND hDlg, UINT msg,
  483.                                                      WPARAM wParam, LPARAM lParam )
  484. {
  485.     HRESULT hr;
  486.  
  487.     switch( msg )
  488.     {
  489.         case WM_INITDIALOG:
  490.             {
  491.                 m_hDlg = hDlg;
  492.  
  493.                 // Load and set the icon
  494.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  495.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  496.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  497.  
  498.                 // Set the window title
  499.                 TCHAR strWindowTitle[256];
  500.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Games"), m_strAppName );
  501.                 SetWindowText( hDlg, strWindowTitle );
  502.  
  503.                 // Init the search portion of the dialog
  504.                 m_bSearchingForSessions = FALSE;
  505.                 SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
  506.                 SessionsDlgInitListbox( hDlg );
  507.             }
  508.             break;
  509.  
  510.         case WM_TIMER:
  511.             // Upon this timer message, then refresh the list of hosts
  512.             // by expiring old hosts, and displaying the list in the
  513.             // dialog box
  514.             if( wParam == TIMERID_DISPLAY_HOSTS )
  515.             {
  516.                 // Don't refresh if we are not enumerating hosts
  517.                 if( !m_bSearchingForSessions )
  518.                     break;
  519.  
  520.                 // Expire all of the hosts that haven't
  521.                 // refreshed in a certain period of time
  522.                 SessionsDlgExpireOldHostEnums();
  523.  
  524.                 // Display the list of hosts in the dialog
  525.                 if( FAILED( hr = SessionsDlgDisplayEnumList( hDlg ) ) )
  526.                 {
  527.                     DXTRACE_ERR( TEXT("SessionsDlgDisplayEnumList"), hr );
  528.                     KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  529.                     MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  530.                                 TEXT("DirectPlay Sample"),
  531.                                 MB_OK | MB_ICONERROR );
  532.                 }
  533.             }
  534.             else if( wParam == TIMERID_CONNECT_COMPLETE )
  535.             {
  536.                 // Check to see if the MessageHandler has set an event to tell us the
  537.                 // DPN_MSGID_CONNECT_COMPLETE has been processed.  Now m_hrConnectComplete
  538.                 // is valid.
  539.                 if( WAIT_OBJECT_0 == WaitForSingleObject( m_hConnectCompleteEvent, 0 ) )
  540.                 {
  541.                     m_bConnecting = FALSE;
  542.  
  543.                     // Re-enable create button
  544.                     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), TRUE );
  545.  
  546.                     if( FAILED( m_hrConnectComplete ) )
  547.                     {
  548.                         DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  549.                         MessageBox( m_hDlg, TEXT("Unable to join game."),
  550.                                     TEXT("DirectPlay Sample"),
  551.                                     MB_OK | MB_ICONERROR );
  552.                     }
  553.                     else
  554.                     {
  555.                         // DirectPlay connect successful, so end dialog
  556.                         m_hrDialog = NCW_S_FORWARD;
  557.                         EndDialog( m_hDlg, 0 );
  558.                     }
  559.  
  560.                     KillTimer( hDlg, TIMERID_CONNECT_COMPLETE );
  561.                 }
  562.             }
  563.  
  564.             break;
  565.  
  566.         case WM_COMMAND:
  567.             switch( LOWORD(wParam) )
  568.             {
  569.                 case IDC_SEARCH_CHECK:
  570.                     m_bSearchingForSessions = !m_bSearchingForSessions;
  571.  
  572.                     if( m_bSearchingForSessions )
  573.                     {
  574.                         SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Searching...") );
  575.  
  576.                         // Start the timer to display the host list every so often
  577.                         SetTimer( hDlg, TIMERID_DISPLAY_HOSTS, DISPLAY_REFRESH_RATE, NULL );
  578.  
  579.                         // Start the async enumeration
  580.                         if( FAILED( hr = SessionsDlgEnumHosts( hDlg ) ) )
  581.                         {
  582.                             DXTRACE_ERR( TEXT("SessionsDlgEnumHosts"), hr );
  583.                             KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  584.                             MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  585.                                         TEXT("DirectPlay Sample"),
  586.                                         MB_OK | MB_ICONERROR );
  587.                         }
  588.                     }
  589.                     else
  590.                     {
  591.                         SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
  592.  
  593.                         // Stop the timer, and stop the async enumeration
  594.                         KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  595.  
  596.                         // Until the CancelAsyncOperation returns, it is possible
  597.                         // to still receive host enumerations
  598.                         if( m_hEnumAsyncOp )
  599.                             m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
  600.  
  601.                         // Reset the search portion of the dialog
  602.                         SessionsDlgInitListbox( hDlg );
  603.                     }
  604.                     break;
  605.  
  606.                 case IDC_GAMES_LIST:
  607.                     if( HIWORD(wParam) != LBN_DBLCLK )
  608.                         break;
  609.                     // Fall through
  610.  
  611.                 case IDC_JOIN:
  612.                     if( FAILED( hr = SessionsDlgJoinGame( hDlg ) ) )
  613.                     {
  614.                         DXTRACE_ERR( TEXT("SessionsDlgJoinGame"), hr );
  615.                         MessageBox( hDlg, TEXT("Unable to join game."),
  616.                                     TEXT("DirectPlay Sample"),
  617.                                     MB_OK | MB_ICONERROR );
  618.                     }
  619.                     break;
  620.  
  621.                 case IDC_CREATE:
  622.                     if( FAILED( hr = SessionsDlgCreateGame( hDlg ) ) )
  623.                     {
  624.                         DXTRACE_ERR( TEXT("SessionsDlgCreateGame"), hr );
  625.                         MessageBox( hDlg, TEXT("Unable to create game."),
  626.                                     TEXT("DirectPlay Sample"),
  627.                                     MB_OK | MB_ICONERROR );
  628.                     }
  629.                     break;
  630.  
  631.                 case IDCANCEL: // The close button was press
  632.                     m_hrDialog = NCW_S_QUIT;
  633.                     EndDialog( hDlg, 0 );
  634.                     break;
  635.  
  636.                 case IDC_BACK: // Cancel button was pressed
  637.                     m_hrDialog = NCW_S_BACKUP;
  638.                     EndDialog( hDlg, 0 );
  639.                     break;
  640.  
  641.                 default:
  642.                     return FALSE; // Message not handled
  643.             }
  644.             break;
  645.  
  646.         case WM_DESTROY:
  647.         {
  648.             KillTimer( hDlg, 1 );
  649.  
  650.             // Cancel the enum hosts search
  651.             // if the enumeration is going on
  652.             if( m_bSearchingForSessions && m_hEnumAsyncOp )
  653.             {
  654.                 m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
  655.                 m_bSearchingForSessions = FALSE;
  656.             }
  657.             break;
  658.         }
  659.  
  660.         default:
  661.             return FALSE; // Message not handled
  662.     }
  663.  
  664.     // Message was handled
  665.     return TRUE;
  666. }
  667.  
  668.  
  669.  
  670.  
  671. //-----------------------------------------------------------------------------
  672. // Name: SessionsDlgInitListbox()
  673. // Desc: Initializes the listbox
  674. //-----------------------------------------------------------------------------
  675. VOID CNetConnectWizard::SessionsDlgInitListbox( HWND hDlg )
  676. {
  677.     HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  678.  
  679.     // Clear the contents from the list box, and
  680.     // display "Looking for games" text in listbox
  681.     SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  682.     if( m_bSearchingForSessions )
  683.     {
  684.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  685.                      (LPARAM) TEXT("Looking for games...") );
  686.     }
  687.     else
  688.     {
  689.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  690.                      (LPARAM) TEXT("Click Start Search to see a list of games.  ")
  691.                               TEXT("Click Create to start a new game.") );
  692.     }
  693.  
  694.     SendMessage( hWndListBox, LB_SETITEMDATA,  0, NULL );
  695.     SendMessage( hWndListBox, LB_SETCURSEL,    0, 0 );
  696.  
  697.     // Disable the join button until sessions are found
  698.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  699. }
  700.  
  701.  
  702.  
  703.  
  704. //-----------------------------------------------------------------------------
  705. // Name: SessionsDlgEnumHosts()
  706. // Desc: Enumerates the DirectPlay sessions, and displays them in the listbox
  707. //-----------------------------------------------------------------------------
  708. HRESULT CNetConnectWizard::SessionsDlgEnumHosts( HWND hDlg )
  709. {
  710.     HRESULT hr;
  711.  
  712.     m_bEnumListChanged = TRUE;
  713.  
  714.     // Enumerate hosts
  715.     DPN_APPLICATION_DESC    dnAppDesc;
  716.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  717.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  718.     dnAppDesc.guidApplication = m_guidApp;
  719.  
  720.     // Enumerate all the active DirectPlay games on the selected connection
  721.     hr = m_pDP->EnumHosts( &dnAppDesc,                            // application description
  722.                            m_pHostAddress,                        // host address
  723.                            m_pDeviceAddress,                      // device address
  724.                            NULL,                                  // pointer to user data
  725.                            0,                                     // user data size
  726.                            INFINITE,                              // retry count (forever)
  727.                            0,                                     // retry interval (0=default)
  728.                            INFINITE,                              // time out (forever)
  729.                            NULL,                                  // user context
  730.                            &m_hEnumAsyncOp,                       // async handle
  731.                            DPNENUMHOSTS_OKTOQUERYFORADDRESSING    // flags
  732.                            );
  733.     if( FAILED(hr) )
  734.         return DXTRACE_ERR( TEXT("EnumHosts"), hr );
  735.  
  736.     return S_OK;
  737. }
  738.  
  739.  
  740.  
  741.  
  742. //-----------------------------------------------------------------------------
  743. // Name: SessionsDlgNoteEnumResponse()
  744. // Desc: Stores them in the linked list, m_DPHostEnumHead.  This is
  745. //       called from the DirectPlay message handler so it could be
  746. //       called simultaneously from multiple threads.
  747. //-----------------------------------------------------------------------------
  748. HRESULT CNetConnectWizard::SessionsDlgNoteEnumResponse( PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg )
  749. {
  750.     HRESULT hr = S_OK;
  751.     BOOL    bFound;
  752.  
  753.     // This function is called from the DirectPlay message handler so it could be
  754.     // called simultaneously from multiple threads, so enter a critical section
  755.     // to assure that it we don't get race conditions.  Locking the entire
  756.     // function is crude, and could be more optimal but is effective for this
  757.     // simple sample
  758.     EnterCriticalSection( &m_csHostEnum );
  759.  
  760.     DPHostEnumInfo* pDPHostEnum          = m_DPHostEnumHead.pNext;
  761.     DPHostEnumInfo* pDPHostEnumNext      = NULL;
  762.     const DPN_APPLICATION_DESC* pResponseMsgAppDesc =
  763.                             pEnumHostsResponseMsg->pApplicationDescription;
  764.  
  765.     // Look for a matching session instance GUID.
  766.     bFound = FALSE;
  767.     while ( pDPHostEnum != &m_DPHostEnumHead )
  768.     {
  769.         if( pResponseMsgAppDesc->guidInstance == pDPHostEnum->pAppDesc->guidInstance )
  770.         {
  771.             bFound = TRUE;
  772.             break;
  773.         }
  774.  
  775.         pDPHostEnumNext = pDPHostEnum;
  776.         pDPHostEnum = pDPHostEnum->pNext;
  777.     }
  778.  
  779.     if( !bFound )
  780.     {
  781.         m_bEnumListChanged = TRUE;
  782.  
  783.         // If there's no match, then look for invalid session and use it
  784.         pDPHostEnum = m_DPHostEnumHead.pNext;
  785.         while ( pDPHostEnum != &m_DPHostEnumHead )
  786.         {
  787.             if( !pDPHostEnum->bValid )
  788.                 break;
  789.  
  790.             pDPHostEnum = pDPHostEnum->pNext;
  791.         }
  792.  
  793.         // If no invalid sessions are found then make a new one
  794.         if( pDPHostEnum == &m_DPHostEnumHead )
  795.         {
  796.             // Found a new session, so create a new node
  797.             pDPHostEnum = new DPHostEnumInfo;
  798.             if( NULL == pDPHostEnum )
  799.             {
  800.                 hr = E_OUTOFMEMORY;
  801.                 goto LCleanup;
  802.             }
  803.  
  804.             ZeroMemory( pDPHostEnum, sizeof(DPHostEnumInfo) );
  805.  
  806.             // Add pDPHostEnum to the circular linked list, m_DPHostEnumHead
  807.             pDPHostEnum->pNext = m_DPHostEnumHead.pNext;
  808.             m_DPHostEnumHead.pNext = pDPHostEnum;
  809.         }
  810.     }
  811.  
  812.     // Update the pDPHostEnum with new information
  813.     TCHAR strName[MAX_PATH];
  814.     if( pResponseMsgAppDesc->pwszSessionName )
  815.     {
  816.         DXUtil_ConvertWideStringToGeneric( strName, pResponseMsgAppDesc->pwszSessionName );
  817.     }
  818.  
  819.     // Cleanup any old enum
  820.     if( pDPHostEnum->pAppDesc )
  821.     {
  822.         SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc->pwszSessionName );
  823.         SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc );
  824.     }
  825.     SAFE_RELEASE( pDPHostEnum->pHostAddr );
  826.     SAFE_RELEASE( pDPHostEnum->pDeviceAddr );
  827.  
  828.     //
  829.     // Duplicate pEnumHostsResponseMsg->pAddressSender in pDPHostEnum->pHostAddr.
  830.     // Duplicate pEnumHostsResponseMsg->pAddressDevice in pDPHostEnum->pDeviceAddr.
  831.     //
  832.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressSender->Duplicate( &pDPHostEnum->pHostAddr ) ) )
  833.     {
  834.         DXTRACE_ERR( TEXT("Duplicate"), hr );
  835.         goto LCleanup;
  836.     }
  837.  
  838.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressDevice->Duplicate( &pDPHostEnum->pDeviceAddr ) ) )
  839.     {
  840.         DXTRACE_ERR( TEXT("Duplicate"), hr );
  841.         goto LCleanup;
  842.     }
  843.  
  844.     // Deep copy the DPN_APPLICATION_DESC from
  845.     pDPHostEnum->pAppDesc = new DPN_APPLICATION_DESC;
  846.     ZeroMemory( pDPHostEnum->pAppDesc, sizeof(DPN_APPLICATION_DESC) );
  847.     memcpy( pDPHostEnum->pAppDesc, pResponseMsgAppDesc, sizeof(DPN_APPLICATION_DESC) );
  848.     if( pResponseMsgAppDesc->pwszSessionName )
  849.     {
  850.         pDPHostEnum->pAppDesc->pwszSessionName = new WCHAR[ wcslen(pResponseMsgAppDesc->pwszSessionName)+1 ];
  851.         wcscpy( pDPHostEnum->pAppDesc->pwszSessionName,
  852.                 pResponseMsgAppDesc->pwszSessionName );
  853.     }
  854.  
  855.     // Update the time this was done, so that we can expire this host
  856.     // if it doesn't refresh w/in a certain amount of time
  857.     pDPHostEnum->dwLastPollTime = timeGetTime();
  858.  
  859.     // Check to see if the current number of players changed
  860.     TCHAR szSessionTemp[MAX_PATH];
  861.     if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
  862.     {
  863.         wsprintf( szSessionTemp, TEXT("%s (%d/%d) (%dms)"), strName,
  864.                   pResponseMsgAppDesc->dwCurrentPlayers,
  865.                   pResponseMsgAppDesc->dwMaxPlayers,
  866.                   pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  867.     }
  868.     else
  869.     {
  870.         wsprintf( szSessionTemp, TEXT("%s (%d) (%dms)"), strName,
  871.                   pResponseMsgAppDesc->dwCurrentPlayers,
  872.                   pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  873.     }
  874.  
  875.     // if this node was previously invalidated, or the session name is now
  876.     // different the session list in the dialog needs to be updated
  877.     if( ( pDPHostEnum->bValid == FALSE ) ||
  878.         ( _tcscmp( pDPHostEnum->szSession, szSessionTemp ) != 0 ) )
  879.     {
  880.         m_bEnumListChanged = TRUE;
  881.     }
  882.     _tcscpy( pDPHostEnum->szSession, szSessionTemp );
  883.  
  884.     // This host is now valid
  885.     pDPHostEnum->bValid = TRUE;
  886.  
  887. LCleanup:
  888.     LeaveCriticalSection( &m_csHostEnum );
  889.  
  890.     return hr;
  891. }
  892.  
  893.  
  894.  
  895.  
  896. //-----------------------------------------------------------------------------
  897. // Name: SessionsDlgExpireOldHostEnums
  898. // Desc: Check all nodes to see if any have expired yet.
  899. //-----------------------------------------------------------------------------
  900. VOID CNetConnectWizard::SessionsDlgExpireOldHostEnums()
  901. {
  902.     DWORD dwCurrentTime = timeGetTime();
  903.  
  904.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  905.     // is called from the DirectPlay message handler threads so
  906.     // they may also be inside it at this time, so we need to go into the
  907.     // critical section first
  908.     EnterCriticalSection( &m_csHostEnum );
  909.  
  910.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  911.     while ( pDPHostEnum != &m_DPHostEnumHead )
  912.     {
  913.         // Check the poll time to expire stale entries.  Also check to see if
  914.         // the entry is already invalid.  If so, don't note that the enum list
  915.         // changed because that causes the list in the dialog to constantly redraw.
  916.         if( ( pDPHostEnum->bValid != FALSE ) &&
  917.             ( pDPHostEnum->dwLastPollTime < dwCurrentTime - m_dwEnumHostExpireInterval ) )
  918.         {
  919.             // This node has expired, so invalidate it.
  920.             pDPHostEnum->bValid = FALSE;
  921.             m_bEnumListChanged  = TRUE;
  922.         }
  923.  
  924.         pDPHostEnum = pDPHostEnum->pNext;
  925.     }
  926.  
  927.     LeaveCriticalSection( &m_csHostEnum );
  928. }
  929.  
  930.  
  931.  
  932.  
  933. //-----------------------------------------------------------------------------
  934. // Name: SessionsDlgDisplayEnumList
  935. // Desc: Display the list of hosts in the dialog box
  936. //-----------------------------------------------------------------------------
  937. HRESULT CNetConnectWizard::SessionsDlgDisplayEnumList( HWND hDlg )
  938. {
  939.     HWND           hWndListBox   = GetDlgItem( hDlg, IDC_GAMES_LIST );
  940.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  941.     GUID           guidSelectedInstance;
  942.     BOOL           bFindSelectedGUID;
  943.     BOOL           bFoundSelectedGUID;
  944.     int            nItemSelected;
  945.  
  946.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  947.     // is called from the DirectPlay message handler threads so
  948.     // they may also be inside it at this time, so we need to go into the
  949.     // critical section first
  950.     EnterCriticalSection( &m_csHostEnum );
  951.  
  952.     // Only update the display list if it has changed since last time
  953.     if( !m_bEnumListChanged )
  954.     {
  955.         LeaveCriticalSection( &m_csHostEnum );
  956.         return S_OK;
  957.     }
  958.  
  959.     m_bEnumListChanged = FALSE;
  960.  
  961.     bFindSelectedGUID  = FALSE;
  962.     bFoundSelectedGUID = FALSE;
  963.  
  964.     // Try to keep the same session selected unless it goes away or
  965.     // there is no real session currently selected
  966.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  967.     if( nItemSelected != LB_ERR )
  968.     {
  969.         pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  970.                                                              nItemSelected, 0 );
  971.         if( pDPHostEnumSelected != NULL && pDPHostEnumSelected->bValid )
  972.         {
  973.             guidSelectedInstance = pDPHostEnumSelected->pAppDesc->guidInstance;
  974.             bFindSelectedGUID = TRUE;
  975.         }
  976.     }
  977.  
  978.     // Tell listbox not to redraw itself since the contents are going to change
  979.     SendMessage( hWndListBox, WM_SETREDRAW, FALSE, 0 );
  980.  
  981.     // Test to see if any sessions exist in the linked list
  982.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  983.     while ( pDPHostEnum != &m_DPHostEnumHead )
  984.     {
  985.         if( pDPHostEnum->bValid )
  986.             break;
  987.         pDPHostEnum = pDPHostEnum->pNext;
  988.     }
  989.  
  990.     // If there are any sessions in list,
  991.     // then add them to the listbox
  992.     if( pDPHostEnum != &m_DPHostEnumHead )
  993.     {
  994.         // Clear the contents from the list box and enable the join button
  995.         SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  996.  
  997.         // Enable the join button only if not already connecting to a game
  998.         if( !m_bConnecting )
  999.             EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), TRUE );
  1000.  
  1001.         pDPHostEnum = m_DPHostEnumHead.pNext;
  1002.         while ( pDPHostEnum != &m_DPHostEnumHead )
  1003.         {
  1004.             // Add host to list box if it is valid
  1005.             if( pDPHostEnum->bValid )
  1006.             {
  1007.                 int nIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  1008.                                                (LPARAM)pDPHostEnum->szSession );
  1009.                 SendMessage( hWndListBox, LB_SETITEMDATA, nIndex, (LPARAM)pDPHostEnum );
  1010.  
  1011.                 if( bFindSelectedGUID )
  1012.                 {
  1013.                     // Look for the session the was selected before
  1014.                     if( pDPHostEnum->pAppDesc->guidInstance == guidSelectedInstance )
  1015.                     {
  1016.                         SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
  1017.                         bFoundSelectedGUID = TRUE;
  1018.                     }
  1019.                 }
  1020.             }
  1021.  
  1022.             pDPHostEnum = pDPHostEnum->pNext;
  1023.         }
  1024.  
  1025.         if( !bFindSelectedGUID || !bFoundSelectedGUID )
  1026.             SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  1027.     }
  1028.     else
  1029.     {
  1030.         // There are no active session, so just reset the listbox
  1031.         SessionsDlgInitListbox( hDlg );
  1032.     }
  1033.  
  1034.     // Tell listbox to redraw itself now since the contents have changed
  1035.     SendMessage( hWndListBox, WM_SETREDRAW, TRUE, 0 );
  1036.     InvalidateRect( hWndListBox, NULL, FALSE );
  1037.  
  1038.     LeaveCriticalSection( &m_csHostEnum );
  1039.  
  1040.     return S_OK;
  1041. }
  1042.  
  1043.  
  1044.  
  1045.  
  1046. //-----------------------------------------------------------------------------
  1047. // Name: SessionsDlgJoinGame()
  1048. // Desc: Joins the selected DirectPlay session
  1049. //-----------------------------------------------------------------------------
  1050. HRESULT CNetConnectWizard::SessionsDlgJoinGame( HWND hDlg )
  1051. {
  1052.     HRESULT         hr;
  1053.     HWND            hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  1054.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  1055.     int             nItemSelected;
  1056.     DWORD           dwPort = 0;
  1057.  
  1058.     m_bHostPlayer = FALSE;
  1059.  
  1060.     // Add status text in list box
  1061.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  1062.  
  1063.     EnterCriticalSection( &m_csHostEnum );
  1064.  
  1065.     pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  1066.                                                          nItemSelected, 0 );
  1067.  
  1068.     if( NULL == pDPHostEnumSelected )
  1069.     {
  1070.         LeaveCriticalSection( &m_csHostEnum );
  1071.         MessageBox( hDlg, TEXT("There are no games to join."),
  1072.                     TEXT("DirectPlay Sample"), MB_OK );
  1073.         return S_OK;
  1074.     }
  1075.  
  1076.     m_bConnecting = TRUE;
  1077.  
  1078.     // Set the peer info
  1079.     WCHAR wszPeerName[MAX_PATH];
  1080.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1081.  
  1082.     DPN_PLAYER_INFO dpPlayerInfo;
  1083.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1084.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1085.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1086.     dpPlayerInfo.pwszName = wszPeerName;
  1087.  
  1088.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1089.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1090.     // be set by the time we call Connect() below.
  1091.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1092.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1093.  
  1094.     ResetEvent( m_hConnectCompleteEvent );
  1095.  
  1096.     // Connect to an existing session. DPNCONNECT_OKTOQUERYFORADDRESSING allows
  1097.     // DirectPlay to prompt the user using a dialog box for any device address
  1098.     // or host address information that is missing
  1099.     // We also pass in copies of the app desc and host addr, since pDPHostEnumSelected
  1100.     // might be deleted from another thread that calls SessionsDlgExpireOldHostEnums().
  1101.     // This process could also be done using reference counting instead.
  1102.     hr = m_pDP->Connect( pDPHostEnumSelected->pAppDesc,       // the application desc
  1103.                          pDPHostEnumSelected->pHostAddr,      // address of the host of the session
  1104.                          pDPHostEnumSelected->pDeviceAddr,    // address of the local device the enum responses were received on
  1105.                          NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1106.                          NULL, 0,                             // user data, user data size
  1107.                          NULL,                                // player context,
  1108.                          NULL, &m_hConnectAsyncOp,            // async context, async handle,
  1109.                          DPNCONNECT_OKTOQUERYFORADDRESSING ); // flags
  1110.     if( hr != E_PENDING && FAILED(hr) )
  1111.         return DXTRACE_ERR( TEXT("Connect"), hr );
  1112.  
  1113.     LeaveCriticalSection( &m_csHostEnum );
  1114.  
  1115.     // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  1116.     // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  1117.     // which lets us know if the connect was successful or not.
  1118.     SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  1119.  
  1120.     // Disable the create/join buttons until connect succeeds or fails
  1121.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  1122.     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), FALSE );
  1123.  
  1124.     return S_OK;
  1125. }
  1126.  
  1127.  
  1128.  
  1129.  
  1130. //-----------------------------------------------------------------------------
  1131. // Name: SessionsDlgCreateGame()
  1132. // Desc: Asks the user the session name, and creates a new DirectPlay session
  1133. //-----------------------------------------------------------------------------
  1134. HRESULT CNetConnectWizard::SessionsDlgCreateGame( HWND hDlg )
  1135. {
  1136.     HRESULT hr;
  1137.     int     nResult;
  1138.  
  1139.     // Display a modal multiplayer connect dialog box.
  1140.     EnableWindow( hDlg, FALSE );
  1141.     nResult = (int)DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CREATE),
  1142.                               hDlg, (DLGPROC) StaticCreateSessionDlgProc );
  1143.     EnableWindow( hDlg, TRUE );
  1144.  
  1145.     if( nResult == IDCANCEL )
  1146.         return S_OK;
  1147.  
  1148.     // Stop the search if we are about to connect
  1149.     if( m_bSearchingForSessions )
  1150.     {
  1151.         CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  1152.         SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
  1153.     }
  1154.  
  1155.     m_bHostPlayer = TRUE;
  1156.  
  1157.     // Set peer info name
  1158.     WCHAR wszPeerName[MAX_PATH];
  1159.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1160.  
  1161.     DPN_PLAYER_INFO dpPlayerInfo;
  1162.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1163.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1164.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1165.     dpPlayerInfo.pwszName = wszPeerName;
  1166.  
  1167.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1168.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1169.     // be set by the time we call Host() below.
  1170.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1171.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1172.  
  1173.     WCHAR wszSessionName[MAX_PATH];
  1174.     DXUtil_ConvertGenericStringToWide( wszSessionName, m_strSessionName );
  1175.  
  1176.     // Setup the application desc
  1177.     DPN_APPLICATION_DESC dnAppDesc;
  1178.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1179.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  1180.     dnAppDesc.guidApplication = m_guidApp;
  1181.     dnAppDesc.pwszSessionName = wszSessionName;
  1182.     dnAppDesc.dwMaxPlayers    = m_dwMaxPlayers;
  1183.     dnAppDesc.dwFlags         = 0;
  1184.     if( m_bMigrateHost )
  1185.         dnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1186.  
  1187.     // Host a game on m_pDeviceAddress as described by dnAppDesc
  1188.     // DPNHOST_OKTOQUERYFORADDRESSING allows DirectPlay to prompt the user
  1189.     // using a dialog box for any device address information that is missing
  1190.     if( FAILED( hr = m_pDP->Host( &dnAppDesc,               // the application desc
  1191.                                   &m_pDeviceAddress,        // array of addresses of the local devices used to connect to the host
  1192.                                   1,                        // number in array
  1193.                                   NULL, NULL,               // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1194.                                   NULL,                     // player context
  1195.                                   DPNHOST_OKTOQUERYFORADDRESSING ) ) ) // flags
  1196.         return DXTRACE_ERR( TEXT("Host"), hr );
  1197.  
  1198.     // DirectPlay connect successful, so end dialog
  1199.     m_hrDialog = NCW_S_FORWARD;
  1200.     EndDialog( hDlg, 0 );
  1201.  
  1202.     return S_OK;
  1203. }
  1204.  
  1205.  
  1206.  
  1207.  
  1208. //-----------------------------------------------------------------------------
  1209. // Name: StaticConnectionsDlgProc()
  1210. // Desc: Static msg handler which passes messages
  1211. //-----------------------------------------------------------------------------
  1212. INT_PTR CALLBACK CNetConnectWizard::StaticCreateSessionDlgProc( HWND hDlg, UINT uMsg,
  1213.                                                                 WPARAM wParam, LPARAM lParam )
  1214. {
  1215.     if( g_pNCW )
  1216.         return g_pNCW->CreateSessionDlgProc( hDlg, uMsg, wParam, lParam );
  1217.  
  1218.     return FALSE; // Message not handled
  1219. }
  1220.  
  1221.  
  1222.  
  1223.  
  1224. //-----------------------------------------------------------------------------
  1225. // Name: CreateSessionDlgProc()
  1226. // Desc: Handles messages fro the multiplayer create game dialog
  1227. //-----------------------------------------------------------------------------
  1228. INT_PTR CALLBACK CNetConnectWizard::CreateSessionDlgProc( HWND hDlg, UINT msg,
  1229.                                                           WPARAM wParam, LPARAM lParam )
  1230. {
  1231.     DWORD dwNameLength;
  1232.  
  1233.     switch( msg )
  1234.     {
  1235.         case WM_INITDIALOG:
  1236.             SetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME, m_strSessionName );
  1237.             CheckDlgButton( hDlg, IDC_MIGRATE_HOST, BST_CHECKED );
  1238.             return TRUE;
  1239.  
  1240.         case WM_COMMAND:
  1241.             switch( LOWORD(wParam) )
  1242.             {
  1243.                 case IDOK:
  1244.                     dwNameLength = GetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME,
  1245.                                                    m_strSessionName,
  1246.                                                    MAX_PATH );
  1247.                     if( dwNameLength == 0 )
  1248.                         return TRUE; // Don't accept blank session names
  1249.  
  1250.                     m_bMigrateHost = ( IsDlgButtonChecked( hDlg,
  1251.                                        IDC_MIGRATE_HOST ) == BST_CHECKED );
  1252.  
  1253.                     EndDialog( hDlg, IDOK );
  1254.                     return TRUE;
  1255.  
  1256.                 case IDCANCEL:
  1257.                     EndDialog( hDlg, IDCANCEL );
  1258.                     return TRUE;
  1259.             }
  1260.             break;
  1261.     }
  1262.  
  1263.     return FALSE; // Didn't handle message
  1264. }
  1265.  
  1266.  
  1267.  
  1268.  
  1269. //-----------------------------------------------------------------------------
  1270. // Name: SessionsDlgEnumListCleanup()
  1271. // Desc: Deletes the linked list, g_DPHostEnumInfoHead
  1272. //-----------------------------------------------------------------------------
  1273. VOID CNetConnectWizard::SessionsDlgEnumListCleanup()
  1274. {
  1275.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  1276.     DPHostEnumInfo* pDPHostEnumDelete;
  1277.  
  1278.     while ( pDPHostEnum != &m_DPHostEnumHead )
  1279.     {
  1280.         pDPHostEnumDelete = pDPHostEnum;
  1281.         pDPHostEnum = pDPHostEnum->pNext;
  1282.  
  1283.         if( pDPHostEnumDelete->pAppDesc )
  1284.         {
  1285.             SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc->pwszSessionName );
  1286.             SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc );
  1287.         }
  1288.  
  1289.         // Changed from array delete to Release
  1290.         SAFE_RELEASE( pDPHostEnumDelete->pHostAddr );
  1291.         SAFE_RELEASE( pDPHostEnumDelete->pDeviceAddr );
  1292.         SAFE_DELETE( pDPHostEnumDelete );
  1293.     }
  1294.  
  1295.     // Re-link the g_DPHostEnumInfoHead circular linked list
  1296.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  1297. }
  1298.  
  1299.  
  1300.  
  1301.  
  1302. //-----------------------------------------------------------------------------
  1303. // Name: MessageHandler
  1304. // Desc: Handler for DirectPlay messages.  This function is called by
  1305. //       the DirectPlay message handler pool of threads, so be careful of thread
  1306. //       synchronization problems with shared memory
  1307. //-----------------------------------------------------------------------------
  1308. HRESULT WINAPI CNetConnectWizard::MessageHandler( PVOID pvUserContext,
  1309.                                                   DWORD dwMessageId,
  1310.                                                   PVOID pMsgBuffer )
  1311. {
  1312.     // Try not to stay in this message handler for too long, otherwise
  1313.     // there will be a backlog of data.  The best solution is to
  1314.     // queue data as it comes in, and then handle it on other threads.
  1315.  
  1316.     // This function is called by the DirectPlay message handler pool of
  1317.     // threads, so be careful of thread synchronization problems with shared memory
  1318.  
  1319.     switch(dwMessageId)
  1320.     {
  1321.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  1322.         {
  1323.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
  1324.             pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
  1325.  
  1326.             // Take note of the host response
  1327.             SessionsDlgNoteEnumResponse( pEnumHostsResponseMsg );
  1328.             break;
  1329.         }
  1330.  
  1331.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  1332.         {
  1333.             PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
  1334.             pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
  1335.  
  1336.             if( pAsyncOpCompleteMsg->hAsyncOp == m_hEnumAsyncOp )
  1337.             {
  1338.                 SessionsDlgEnumListCleanup();
  1339.  
  1340.                 // The user canceled the DirectPlay connection dialog,
  1341.                 // so stop the search
  1342.                 if( m_bSearchingForSessions )
  1343.                 {
  1344.                     CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  1345.                     SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
  1346.                 }
  1347.  
  1348.                 m_hEnumAsyncOp = NULL;
  1349.                 m_bSearchingForSessions = FALSE;
  1350.             }
  1351.             break;
  1352.         }
  1353.  
  1354.         case DPN_MSGID_CONNECT_COMPLETE:
  1355.         {
  1356.             PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
  1357.             pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
  1358.  
  1359.             // Set m_hrConnectComplete, then set an event letting
  1360.             // everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
  1361.             // has been handled
  1362.             m_hrConnectComplete = pConnectCompleteMsg->hResultCode;
  1363.             SetEvent( m_hConnectCompleteEvent );
  1364.             break;
  1365.         }
  1366.     }
  1367.  
  1368.     return S_OK;
  1369. }
  1370.  
  1371.  
  1372.  
  1373.  
  1374. //-----------------------------------------------------------------------------
  1375. // Name: ConnectUsingLobbySettings
  1376. // Desc: Call this after the DPL_MSGID_CONNECT has been processed to carry out
  1377. //       the connection settings recieved by the lobby client.  DPL_MSGID_CONNECT
  1378. //       will have already been processed if we were lobby launched, or after
  1379. //       WaitForConnection returns without timing out.
  1380. //-----------------------------------------------------------------------------
  1381. HRESULT CNetConnectWizard::ConnectUsingLobbySettings()
  1382. {
  1383.     HRESULT hr;
  1384.     DPNHANDLE hAsync;
  1385.  
  1386.     if( m_hLobbyClient == NULL )
  1387.         return E_INVALIDARG;
  1388.  
  1389.     DPL_CONNECTION_SETTINGS* pSettings = NULL;
  1390.     DWORD dwSettingsSize = 0;
  1391.  
  1392.     // Get the connection settings from the lobby.
  1393.     hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 );
  1394.     if( hr != DPNERR_BUFFERTOOSMALL )
  1395.         return DXTRACE_ERR( TEXT("GetConnectionSettings"), hr );
  1396.     pSettings = (DPL_CONNECTION_SETTINGS*) new BYTE[dwSettingsSize];
  1397.     if( FAILED( hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 ) ) )
  1398.         return DXTRACE_ERR( TEXT("GetConnectionSettings"), hr );
  1399.  
  1400.     // Check if the lobby told us to host the game
  1401.     m_bHostPlayer = (pSettings->dwFlags & DPLCONNECTSETTINGS_HOST);
  1402.  
  1403.     // Set the peer info
  1404.     WCHAR wszPeerName[MAX_PATH];
  1405.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1406.     DPN_PLAYER_INFO dpPlayerInfo;
  1407.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1408.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1409.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1410.     dpPlayerInfo.pwszName = wszPeerName;
  1411.  
  1412.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1413.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1414.     // be set by the time we call Connect() below.
  1415.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1416.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1417.  
  1418.     if( m_bHostPlayer )
  1419.     {
  1420.         // Enable host migrate by default.
  1421.         pSettings->dpnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1422.  
  1423.         // Host a game as described by pSettings
  1424.         if( FAILED( hr = m_pDP->Host( &pSettings->dpnAppDesc,               // the application desc
  1425.                                       pSettings->ppdp8DeviceAddresses,      // array of addresses of the local devices used to connect to the host
  1426.                                       pSettings->cNumDeviceAddresses,       // number in array
  1427.                                       NULL, NULL,                           // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1428.                                       NULL,                                 // player context
  1429.                                       0 ) ) )                               // flags
  1430.             return DXTRACE_ERR( TEXT("Host"), hr );
  1431.     }
  1432.     else
  1433.     {
  1434.         // Connect to an existing session. There should only be on device address in
  1435.         // the connection settings structure when connecting to a session, so just
  1436.         // pass in the first one.
  1437.         // The enumeration is automatically cancelled after Connect is called 
  1438.         hr = m_pDP->Connect( &pSettings->dpnAppDesc,              // the application desc
  1439.                              pSettings->pdp8HostAddress,          // address of the host of the session
  1440.                              pSettings->ppdp8DeviceAddresses[0],  // address of the local device used to connect to the host
  1441.                              NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1442.                              NULL, 0,                             // user data, user data size
  1443.                              NULL,                                // player context,
  1444.                              NULL, &hAsync,                       // async context, async handle,
  1445.                              0 );                                 // flags
  1446.         if( hr != E_PENDING && FAILED(hr) )
  1447.             return DXTRACE_ERR( TEXT("Connect"), hr );
  1448.         hr = S_OK; // Accept E_PENDING.
  1449.  
  1450.         // Wait until the MessageHandler sets an event to tell us the
  1451.         // DPN_MSGID_CONNECT_COMPLETE has been processed.  Then m_hrConnectComplete
  1452.         // will be valid.
  1453.         WaitForSingleObject( m_hConnectCompleteEvent, INFINITE );
  1454.  
  1455.         if( FAILED( m_hrConnectComplete ) )
  1456.         {
  1457.             DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  1458.             MessageBox( m_hDlg, TEXT("Unable to join game."),
  1459.                         TEXT("DirectPlay Sample"),
  1460.                         MB_OK | MB_ICONERROR );
  1461.             hr = m_hrConnectComplete;
  1462.         }
  1463.     }
  1464.  
  1465.     // Cleanup the addresses and memory obtained from GetConnectionSettings
  1466.     SAFE_RELEASE( pSettings->pdp8HostAddress );
  1467.     for( DWORD dwIndex=0; dwIndex < pSettings->cNumDeviceAddresses; dwIndex++ )
  1468.     {
  1469.         SAFE_RELEASE( pSettings->ppdp8DeviceAddresses[dwIndex] );
  1470.     }
  1471.  
  1472.     SAFE_DELETE_ARRAY( pSettings );
  1473.  
  1474.     return hr;
  1475. }
  1476.  
  1477.  
  1478.  
  1479.  
  1480. //-----------------------------------------------------------------------------
  1481. // Name: LobbyMessageHandler
  1482. // Desc: Handler for DirectPlay messages.  This function is called by
  1483. //       the DirectPlay lobby message handler pool of threads, so be careful of thread
  1484. //       synchronization problems with shared memory
  1485. //-----------------------------------------------------------------------------
  1486. HRESULT WINAPI CNetConnectWizard::LobbyMessageHandler( PVOID pvUserContext,
  1487.                                                        DWORD dwMessageId,
  1488.                                                        PVOID pMsgBuffer )
  1489. {
  1490.     HRESULT hr = S_OK;
  1491.  
  1492.     switch(dwMessageId)
  1493.     {
  1494.         case DPL_MSGID_CONNECT:
  1495.         {
  1496.             // This message will be processed when a lobby connection has been
  1497.             // established. If you were lobby launched then
  1498.             // IDirectPlay8LobbiedApplication::Initialize()
  1499.             // waits until this message has been processed before returning, so
  1500.             // take care not to deadlock by making calls that need to be handled by
  1501.             // the thread who called Initialize().  The same is true for WaitForConnection()
  1502.  
  1503.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1504.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1505.             PDPL_CONNECTION_SETTINGS pSettings = pConnectMsg->pdplConnectionSettings;
  1506.  
  1507.             m_hLobbyClient = pConnectMsg->hConnectId;
  1508.  
  1509.             if( FAILED( hr = m_pDP->RegisterLobby( m_hLobbyClient, m_pLobbiedApp,
  1510.                                                    DPNLOBBY_REGISTER ) ) )
  1511.                 return DXTRACE_ERR( TEXT("RegisterLobby"), hr );
  1512.  
  1513.             if( pSettings == NULL )
  1514.             {
  1515.                 // There aren't connection settings from the lobby
  1516.                 m_bHaveConnectionSettingsFromLobby = FALSE;
  1517.             }
  1518.             else
  1519.             {
  1520.                 // Record the player name if found
  1521.                 if( pSettings->pwszPlayerName != NULL )
  1522.                 {
  1523.                     TCHAR strPlayerName[MAX_PATH];
  1524.                     DXUtil_ConvertWideStringToGeneric( strPlayerName, pSettings->pwszPlayerName );
  1525.                     _tcscpy( m_strLocalPlayerName, strPlayerName );
  1526.                 }
  1527.                 else
  1528.                 {
  1529.                     _tcscpy( m_strLocalPlayerName, TEXT("Unknown player name") );
  1530.                 }
  1531.  
  1532.                 m_bHaveConnectionSettingsFromLobby = TRUE;
  1533.             }
  1534.  
  1535.             // Tell everyone we have a lobby connection now
  1536.             SetEvent( m_hLobbyConnectionEvent );
  1537.             break;
  1538.         }
  1539.     }
  1540.  
  1541.     return S_OK;
  1542. }
  1543.  
  1544.  
  1545.  
  1546. //-----------------------------------------------------------------------------
  1547. // Name: StaticLobbyWaitDlgProc()
  1548. // Desc: Static msg handler which passes messages
  1549. //-----------------------------------------------------------------------------
  1550. INT_PTR CALLBACK CNetConnectWizard::StaticLobbyWaitDlgProc( HWND hDlg, UINT uMsg,
  1551.                                                                 WPARAM wParam, LPARAM lParam )
  1552. {
  1553.     if( g_pNCW )
  1554.         return g_pNCW->LobbyWaitDlgProc( hDlg, uMsg, wParam, lParam );
  1555.  
  1556.     return FALSE; // Message not handled
  1557. }
  1558.  
  1559.  
  1560.  
  1561.  
  1562. //-----------------------------------------------------------------------------
  1563. // Name: LobbyWaitDlgProc()
  1564. // Desc: Handles messages for the lobby wait status dialog
  1565. //-----------------------------------------------------------------------------
  1566. INT_PTR CALLBACK CNetConnectWizard::LobbyWaitDlgProc( HWND hDlg, UINT msg,
  1567.                                                       WPARAM wParam, LPARAM lParam )
  1568. {
  1569.     switch( msg )
  1570.     {
  1571.         case WM_INITDIALOG:
  1572.             // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  1573.             // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  1574.             // which lets us know if the connect was successful or not.
  1575.             SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  1576.  
  1577.             SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Waiting for lobby connection...") );
  1578.             return TRUE;
  1579.  
  1580.         case WM_COMMAND:
  1581.             switch( LOWORD(wParam) )
  1582.             {
  1583.                 case IDCANCEL:
  1584.                     EndDialog( hDlg, IDCANCEL );
  1585.                     return TRUE;
  1586.             }
  1587.             break;
  1588.  
  1589.         case WM_TIMER:
  1590.         {
  1591.             if( wParam == TIMERID_CONNECT_COMPLETE )
  1592.             {
  1593.                 // Wait for a lobby connection.  If this call
  1594.                 // returns WAIT_OBJECT_0 then the DPL_MSGID_CONNECT will
  1595.                 // have already been processed.
  1596.                 DWORD dwResult = WaitForSingleObject( m_hLobbyConnectionEvent, 100 );
  1597.                 if( dwResult != WAIT_TIMEOUT )
  1598.                     EndDialog( hDlg, IDOK );
  1599.             }
  1600.             break;
  1601.         }
  1602.     }
  1603.  
  1604.     return FALSE; // Didn't handle message
  1605. }
  1606.  
  1607.  
  1608.  
  1609.  
  1610.