home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directplay / addressoverride / addressoverride.cpp next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  53.4 KB  |  1,322 lines

  1. //----------------------------------------------------------------------------
  2. // File: AddressOverride.cpp
  3. //
  4. // Desc: The main game file for the AddressOverride sample.  AddressOverride
  5. //       shows how to override the DirectPlay addressing in order to host or 
  6. //       connect to another session on the network.
  7. // 
  8. //       After a new game has started the sample begins a very simplistic 
  9. //       game called "The Greeting Game".  When two or more players are connected
  10. //       to the game, the players have the option of sending a single simple 
  11. //       DirectPlay message to all of the other players. When this message
  12. //       is receieved by the other players, they simply display a dialog box.
  13. //
  14. // Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. #define STRICT
  17. #include <winsock.h>
  18. #include <windows.h>
  19. #include <basetsd.h>
  20. #include <dplay8.h>
  21. #include <dplobby8.h>
  22. #include <dpaddr.h>
  23. #include <dxerr8.h>
  24. #include <tchar.h>
  25. #include <cguid.h>
  26. #include "DXUtil.h"
  27. #include "resource.h"
  28.  
  29.  
  30.  
  31.  
  32. //-----------------------------------------------------------------------------
  33. // Player context locking defines
  34. //-----------------------------------------------------------------------------
  35. CRITICAL_SECTION g_csPlayerContext;
  36. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  37. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  38. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  39. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  40.  
  41.  
  42. //-----------------------------------------------------------------------------
  43. // Defines, and constants
  44. //-----------------------------------------------------------------------------
  45. #define DPLAY_SAMPLE_KEY                TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  46. #define MAX_PLAYER_NAME                 14
  47. #define WM_APP_UPDATE_STATS             (WM_APP + 0)
  48. #define WM_APP_DISPLAY_WAVE             (WM_APP + 1)
  49. #define TIMER_WAIT_HOSTS_RESPONSE       (1)
  50.  
  51. // This GUID allows DirectPlay to find other instances of the same game on
  52. // the network.  So it must be unique for every game, and the same for 
  53. // every instance of that game.  // {02AE835D-9179-485f-8343-901D327CE794}
  54. GUID g_guidApp = { 0x2ae835d, 0x9179, 0x485f, { 0x83, 0x43, 0x90, 0x1d, 0x32, 0x7c, 0xe7, 0x94 } };
  55.  
  56. struct APP_PLAYER_INFO
  57. {
  58.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  59.                                             // are done w/ this object
  60.     DPNID dpnidPlayer;                      // DPNID of player
  61.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  62. };
  63.  
  64.  
  65.  
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Global variables
  69. //-----------------------------------------------------------------------------
  70. IDirectPlay8Peer*       g_pDP                         = NULL;    // DirectPlay peer object
  71. HINSTANCE               g_hInst                       = NULL;    // HINST of app
  72. HWND                    g_hDlg                        = NULL;    // HWND of main dialog
  73. DPNID                   g_dpnidLocalPlayer            = 0;       // DPNID of local player
  74. LONG                    g_lNumberOfActivePlayers      = 0;       // Number of players currently in game
  75. TCHAR                   g_strAppName[256]             = TEXT("AddressOverride");
  76. HRESULT                 g_hrDialog;                              // Exit code for app 
  77. TCHAR                   g_strLocalPlayerName[MAX_PATH];          // Local player name
  78. TCHAR                   g_strSessionName[MAX_PATH];              // Session name
  79. TCHAR                   g_strPreferredProvider[MAX_PATH];        // Provider string
  80.  
  81. BOOL                    g_bHostPlayer                 = FALSE;   // TRUE if local player is host
  82. GUID*                   g_pCurSPGuid                  = NULL;    // Currently selected guid
  83. TCHAR                   g_strLocalIP[100];                       // Local IP address
  84. HANDLE                  g_hConnectCompleteEvent       = NULL;    // Event signaled when connection complete
  85. HRESULT                 g_hrConnectComplete           = S_OK;    // Status of connection when it completes
  86. HANDLE                  g_hEnumHostEvent              = NULL;    // Event signaled when the first session is enum
  87. DPNHANDLE               g_hEnumAsyncOp                = NULL;    // Async handle for enuming hosts
  88. DPN_APPLICATION_DESC*   g_pEnumedSessionAppDesc       = NULL;    // App desc of first session enumed
  89. IDirectPlay8Address*    g_pEnumedSessionHostAddr      = NULL;    // Host addr of first session enumed
  90. IDirectPlay8Address*    g_pEnumedSessionDeviceAddr    = NULL;    // Address of device to use
  91.  
  92.  
  93. //-----------------------------------------------------------------------------
  94. // App specific DirectPlay messages and structures 
  95. //-----------------------------------------------------------------------------
  96. #define GAME_MSGID_WAVE        1
  97.  
  98. // Change compiler pack alignment to be BYTE aligned, and pop the current value
  99. #pragma pack( push, 1 )
  100.  
  101. struct GAMEMSG_GENERIC
  102. {
  103.     DWORD dwType;
  104. };
  105.  
  106. // Pop the old pack alignment
  107. #pragma pack( pop )
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Function-prototypes
  113. //-----------------------------------------------------------------------------
  114. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  115. INT_PTR CALLBACK OverrideDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  116. INT_PTR CALLBACK GreetingDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  117. HRESULT          InitDirectPlay();
  118. HRESULT          OnInitOverrideDialog( HWND hDlg );
  119. VOID             SetupAddressFields( HWND hDlg );
  120. HRESULT          EnumServiceProviders( HWND hDlg );
  121. HRESULT          EnumAdapters( HWND hDlg, GUID* pSPGuid );
  122. HRESULT          LaunchMultiplayerGame( HWND hDlg );
  123. HRESULT          WaveToAllPlayers();
  124. VOID             AppendTextToEditControl( HWND hDlg, TCHAR* strNewLogLine );
  125.  
  126.  
  127.  
  128.  
  129. //-----------------------------------------------------------------------------
  130. // Name: WinMain()
  131. // Desc: Entry point for the application.  Since we use a simple dialog for 
  132. //       user interaction we don't need to pump messages.
  133. //-----------------------------------------------------------------------------
  134. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, 
  135.                       LPSTR pCmdLine, INT nCmdShow )
  136. {
  137.     HRESULT hr;
  138.     HKEY    hDPlaySampleRegKey;
  139.     BOOL    bConnectSuccess = FALSE;
  140.  
  141.     g_hInst = hInst; 
  142.     InitializeCriticalSection( &g_csPlayerContext );
  143.     g_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 
  144.     g_hEnumHostEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 
  145.  
  146.     // Read persistent state information from registry
  147.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  148.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  149.                     &hDPlaySampleRegKey, NULL );
  150.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  151.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  152.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  153.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  154.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  155.                              g_strPreferredProvider, MAX_PATH, 
  156.                              TEXT("DirectPlay8 TCP/IP Service Provider") );
  157.  
  158.     // Init COM so we can use CoCreateInstance
  159.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  160.  
  161.     if( FAILED( hr = InitDirectPlay() ) )
  162.     {
  163.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  164.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  165.                     TEXT("The sample will now quit."),
  166.                     g_strAppName, MB_OK | MB_ICONERROR );
  167.         return FALSE;
  168.     }
  169.  
  170.     // Connect or host a DirectPlay session.  Pop UI to query 
  171.     // for addressing so that DirectPlay's default dialogs are overridden
  172.     g_hrDialog = S_OK;
  173.     DialogBox( g_hInst, MAKEINTRESOURCE(IDD_ADDRESS_OVERRIDE), NULL, 
  174.                (DLGPROC) OverrideDlgProc );
  175.     
  176.     if( FAILED( g_hrDialog ) ) 
  177.     {
  178.         DXTRACE_ERR( TEXT("ConnectUsingOverrideDlg"), g_hrDialog );
  179.         MessageBox( NULL, TEXT("Mutliplayer connect failed. ")
  180.                     TEXT("The sample will now quit."),
  181.                     g_strAppName, MB_OK | MB_ICONERROR );
  182.         bConnectSuccess = FALSE;
  183.     } 
  184.     else if( g_hrDialog == S_FALSE ) 
  185.     {
  186.         // The user canceled the connect dialog, so quit 
  187.         bConnectSuccess = FALSE;
  188.     }
  189.     else
  190.     {
  191.         bConnectSuccess = TRUE; 
  192.  
  193.         // Write information to the registry
  194.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  195.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  196.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  197.     }
  198.  
  199.     if( bConnectSuccess )
  200.     {
  201.         // App is now connected via DirectPlay, so start the game.  
  202.  
  203.         // For this sample, we just start a simple dialog box game.
  204.         g_hrDialog = S_OK;
  205.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, 
  206.                    (DLGPROC) GreetingDlgProc );
  207.  
  208.         if( FAILED( g_hrDialog ) )
  209.         {
  210.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  211.             {
  212.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  213.                             TEXT("The sample will now quit."),
  214.                             g_strAppName, MB_OK | MB_ICONERROR );
  215.             }
  216.             else
  217.             {
  218.                 DXTRACE_ERR( TEXT("DialogBox"), g_hrDialog );
  219.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  220.                             TEXT("The sample will now quit."),
  221.                             g_strAppName, MB_OK | MB_ICONERROR );
  222.             }
  223.         }
  224.     }
  225.  
  226.     if( g_pDP )
  227.     {
  228.         g_pDP->Close(0);
  229.         SAFE_RELEASE( g_pDP );
  230.     }
  231.  
  232.     RegCloseKey( hDPlaySampleRegKey );
  233.     DeleteCriticalSection( &g_csPlayerContext );
  234.     CloseHandle( g_hEnumHostEvent );
  235.     CloseHandle( g_hConnectCompleteEvent );
  236.     CoUninitialize();
  237.  
  238.     return TRUE;
  239. }
  240.  
  241.  
  242.  
  243.  
  244. //-----------------------------------------------------------------------------
  245. // Name: InitDirectPlay()
  246. // Desc: 
  247. //-----------------------------------------------------------------------------
  248. HRESULT InitDirectPlay()
  249. {
  250.     HRESULT hr;
  251.  
  252.     // Create IDirectPlay8Peer
  253.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  254.                                        CLSCTX_INPROC_SERVER,
  255.                                        IID_IDirectPlay8Peer, 
  256.                                        (LPVOID*) &g_pDP ) ) )
  257.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  258.  
  259.     // Init IDirectPlay8Peer
  260.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  261.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  262.  
  263.     return S_OK;
  264. }
  265.  
  266.  
  267.  
  268.  
  269. //-----------------------------------------------------------------------------
  270. // Name: OverrideDlgProc()
  271. // Desc: Handles dialog messages
  272. //-----------------------------------------------------------------------------
  273. INT_PTR CALLBACK OverrideDlgProc( HWND hDlg, UINT msg, 
  274.                                   WPARAM wParam, LPARAM lParam )
  275. {
  276.     HRESULT hr;
  277.  
  278.     switch( msg ) 
  279.     {
  280.         case WM_INITDIALOG:
  281.         {
  282.             g_hDlg = hDlg;
  283.             if( FAILED( hr = OnInitOverrideDialog( hDlg ) ) )
  284.             {
  285.                 DXTRACE_ERR( TEXT("OnInitDialog"), hr );
  286.                 MessageBox( NULL, TEXT("Failed initializing dialog box. ")
  287.                             TEXT("The sample will now quit."),
  288.                             g_strAppName, MB_OK | MB_ICONERROR );
  289.                 EndDialog( hDlg, 0 );
  290.             }
  291.             break;
  292.         }
  293.  
  294.         case WM_COMMAND:
  295.         {
  296.             switch( LOWORD(wParam) )
  297.             {
  298.                 case IDC_HOST_SESSION:
  299.                     SetupAddressFields( hDlg );
  300.                     break;
  301.  
  302.                 case IDC_SP_COMBO:
  303.                 {
  304.                     // If the pSPGuid changed then re-enum the adapters, and
  305.                     // update the address fields.
  306.                     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  307.                     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  308.                     if( pSPGuid != NULL && g_pCurSPGuid != pSPGuid )
  309.                     {
  310.                         g_pCurSPGuid = pSPGuid;
  311.                         SetupAddressFields( hDlg );
  312.                         EnumAdapters( hDlg, pSPGuid );
  313.                     }
  314.                     break;
  315.                 }
  316.  
  317.                 case IDOK:
  318.                     if( FAILED( g_hrDialog = LaunchMultiplayerGame( hDlg ) ) )
  319.                     {
  320.                         if( g_hrDialog == DPNERR_ADDRESSING )
  321.                         {
  322.                             // This will be returned if the ip address is invalid
  323.                             MessageBox( hDlg, TEXT("IP address not valid."),
  324.                                         g_strAppName, MB_OK );
  325.                         }
  326.                         else
  327.                         {
  328.                             DXTRACE_ERR( TEXT("LaunchMultiplayerGame"), g_hrDialog );
  329.                             MessageBox( NULL, TEXT("Failed to launch game. "),
  330.                                         g_strAppName, MB_OK | MB_ICONERROR );                        
  331.                         }
  332.                     }
  333.                     break;
  334.  
  335.                 case IDCANCEL:
  336.                     g_hrDialog = S_FALSE;
  337.                     EndDialog( hDlg, 0 );
  338.                     break;
  339.             }
  340.             break;
  341.         }
  342.  
  343.         case WM_TIMER:
  344.             if( wParam == TIMER_WAIT_HOSTS_RESPONSE )
  345.             {
  346.                 DWORD dwResult;
  347.                 
  348.                 dwResult = WaitForSingleObject( g_hEnumHostEvent, 0 );
  349.                 if( dwResult == WAIT_OBJECT_0 )
  350.                 {
  351.                     // Connect to host that was found. There should only be on device address in
  352.                     // the connection settings structure when connecting to a session, so just 
  353.                     // pass in the first one.  
  354.                     // The enumeration is automatically cancelled after Connect is called 
  355.                     DPNHANDLE hAsync;
  356.                     hr = g_pDP->Connect( g_pEnumedSessionAppDesc,      // the application desc
  357.                                          g_pEnumedSessionHostAddr,     // address of the host of the session
  358.                                          g_pEnumedSessionDeviceAddr,   // address of the local device used to connect to the host
  359.                                          NULL, NULL,                   // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  360.                                          NULL, 0,                      // user data, user data size
  361.                                          NULL,                         // player context,
  362.                                          NULL, &hAsync,                // async context, async handle,
  363.                                          0 );                          // flags
  364.                     if( FAILED(hr) )
  365.                         return DXTRACE_ERR( TEXT("Connect"), hr );
  366.  
  367.                     // Wait until the MessageHandler sets an event to tell us the 
  368.                     // DPN_MSGID_CONNECT_COMPLETE has been processed.  Then 
  369.                     // m_hrConnectComplete will be valid.
  370.                     WaitForSingleObject( g_hConnectCompleteEvent, INFINITE );
  371.  
  372.                     if( FAILED( g_hrConnectComplete ) )
  373.                     {
  374.                         DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), g_hrConnectComplete );
  375.                         MessageBox( hDlg, TEXT("Unable to join game."),
  376.                                     g_strAppName, MB_OK | MB_ICONERROR );
  377.                         hr = g_hrConnectComplete;
  378.                     }
  379.  
  380.                     if( g_pEnumedSessionAppDesc )
  381.                     {
  382.                         SAFE_DELETE_ARRAY( g_pEnumedSessionAppDesc->pwszSessionName );
  383.                         SAFE_DELETE_ARRAY( g_pEnumedSessionAppDesc );
  384.                     }
  385.                     SAFE_RELEASE( g_pEnumedSessionHostAddr );                    
  386.                     SAFE_RELEASE( g_pEnumedSessionDeviceAddr );
  387.  
  388.                     EndDialog( g_hDlg, 0 );
  389.                 }
  390.             }
  391.             break;
  392.  
  393.         case WM_DESTROY:
  394.         {
  395.             GetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName, MAX_PATH );
  396.             GetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName, MAX_PATH );
  397.             int nIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  398.             SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETLBTEXT, nIndex, (LPARAM) g_strPreferredProvider );
  399.  
  400.             int nCount,i;
  401.             nCount = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCOUNT, 0, 0 );
  402.             for( i=0; i<nCount; i++ )
  403.             {
  404.                 GUID* pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, i, 0 );
  405.                 SAFE_DELETE( pGuid );
  406.             }
  407.  
  408.             nCount = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCOUNT, 0, 0 );
  409.             for( i=0; i<nCount; i++ )
  410.             {
  411.                 GUID* pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, 
  412.                                                            CB_GETITEMDATA, i, 0 );
  413.                 SAFE_DELETE( pGuid );
  414.             }            
  415.             break;
  416.         }
  417.     }
  418.  
  419.     return FALSE; // Didn't handle message
  420. }
  421.  
  422.  
  423.  
  424.  
  425. //-----------------------------------------------------------------------------
  426. // Name: OnInitOverrideDialog
  427. // Desc: 
  428. //-----------------------------------------------------------------------------
  429. HRESULT OnInitOverrideDialog( HWND hDlg )
  430. {
  431.     HRESULT hr;
  432.  
  433.     // Load and set the icon
  434.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  435.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  436.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  437.  
  438.     CheckDlgButton( hDlg, IDC_HOST_SESSION, BST_CHECKED );
  439.  
  440.     SetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName );
  441.     SetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName );
  442.  
  443.     if( FAILED( hr = EnumServiceProviders( hDlg ) ) )
  444.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  445.     
  446.     WSADATA WSAData;
  447.     _tcscpy( g_strLocalIP, TEXT("") );
  448.     if( WSAStartup (MAKEWORD(1,0), &WSAData) == 0) 
  449.     {
  450.         CHAR strLocalHostName[MAX_PATH];
  451.         gethostname( strLocalHostName, MAX_PATH );
  452.         HOSTENT* pHostEnt = gethostbyname( strLocalHostName );
  453.         if( pHostEnt )
  454.         {
  455.             in_addr* pInAddr = (in_addr*) pHostEnt->h_addr_list[0];
  456.             char* strLocalIP = inet_ntoa( *pInAddr );
  457.             if( strLocalIP )
  458.                 DXUtil_ConvertAnsiStringToGeneric( g_strLocalIP, strLocalIP );
  459.         }
  460.  
  461.         WSACleanup();
  462.     }
  463.     SetDlgItemText( hDlg, IDC_LOCAL_IP, g_strLocalIP );
  464.     
  465.     SetupAddressFields( hDlg );
  466.  
  467.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  468.     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  469.     if( pSPGuid != NULL )
  470.     {
  471.         g_pCurSPGuid = pSPGuid;
  472.         EnumAdapters( hDlg, pSPGuid );
  473.     }
  474.  
  475.     return S_OK;
  476. }
  477.  
  478.  
  479.  
  480.  
  481.  
  482. //-----------------------------------------------------------------------------
  483. // Name: SetupAddressFields
  484. // Desc: Based on the SP selected, update the address UI 
  485. //-----------------------------------------------------------------------------
  486. VOID SetupAddressFields( HWND hDlg )
  487. {
  488.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  489.     if( nSPIndex == LB_ERR )
  490.         return;
  491.     GUID* pGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  492.     if( pGuid == NULL )
  493.         return;
  494.  
  495.     BOOL bHosting = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
  496.  
  497.     if( *pGuid == CLSID_DP8SP_TCPIP )
  498.     {
  499.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), TRUE );
  500.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  501.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), TRUE );
  502.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("Port:") );
  503.  
  504.         if( bHosting )
  505.         {
  506.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  507.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  508.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  509.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  510.         }
  511.         else
  512.         {
  513.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
  514.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  515.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
  516.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("IP Address:") );
  517.         }
  518.     }
  519.     else if( *pGuid == CLSID_DP8SP_MODEM )
  520.     {
  521.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
  522.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  523.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
  524.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("Phone Number:") );
  525.  
  526.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
  527.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  528.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
  529.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
  530.     }
  531.     else if( *pGuid == CLSID_DP8SP_IPX )
  532.     {
  533.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  534.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  535.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  536.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  537.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), TRUE );
  538.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  539.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), TRUE );
  540.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("Port:") );
  541.     }
  542.     else 
  543.     {
  544.         // CLSID_DP8SP_SERIAL or unknown so disable all the address lines 
  545.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  546.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  547.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  548.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  549.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
  550.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  551.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
  552.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
  553.     }
  554. }
  555.  
  556.  
  557.  
  558.  
  559. //-----------------------------------------------------------------------------
  560. // Name: EnumServiceProviders()
  561. // Desc: Fills the combobox with service providers
  562. //-----------------------------------------------------------------------------
  563. HRESULT EnumServiceProviders( HWND hDlg )
  564. {
  565.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
  566.     HRESULT hr;
  567.     DWORD   dwItems = 0;
  568.     DWORD   dwSize  = 0;
  569.     int     nIndex;
  570.  
  571.     // Enumerate all DirectPlay service providers, and store them in the listbox
  572.     hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
  573.                                       &dwItems, 0 );
  574.     if( hr != DPNERR_BUFFERTOOSMALL )
  575.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  576.  
  577.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  578.     if( FAILED( hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
  579.                                                   &dwSize, &dwItems, 0 ) ) )
  580.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  581.  
  582.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  583.     for ( DWORD i = 0; i < dwItems; i++ )
  584.     {
  585.         TCHAR strName[MAX_PATH];
  586.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  587.  
  588.         // Found a service provider, so put it in the listbox
  589.         nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_ADDSTRING, 
  590.                                               0, (LPARAM) strName );
  591.  
  592.         // Store pointer to GUID in listbox
  593.         GUID* pGuid = new GUID;
  594.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  595.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETITEMDATA, 
  596.                             nIndex, (LPARAM) pGuid );
  597.  
  598.         pdnSPInfoEnum++;
  599.     }
  600.  
  601.     SAFE_DELETE_ARRAY( pdnSPInfo );
  602.  
  603.     // Try to select the default preferred provider
  604.     nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1,
  605.                                       (LPARAM)g_strPreferredProvider );
  606.     if( nIndex != LB_ERR )
  607.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, nIndex, 0 );
  608.     else
  609.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, 0, 0 );
  610.  
  611.     return S_OK;
  612. }
  613.  
  614.  
  615.  
  616.  
  617. //-----------------------------------------------------------------------------
  618. // Name: EnumAdapters()
  619. // Desc: Fills the combobox with adapters for a specified SP
  620. //-----------------------------------------------------------------------------
  621. HRESULT EnumAdapters( HWND hDlg, GUID* pSPGuid )
  622. {
  623.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
  624.     TCHAR   strName[MAX_PATH];
  625.     HRESULT hr;
  626.     DWORD   dwItems = 0;
  627.     DWORD   dwSize  = 0;
  628.     int     nIndex;
  629.     int     nAllAdaptersIndex = 0;
  630.  
  631.     SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_RESETCONTENT, 0, 0 );
  632.  
  633.     // Enumerate all DirectPlay service providers, and store them in the listbox
  634.     hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo, &dwSize,
  635.                                       &dwItems, 0 );
  636.     if( SUCCEEDED(hr) ) // No adapters found
  637.         return S_OK;
  638.  
  639.     if( hr != DPNERR_BUFFERTOOSMALL )
  640.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  641.  
  642.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  643.     if( FAILED( hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo,
  644.                                                   &dwSize, &dwItems, 0 ) ) )
  645.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  646.  
  647.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  648.     for ( DWORD i = 0; i < dwItems; i++ )
  649.     {
  650.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  651.  
  652.         // Found a service provider, so put it in the listbox
  653.         nIndex = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_ADDSTRING, 
  654.                                           0, (LPARAM) strName );
  655.  
  656.         if( _tcscmp( strName, "All Adapters" ) == 0 )
  657.             nAllAdaptersIndex = nIndex;
  658.  
  659.         // Store pointer to GUID in listbox
  660.         GUID* pGuid = new GUID;
  661.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  662.  
  663.         SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETITEMDATA, 
  664.                             nIndex, (LPARAM) pGuid );
  665.  
  666.         pdnSPInfoEnum++;
  667.     }
  668.  
  669.     SAFE_DELETE_ARRAY( pdnSPInfo );
  670.  
  671.     SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETCURSEL, nAllAdaptersIndex, 0 );
  672.  
  673.     return S_OK;
  674. }
  675.  
  676.  
  677.  
  678.  
  679. //-----------------------------------------------------------------------------
  680. // Name: LaunchMultiplayerGame
  681. // Desc: 
  682. //-----------------------------------------------------------------------------
  683. HRESULT LaunchMultiplayerGame( HWND hDlg ) 
  684. {
  685.     HRESULT hr;
  686.  
  687.     g_bHostPlayer = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
  688.     IDirectPlay8Address* pHostAddress     = NULL;
  689.     IDirectPlay8Address* pDeviceAddress   = NULL;
  690.  
  691.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  692.     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  693.  
  694.     if( !g_bHostPlayer )
  695.     {
  696.         // Create a host address if connecting to a host, 
  697.         // otherwise keep it as NULL
  698.         if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, 
  699.                                            IID_IDirectPlay8Address, (void **) &pHostAddress ) ) )
  700.             return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  701.  
  702.         // Set the SP to pHostAddress
  703.         if( FAILED( hr = pHostAddress->SetSP( pSPGuid ) ) )
  704.             return DXTRACE_ERR( TEXT("SetSP"), hr );
  705.     }
  706.  
  707.     // Create a device address to specify which device we are using 
  708.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, 
  709.                                        IID_IDirectPlay8Address, (void **) &pDeviceAddress ) ) )
  710.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  711.  
  712.     // Set the SP to pDeviceAddress
  713.     if( FAILED( hr = pDeviceAddress->SetSP( pSPGuid ) ) )
  714.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  715.  
  716.     // Add the adapter to pHostAddress
  717.     int nAdapterIndex = (int) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCURSEL, 0, 0 );
  718.     GUID* pAdapterGuid = NULL;
  719.  
  720.     if( nAdapterIndex != CB_ERR )
  721.     {
  722.         GUID* pAdapterGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETITEMDATA, 
  723.                                                          nAdapterIndex, 0 );
  724.         if( FAILED( hr = pDeviceAddress->SetDevice( pAdapterGuid ) ) )
  725.             return DXTRACE_ERR( TEXT("SetDevice"), hr );
  726.     }
  727.  
  728.     if( *pSPGuid == CLSID_DP8SP_TCPIP )
  729.     {
  730.         TCHAR strIP[MAX_PATH];
  731.         TCHAR strPort[MAX_PATH];
  732.  
  733.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strIP, MAX_PATH );
  734.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE2, strPort, MAX_PATH );
  735.  
  736.         if( g_bHostPlayer )
  737.         {
  738.             if( _tcslen( strPort ) > 0 )
  739.             {
  740.                 // Add the port to pDeviceAddress
  741.                 DWORD dwPort = atoi( strPort );
  742.                 if( FAILED( hr = pDeviceAddress->AddComponent( DPNA_KEY_PORT, 
  743.                                                                &dwPort, sizeof(dwPort),
  744.                                                                DPNA_DATATYPE_DWORD ) ) )
  745.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  746.             }
  747.         }
  748.         else
  749.         {
  750.             // Add the IP address to pHostAddress
  751.             if( _tcslen( strIP ) > 0 )
  752.             {
  753.                 WCHAR wstrIP[MAX_PATH];
  754.                 DXUtil_ConvertGenericStringToWide( wstrIP, strIP );
  755.  
  756.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_HOSTNAME, 
  757.                                                              wstrIP, (wcslen(wstrIP)+1)*sizeof(WCHAR), 
  758.                                                              DPNA_DATATYPE_STRING ) ) )
  759.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  760.             }
  761.  
  762.             if( _tcslen( strPort ) > 0 )
  763.             {
  764.                 // Add the port to pHostAddress
  765.                 DWORD dwPort = atoi( strPort );
  766.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PORT, 
  767.                                                              &dwPort, sizeof(dwPort),
  768.                                                              DPNA_DATATYPE_DWORD ) ) )
  769.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  770.             }
  771.         }
  772.     }
  773.     else if( *pSPGuid == CLSID_DP8SP_IPX )
  774.     {
  775.         TCHAR strPort[MAX_PATH];
  776.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE2, strPort, MAX_PATH );
  777.  
  778.         if( g_bHostPlayer )
  779.         {
  780.             if( _tcslen( strPort ) > 0 )
  781.             {
  782.                 // Add the port to pDeviceAddress
  783.                 DWORD dwPort = atoi( strPort );
  784.                 if( FAILED( hr = pDeviceAddress->AddComponent( DPNA_KEY_PORT, 
  785.                                                                &dwPort, sizeof(dwPort),
  786.                                                                DPNA_DATATYPE_DWORD ) ) )
  787.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  788.             }
  789.         }
  790.         else
  791.         {
  792.             if( _tcslen( strPort ) > 0 )
  793.             {
  794.                 // Add the port to pHostAddress
  795.                 DWORD dwPort = atoi( strPort );
  796.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PORT, 
  797.                                                              &dwPort, sizeof(dwPort),
  798.                                                              DPNA_DATATYPE_DWORD ) ) )
  799.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  800.             }
  801.         }
  802.     }
  803.     else if( *pSPGuid == CLSID_DP8SP_MODEM )
  804.     {
  805.         TCHAR strPhone[MAX_PATH];
  806.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strPhone, MAX_PATH );
  807.  
  808.         if( !g_bHostPlayer )
  809.         {
  810.             // Add the phonenumber to pHostAddress
  811.             if( _tcslen( strPhone ) > 0 )
  812.             {
  813.                 WCHAR wstrPhone[MAX_PATH];
  814.                 DXUtil_ConvertGenericStringToWide( wstrPhone, strPhone );
  815.  
  816.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PHONENUMBER, 
  817.                                                              wstrPhone, (wcslen(wstrPhone)+1)*sizeof(WCHAR), 
  818.                                                              DPNA_DATATYPE_STRING ) ) )
  819.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  820.             }
  821.         }
  822.     }
  823.     else if( *pSPGuid == CLSID_DP8SP_SERIAL )
  824.     {
  825.         // This simple client doesn't have UI to query for the various
  826.         // fields needed for the serial.  So we just let DPlay popup a dialog
  827.         // to ask the user which settings are needed.
  828.     }
  829.     else
  830.     {
  831.         // Unknown SP, so leave as is
  832.     }
  833.  
  834.     DPN_APPLICATION_DESC dpnAppDesc;
  835.     ZeroMemory( &dpnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  836.     dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
  837.     dpnAppDesc.guidApplication = g_guidApp;
  838.     dpnAppDesc.guidInstance    = GUID_NULL;
  839.  
  840.     // Set the peer info
  841.     WCHAR wszPeerName[MAX_PATH];
  842.     DXUtil_ConvertGenericStringToWide( wszPeerName, g_strLocalPlayerName );
  843.     DPN_PLAYER_INFO dpPlayerInfo;
  844.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  845.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  846.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  847.     dpPlayerInfo.pwszName = wszPeerName;
  848.  
  849.     // Set the peer info, and use the DPNOP_SYNC since by default this
  850.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  851.     // be set by the time we call Connect() below.
  852.     if( FAILED( hr = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  853.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  854.  
  855.     if( g_bHostPlayer )
  856.     {
  857.         // Set the dpnAppDesc.pwszSessionName
  858.         TCHAR strSessionName[MAX_PATH];
  859.         GetDlgItemText( hDlg, IDC_SESSION_NAME, strSessionName, MAX_PATH );
  860.         if( _tcslen( strSessionName ) == 0 )
  861.         {
  862.             dpnAppDesc.pwszSessionName = NULL;
  863.         }
  864.         else
  865.         {
  866.             WCHAR wstrSessionName[MAX_PATH];
  867.             DXUtil_ConvertGenericStringToWide( wstrSessionName, strSessionName );
  868.             dpnAppDesc.pwszSessionName = new WCHAR[wcslen(wstrSessionName)+1];
  869.             wcscpy( dpnAppDesc.pwszSessionName, wstrSessionName );
  870.         }
  871.  
  872.         // Host a game as described by pSettings
  873.         hr = g_pDP->Host( &dpnAppDesc,          // the application desc
  874.                           &pDeviceAddress,    // array of addresses of the local devices used to connect to the host
  875.                           1,                    // number in array
  876.                           NULL, NULL,           // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  877.                           NULL,                 // player context
  878.                           0 );                 // flags
  879.  
  880.         SAFE_DELETE_ARRAY( dpnAppDesc.pwszSessionName );
  881.         SAFE_RELEASE( pDeviceAddress );
  882.  
  883.         if( FAILED(hr) )
  884.         {
  885.             SAFE_RELEASE( pHostAddress );
  886.             SAFE_RELEASE( pDeviceAddress );
  887.  
  888.             return DXTRACE_ERR( TEXT("Host"), hr );    
  889.         }
  890.  
  891.         EndDialog( g_hDlg, 0 );
  892.     }
  893.     else
  894.     {
  895.         // Query for the enum host timeout for this SP
  896.         DPN_SP_CAPS dpspCaps;
  897.         ZeroMemory( &dpspCaps, sizeof(DPN_SP_CAPS) );
  898.         dpspCaps.dwSize = sizeof(DPN_SP_CAPS);
  899.         if( FAILED( hr = g_pDP->GetSPCaps( pSPGuid, &dpspCaps, 0 ) ) )
  900.             return DXTRACE_ERR( TEXT("GetSPCaps"), hr );
  901.  
  902.         // Set the host expire time to around 3 times 
  903.         // length of the dwDefaultEnumRetryInterval
  904.         DWORD dwEnumHostTimeout = dpspCaps.dwDefaultEnumRetryInterval * 3;
  905.  
  906.         // Enumerate hosts
  907.         DPN_APPLICATION_DESC    dnAppDesc;
  908.         ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  909.         dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  910.         dnAppDesc.guidApplication = g_guidApp;
  911.  
  912.         // Enumerate all the active DirectPlay games on the selected connection
  913.         hr = g_pDP->EnumHosts( &dnAppDesc,                            // application description
  914.                                pHostAddress,                          // host address
  915.                                pDeviceAddress,                        // device address
  916.                                NULL,                                  // pointer to user data
  917.                                0,                                     // user data size
  918.                                0,                                     // retry count (0=default)
  919.                                0,                                     // retry interval (0=default)
  920.                                dwEnumHostTimeout,                     // time out (forever)
  921.                                NULL,                                  // user context
  922.                                &g_hEnumAsyncOp,                       // async handle
  923.                                DPNENUMHOSTS_OKTOQUERYFORADDRESSING      // flags
  924.                                );
  925.         if( FAILED(hr) )
  926.         {
  927.             SAFE_RELEASE( pHostAddress );
  928.             SAFE_RELEASE( pDeviceAddress );
  929.  
  930.             if( hr == DPNERR_ADDRESSING )  // This will be returned if the ip address is invalid
  931.                 return hr;                 // For example, something like "asdf" 
  932.             return DXTRACE_ERR( TEXT("EnumHosts"), hr );
  933.         }
  934.  
  935.         SetTimer( g_hDlg, TIMER_WAIT_HOSTS_RESPONSE, 100, NULL );
  936.     }
  937.  
  938.     // Cleanup the addresses
  939.     SAFE_RELEASE( pHostAddress );
  940.     SAFE_RELEASE( pDeviceAddress );
  941.     
  942.     return S_OK;
  943. }
  944.  
  945.  
  946.  
  947.  
  948. //-----------------------------------------------------------------------------
  949. // Name: GreetingDlgProc()
  950. // Desc: Handles dialog messages
  951. //-----------------------------------------------------------------------------
  952. INT_PTR CALLBACK GreetingDlgProc( HWND hDlg, UINT msg, 
  953.                                   WPARAM wParam, LPARAM lParam )
  954. {
  955.     switch( msg ) 
  956.     {
  957.         case WM_INITDIALOG:
  958.         {
  959.             g_hDlg = hDlg;
  960.  
  961.             // Load and set the icon
  962.             HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  963.             SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  964.             SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  965.  
  966.             if( g_bHostPlayer )
  967.                 SetWindowText( hDlg, TEXT("AddressOverride (Host)") );
  968.             else
  969.                 SetWindowText( hDlg, TEXT("AddressOverride") );
  970.  
  971.             // Display local player's name
  972.             SetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName );
  973.  
  974.             PostMessage( hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  975.             break;
  976.         }
  977.  
  978.         case WM_APP_UPDATE_STATS:
  979.         {
  980.             // Update the number of players in the game
  981.             TCHAR strNumberPlayers[32];
  982.  
  983.             wsprintf( strNumberPlayers, TEXT("%d"), g_lNumberOfActivePlayers );
  984.             SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  985.             break;
  986.         }
  987.  
  988.         case WM_APP_DISPLAY_WAVE:
  989.         {
  990.             HRESULT          hr;
  991.             DPNID            dpnidPlayer = (DWORD)wParam;
  992.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  993.             
  994.             PLAYER_LOCK(); // enter player context CS
  995.  
  996.             // Get the player context accosicated with this DPNID
  997.             hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  998.                                           (LPVOID* const) &pPlayerInfo,
  999.                                           0);
  1000.  
  1001.             PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1002.             PLAYER_UNLOCK(); // leave player context CS
  1003.  
  1004.             if( FAILED(hr) || pPlayerInfo == NULL )
  1005.             {
  1006.                 // The player who sent this may have gone away before this 
  1007.                 // message was handled, so just ignore it
  1008.                 break;
  1009.             }
  1010.             
  1011.             // Make wave message and display it.
  1012.             TCHAR szWaveMessage[MAX_PATH];
  1013.             wsprintf( szWaveMessage, TEXT("%s just waved at you, %s!\r\n"), 
  1014.                       pPlayerInfo->strPlayerName, g_strLocalPlayerName );
  1015.  
  1016.             PLAYER_LOCK();
  1017.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1018.             PLAYER_UNLOCK();
  1019.  
  1020.             AppendTextToEditControl( hDlg, szWaveMessage );
  1021.             break;
  1022.         }
  1023.  
  1024.         case WM_COMMAND:
  1025.         {
  1026.             switch( LOWORD(wParam) )
  1027.             {
  1028.                 case IDC_WAVE:
  1029.                     if( FAILED( g_hrDialog = WaveToAllPlayers() ) )
  1030.                     {
  1031.                         DXTRACE_ERR( TEXT("WaveToAllPlayers"), g_hrDialog );
  1032.                         EndDialog( hDlg, 0 );
  1033.                     }
  1034.  
  1035.                     return TRUE;
  1036.  
  1037.                 case IDCANCEL:
  1038.                     g_hrDialog = S_OK;
  1039.                     EndDialog( hDlg, 0 );
  1040.                     return TRUE;
  1041.             }
  1042.             break;
  1043.         }
  1044.     }
  1045.  
  1046.     return FALSE; // Didn't handle message
  1047. }
  1048.  
  1049.  
  1050.  
  1051.  
  1052. //-----------------------------------------------------------------------------
  1053. // Name: DirectPlayMessageHandler
  1054. // Desc: Handler for DirectPlay messages.  This function is called by
  1055. //       the DirectPlay message handler pool of threads, so be careful of thread
  1056. //       synchronization problems with shared memory
  1057. //-----------------------------------------------------------------------------
  1058. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  1059.                                          DWORD dwMessageId, 
  1060.                                          PVOID pMsgBuffer )
  1061. {
  1062.     // Try not to stay in this message handler for too long, otherwise
  1063.     // there will be a backlog of data.  The best solution is to 
  1064.     // queue data as it comes in, and then handle it on other threads.
  1065.     
  1066.     // This function is called by the DirectPlay message handler pool of 
  1067.     // threads, so be careful of thread synchronization problems with shared memory
  1068.  
  1069.     switch( dwMessageId )
  1070.     {
  1071.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  1072.         {
  1073.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
  1074.             pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
  1075.  
  1076.             // This simple sample only records the 
  1077.             // first enum responce, and connects to that host
  1078.             if( NULL == g_pEnumedSessionHostAddr )
  1079.             {
  1080.                 // Duplicate pEnumHostsResponseMsg->pAddressSender in g_pEnumedSessionHostAddr.
  1081.                 if( pEnumHostsResponseMsg->pAddressSender )
  1082.                     pEnumHostsResponseMsg->pAddressSender->Duplicate( &g_pEnumedSessionHostAddr );
  1083.  
  1084.                 // Duplicate pEnumHostsResponseMsg->pAddressDevice in g_pEnumedSessionDeviceAddr.
  1085.                 if( pEnumHostsResponseMsg->pAddressDevice )
  1086.                     pEnumHostsResponseMsg->pAddressDevice->Duplicate( &g_pEnumedSessionDeviceAddr );
  1087.  
  1088.                 // Copy pEnumHostsResponseMsg->pApplicationDescription to g_pEnumedSessionAppDesc
  1089.                 g_pEnumedSessionAppDesc = new DPN_APPLICATION_DESC;
  1090.                 ZeroMemory( g_pEnumedSessionAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1091.                 memcpy( g_pEnumedSessionAppDesc, pEnumHostsResponseMsg->pApplicationDescription,
  1092.                         sizeof(DPN_APPLICATION_DESC) );
  1093.                 if( pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName )
  1094.                 {
  1095.                     g_pEnumedSessionAppDesc->pwszSessionName = new WCHAR[ wcslen(pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName)+1 ];
  1096.                     wcscpy( g_pEnumedSessionAppDesc->pwszSessionName,
  1097.                             pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName );
  1098.                 }
  1099.  
  1100.                 SetEvent( g_hEnumHostEvent );
  1101.             }
  1102.             break;
  1103.         }
  1104.  
  1105.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  1106.         {
  1107.             PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
  1108.             pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
  1109.  
  1110.             if( pAsyncOpCompleteMsg->hAsyncOp == g_hEnumAsyncOp )
  1111.             {
  1112.                 if( WAIT_TIMEOUT == WaitForSingleObject( g_hEnumHostEvent, 0 ) )
  1113.                 {
  1114.                     MessageBox( g_hDlg, "No session found.", g_strAppName, MB_OK );
  1115.                     SAFE_RELEASE( g_pEnumedSessionDeviceAddr );
  1116.                     KillTimer( g_hDlg, TIMER_WAIT_HOSTS_RESPONSE );
  1117.                     g_hEnumAsyncOp = NULL;
  1118.                 }
  1119.  
  1120.                 g_hEnumHostEvent = NULL;
  1121.             }
  1122.             break;
  1123.         }
  1124.  
  1125.         case DPN_MSGID_CREATE_PLAYER:
  1126.         {
  1127.             HRESULT hr;
  1128.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1129.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  1130.  
  1131.             // Get the peer info and extract its name
  1132.             DWORD dwSize = 0;
  1133.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1134.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1135.                                      pdpPlayerInfo, &dwSize, 0 );
  1136.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  1137.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1138.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1139.             ZeroMemory( pdpPlayerInfo, dwSize );
  1140.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1141.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1142.                                      pdpPlayerInfo, &dwSize, 0 );
  1143.             if( FAILED(hr) )
  1144.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1145.  
  1146.             // Create a new and fill in a APP_PLAYER_INFO
  1147.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1148.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1149.             pPlayerInfo->lRefCount   = 1;
  1150.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1151.  
  1152.             // This stores a extra TCHAR copy of the player name for 
  1153.             // easier access.  This will be redundent copy since DPlay 
  1154.             // also keeps a copy of the player name in GetPeerInfo()
  1155.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1156.                                                pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );
  1157.  
  1158.             if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  1159.                 g_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  1160.  
  1161.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1162.  
  1163.             // Tell DirectPlay to store this pPlayerInfo 
  1164.             // pointer in the pvPlayerContext.
  1165.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1166.  
  1167.             // Update the number of active players, and 
  1168.             // post a message to the dialog thread to update the 
  1169.             // UI.  This keeps the DirectPlay message handler 
  1170.             // from blocking
  1171.             InterlockedIncrement( &g_lNumberOfActivePlayers );
  1172.             if( g_hDlg != NULL )
  1173.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  1174.  
  1175.             break;
  1176.         }
  1177.  
  1178.         case DPN_MSGID_DESTROY_PLAYER:
  1179.         {
  1180.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1181.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1182.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1183.  
  1184.             PLAYER_LOCK();                  // enter player context CS
  1185.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1186.             PLAYER_UNLOCK();                // leave player context CS
  1187.  
  1188.             // Update the number of active players, and 
  1189.             // post a message to the dialog thread to update the 
  1190.             // UI.  This keeps the DirectPlay message handler 
  1191.             // from blocking
  1192.             InterlockedDecrement( &g_lNumberOfActivePlayers );
  1193.             if( g_hDlg != NULL )
  1194.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  1195.  
  1196.             break;
  1197.         }
  1198.  
  1199.         case DPN_MSGID_HOST_MIGRATE:
  1200.         {
  1201.             PDPNMSG_HOST_MIGRATE pHostMigrateMsg;
  1202.             pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer;
  1203.  
  1204.             // Check to see if we are the new host
  1205.             if( pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer )
  1206.                 SetWindowText( g_hDlg, TEXT("AddressOverride (Host)") );
  1207.             break;
  1208.         }
  1209.  
  1210.         case DPN_MSGID_TERMINATE_SESSION:
  1211.         {
  1212.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1213.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1214.  
  1215.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1216.             EndDialog( g_hDlg, 0 );
  1217.             break;
  1218.         }
  1219.  
  1220.         case DPN_MSGID_RECEIVE:
  1221.         {
  1222.             PDPNMSG_RECEIVE pReceiveMsg;
  1223.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1224.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1225.  
  1226.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1227.             if( pMsg->dwType == GAME_MSGID_WAVE )
  1228.             {
  1229.                 // This message is sent when a player has waved to us, so 
  1230.                 // post a message to the dialog thread to update the UI.  
  1231.                 // This keeps the DirectPlay threads from blocking, and also
  1232.                 // serializes the recieves since DirectPlayMessageHandler can
  1233.                 // be called simultaneously from a pool of DirectPlay threads.
  1234.                 PostMessage( g_hDlg, WM_APP_DISPLAY_WAVE, pPlayerInfo->dpnidPlayer, 0 );
  1235.             }
  1236.             break;
  1237.         }
  1238.  
  1239.         case DPN_MSGID_CONNECT_COMPLETE:
  1240.         {
  1241.             PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
  1242.             pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
  1243.  
  1244.             // Set m_hrConnectComplete, then set an event letting 
  1245.             // everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
  1246.             // has been handled
  1247.             g_hrConnectComplete = pConnectCompleteMsg->hResultCode;
  1248.             SetEvent( g_hConnectCompleteEvent );
  1249.             break;
  1250.         }
  1251.     }
  1252.  
  1253.     return S_OK;
  1254. }
  1255.  
  1256.  
  1257.  
  1258.  
  1259. //-----------------------------------------------------------------------------
  1260. // Name: WaveToAllPlayers()
  1261. // Desc: Send a app-defined "wave" DirectPlay message to all connected players
  1262. //-----------------------------------------------------------------------------
  1263. HRESULT WaveToAllPlayers()
  1264. {
  1265.     // This is called by the dialog UI thread.  This will send a message to all
  1266.     // the players or inform the player that there is no one to wave at.
  1267.     if( g_lNumberOfActivePlayers == 1 )
  1268.     {
  1269.         MessageBox( NULL, TEXT("No one is around to wave at! :("), 
  1270.                     TEXT("AddressOverride"), MB_OK );
  1271.     }
  1272.     else
  1273.     {
  1274.         // Send a message to all of the players
  1275.         GAMEMSG_GENERIC msgWave;
  1276.         msgWave.dwType = GAME_MSGID_WAVE;
  1277.  
  1278.         DPN_BUFFER_DESC bufferDesc;
  1279.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_GENERIC);
  1280.         bufferDesc.pBufferData  = (BYTE*) &msgWave;
  1281.  
  1282.         // DirectPlay will tell via the message handler 
  1283.         // if there are any severe errors, so ignore any errors 
  1284.         DPNHANDLE hAsync;
  1285.         g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1286.                        0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  1287.     }
  1288.  
  1289.     return S_OK;
  1290. }
  1291.  
  1292.  
  1293.  
  1294.  
  1295. //-----------------------------------------------------------------------------
  1296. // Name: AppendTextToEditControl()
  1297. // Desc: Appends a string of text to the edit control
  1298. //-----------------------------------------------------------------------------
  1299. VOID AppendTextToEditControl( HWND hDlg, TCHAR* strNewLogLine )
  1300. {
  1301.     static TCHAR strText[1024*10];
  1302.  
  1303.     HWND hEdit = GetDlgItem( hDlg, IDC_LOG_EDIT );
  1304.     SendMessage( hEdit, WM_SETREDRAW, FALSE, 0 );
  1305.     GetWindowText( hEdit, strText, 1024*9 );
  1306.  
  1307.     _tcscat( strText, strNewLogLine );
  1308.  
  1309.     int nSecondLine = 0;
  1310.     if( SendMessage( hEdit, EM_GETLINECOUNT, 0, 0 ) > 9 )
  1311.         nSecondLine = (int)SendMessage( hEdit, EM_LINEINDEX, 1, 0 );
  1312.  
  1313.     SetWindowText( hEdit, &strText[nSecondLine] );
  1314.  
  1315.     SendMessage( hEdit, WM_SETREDRAW, TRUE, 0 );
  1316.     InvalidateRect( hEdit, NULL, TRUE );
  1317.     UpdateWindow( hEdit );
  1318. }
  1319.  
  1320.  
  1321.  
  1322.