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

  1. //-----------------------------------------------------------------------------
  2. // File: VoiceGroup.cpp
  3. //
  4. // Desc: The main file for VoiceGroup that shows how use DirectPlay along 
  5. //       with DirectPlayVoice to allow talking in to a specific group
  6. //       of players.
  7. //
  8. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <windows.h>
  12. #include <basetsd.h>
  13. #include <stdio.h>
  14. #include <dxerr8.h>
  15. #include <dplay8.h>
  16. #include <dplobby8.h>
  17. #include <dvoice.h>
  18. #include <commctrl.h>
  19. #include <cguid.h>
  20. #include "NetConnect.h"
  21. #include "NetVoice.h"
  22. #include "DXUtil.h"
  23. #include "resource.h"
  24.  
  25.  
  26.  
  27.  
  28. //-----------------------------------------------------------------------------
  29. // Player context locking defines
  30. //-----------------------------------------------------------------------------
  31. CRITICAL_SECTION g_csPlayerContext;
  32. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  33. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  34. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  35. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  36.  
  37.  
  38. //-----------------------------------------------------------------------------
  39. // Defines, and constants
  40. //-----------------------------------------------------------------------------
  41. #define DPLAY_SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  42. #define MAX_GROUPS              5
  43. #define MAX_PLAYER_NAME         14
  44. #define WM_APP_DISPLAY_PLAYERS  (WM_APP + 0)
  45.  
  46. // This GUID allows DirectPlay to find other instances of the same game on
  47. // the network.  So it must be unique for every game, and the same for 
  48. // every instance of that game.  // {9F2DA206-D197-4871-AD1D-D12F59058B5B}
  49. GUID g_guidApp = { 0x9f2da206, 0xd197, 0x4871, { 0xad, 0x1d, 0xd1, 0x2f, 0x59, 0x5, 0x8b, 0x5b } };
  50.  
  51. struct PLAYER_STATE
  52. {
  53.     DWORD        dwGroup;                          // Group # that player joined in
  54.     DWORD        dwTarget;                         // Group # that player is targeting 
  55. };
  56.  
  57. struct APP_PLAYER_INFO
  58. {
  59.     LONG         lRefCount;                        // Ref count so we can cleanup when all threads 
  60.                                                    // are done w/ this object
  61.     DPNID        dpnidPlayer;                      // dpnid of the player
  62.     BOOL         bTalking;                         // Is the player talking
  63.     BOOL         bHalfDuplex;                      // If true, then player cannot talk
  64.     PLAYER_STATE ps;                               // State of player
  65.     TCHAR        strPlayerName[MAX_PLAYER_NAME];   // Player name
  66. };
  67.  
  68.  
  69.  
  70.  
  71. //-----------------------------------------------------------------------------
  72. // App specific DirectPlay messages and structures 
  73. //-----------------------------------------------------------------------------
  74. #define GAME_MSGID_PLAYERSTATECHANGE   1
  75.  
  76. // Change compiler pack alignment to be BYTE aligned, and pop the current value
  77. #pragma pack( push, 1 )
  78.  
  79. struct GAMEMSG_GENERIC
  80. {
  81.     DWORD dwType;
  82. };
  83.  
  84. struct GAMEMSG_PLAYERSTATECHANGE : public GAMEMSG_GENERIC
  85. {
  86.     PLAYER_STATE ps;
  87. };
  88.  
  89. // Pop the old pack alignment
  90. #pragma pack( pop )
  91.  
  92.  
  93.  
  94. //-----------------------------------------------------------------------------
  95. // Global variables
  96. //-----------------------------------------------------------------------------
  97. IDirectPlay8Peer*  g_pDP                         = NULL;    // DirectPlay peer object
  98. CNetConnectWizard* g_pNetConnectWizard           = NULL;    // Connection wizard
  99. CNetVoice*         g_pNetVoice                   = NULL;    // DirectPlay voice helper class
  100. IDirectPlay8LobbiedApplication* g_pLobbiedApp    = NULL;    // DirectPlay lobbied app 
  101. BOOL               g_bWasLobbyLaunched           = FALSE;   // TRUE if lobby launched
  102. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  103. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  104. TCHAR              g_strAppName[256]             = TEXT("VoiceGroup");
  105. APP_PLAYER_INFO*   g_pPlayerLocal                = NULL;    // APP_PLAYER_INFO* of local player
  106. BOOL               g_bVoiceSessionInProgress     = FALSE;   // True if voice has been init'ed
  107. DPNID*             g_pPlayers                    = NULL;    // Array of DPNIDs
  108. DWORD              g_dwPlayersArraySize          = 0;       // Size of g_pPlayers
  109. HRESULT            g_hrDialog;                              // Exit code for app 
  110. TCHAR              g_strLocalPlayerName[MAX_PATH];          // Local player name
  111. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  112. TCHAR              g_strPreferredProvider[MAX_PATH];        // Provider string
  113. BOOL               g_bHostPlayer                 = FALSE;   // TRUE if local player is host
  114. DPNID              g_LocalPlayerDPNID            = 0;       // DPNID of local player
  115. DPNID              g_LocalGroupDPNID             = 0;       // DPNID of the group of the local player
  116. GUID               g_guidDVSessionCT;                       // GUID for choosen voice compression
  117. DVCLIENTCONFIG     g_dvClientConfig;                        // Voice client config
  118.  
  119.  
  120.  
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Function-prototypes
  124. //-----------------------------------------------------------------------------
  125. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  126. HRESULT          OnInitDialog( HWND hDlg );
  127. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  128. HRESULT WINAPI   DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  129. HRESULT WINAPI   DirectPlayVoiceClientMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  130. HRESULT WINAPI   DirectPlayVoiceServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  131. void             SetPlayerTalking( APP_PLAYER_INFO *pPlayerInfo, BOOL bTalking );
  132. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  133. HRESULT          VoiceConfigEnumCompressionCodecs( HWND hDlg );
  134. VOID             VoiceConfigDlgOnOK( HWND hDlg );
  135. HRESULT          InitDirectPlay();
  136. HRESULT          DisplayPlayersInChat( HWND hDlg );
  137. HRESULT          SendLocalStateToAll( HWND hDlg );
  138. HRESULT          SetGroupAndTarget();
  139.  
  140.  
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: WinMain()
  145. // Desc: Entry point for the application.  Since we use a simple dialog for 
  146. //       user interaction we don't need to pump messages.
  147. //-----------------------------------------------------------------------------
  148. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  149.                       INT nCmdShow )
  150. {
  151.     HRESULT hr;
  152.     HKEY    hDPlaySampleRegKey;
  153.     BOOL    bConnectSuccess = FALSE;
  154.  
  155.     g_hInst = hInst;
  156.     InitializeCriticalSection( &g_csPlayerContext );
  157.  
  158.     // Init player ID array 
  159.     g_dwPlayersArraySize = 10;
  160.     g_pPlayers = (DPNID*) malloc( sizeof(DPNID)*g_dwPlayersArraySize );
  161.  
  162.     // Read persistent state information from registry
  163.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  164.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  165.                     &hDPlaySampleRegKey, NULL );
  166.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  167.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  168.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  169.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  170.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  171.                              g_strPreferredProvider, MAX_PATH, TEXT("DirectPlay8 TCP/IP Service Provider") );
  172.  
  173.     InitCommonControls();
  174.  
  175.     // Init COM so we can use CoCreateInstance
  176.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  177.  
  178.     // Create helper class
  179.     g_pNetConnectWizard = new CNetConnectWizard( hInst, NULL, g_strAppName, &g_guidApp );
  180.     g_pNetVoice         = new CNetVoice( DirectPlayVoiceClientMessageHandler, DirectPlayVoiceServerMessageHandler );
  181.  
  182.     if( FAILED( hr = InitDirectPlay() ) )
  183.     {
  184.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  185.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  186.                     TEXT("The sample will now quit."),
  187.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  188.         return FALSE;
  189.     }
  190.  
  191.     // Check if we were launched from a lobby client
  192.     if( g_bWasLobbyLaunched && g_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  193.     {
  194.         // If were lobby launched then DPL_MSGID_CONNECT has already been
  195.         // handled, so we can just tell the wizard to connect to the lobby
  196.         // that has sent us a DPL_MSGID_CONNECT msg.
  197.         if( FAILED( hr = g_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  198.         {
  199.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  200.             MessageBox( NULL, TEXT("Failed to connect using lobby settings. ")
  201.                         TEXT("The sample will now quit."),
  202.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  203.  
  204.             bConnectSuccess = FALSE;
  205.         }
  206.         else
  207.         {
  208.             // Read information from g_pNetConnectWizard
  209.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  210.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  211.  
  212.             bConnectSuccess = TRUE; 
  213.         }
  214.     }
  215.     else
  216.     {
  217.         // If not lobby launched, prompt the user about the network 
  218.         // connection and which session they would like to join or 
  219.         // if they want to create a new one.
  220.  
  221.         // Setup connection wizard
  222.         g_pNetConnectWizard->SetPlayerName( g_strLocalPlayerName );
  223.         g_pNetConnectWizard->SetSessionName( g_strSessionName );
  224.         g_pNetConnectWizard->SetPreferredProvider( g_strPreferredProvider );
  225.  
  226.         // Do the connection wizard
  227.         hr = g_pNetConnectWizard->DoConnectWizard( FALSE );        
  228.         if( FAILED( hr ) ) 
  229.         {
  230.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  231.             MessageBox( NULL, TEXT("Multiplayer connect failed. ")  
  232.                         TEXT("The sample will now quit."),
  233.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  234.             bConnectSuccess = FALSE;
  235.         } 
  236.         else if( hr == NCW_S_QUIT ) 
  237.         {
  238.             // The user canceled the Multiplayer connect, so quit 
  239.             bConnectSuccess = FALSE;
  240.         }
  241.         else
  242.         {
  243.             bConnectSuccess = TRUE; 
  244.  
  245.             // Read information from g_pNetConnectWizard
  246.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  247.             _tcscpy( g_strSessionName, g_pNetConnectWizard->GetSessionName() );
  248.             _tcscpy( g_strPreferredProvider, g_pNetConnectWizard->GetPreferredProvider() );
  249.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  250.  
  251.             // Write information to the registry
  252.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  253.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  254.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  255.         }
  256.     }
  257.  
  258.     if( bConnectSuccess )
  259.     {
  260.         // Set default DirectPlayVoice setup options
  261.         ZeroMemory( &g_dvClientConfig, sizeof(g_dvClientConfig) );
  262.         g_dvClientConfig.dwSize                 = sizeof(g_dvClientConfig);
  263.         g_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  264.                                                   DVCLIENTCONFIG_AUTORECORDVOLUME;
  265.         g_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  266.         g_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  267.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  268.         g_dvClientConfig.dwThreshold          = DVTHRESHOLD_UNUSED;
  269.         g_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  270.         g_dvClientConfig.dwNotifyPeriod         = 0;
  271.  
  272.         g_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  273.  
  274.         // Ask the user for DirectPlayVoice setup params
  275.         DWORD dwResult = (DWORD)DialogBox( hInst, MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  276.                                            NULL, (DLGPROC) VoiceConfigDlgProc );
  277.         if( dwResult != IDCANCEL )
  278.             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  279.     }
  280.  
  281.     if( bConnectSuccess )
  282.     {
  283.         // App is now connected via DirectPlay, so start the game.  
  284.  
  285.         // For this sample, we just start a simple dialog box game.
  286.         g_hrDialog = S_OK;
  287.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, (DLGPROC) VoiceDlgProc );
  288.  
  289.         if( FAILED( g_hrDialog ) )
  290.         {
  291.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  292.             {
  293.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  294.                             TEXT("The sample will now quit."),
  295.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  296.             }
  297.             else
  298.             {
  299.                 DXTRACE_ERR( TEXT("DialogBox"), hr );
  300.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  301.                             TEXT("The sample will now quit."),
  302.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  303.             }
  304.         }
  305.     }
  306.     
  307.     // Cleanup player ID array 
  308.     free( g_pPlayers );
  309.  
  310.     // Disconnect from the DirectPlayVoice session, 
  311.     // and destory it if we are the host player.
  312.     SAFE_DELETE( g_pNetVoice ); 
  313.  
  314.     // Cleanup DirectPlay and helper classes
  315.     g_pNetConnectWizard->Shutdown();
  316.  
  317.     if( g_pDP )
  318.     {
  319.         g_pDP->Close(0);
  320.         SAFE_RELEASE( g_pDP );
  321.     }
  322.  
  323.     if( g_pLobbiedApp )
  324.     {
  325.         g_pLobbiedApp->Close( 0 );
  326.         SAFE_RELEASE( g_pLobbiedApp );
  327.     }    
  328.  
  329.     // Don't delete the wizard until we know that 
  330.     // DirectPlay is out of its message handlers.
  331.     // This will be true after Close() has been called. 
  332.     SAFE_DELETE( g_pNetConnectWizard );
  333.  
  334.     RegCloseKey( hDPlaySampleRegKey );
  335.     DeleteCriticalSection( &g_csPlayerContext );
  336.     CoUninitialize();
  337.  
  338.     return TRUE;
  339. }
  340.  
  341.  
  342.  
  343.  
  344. //-----------------------------------------------------------------------------
  345. // Name: InitDirectPlay()
  346. // Desc: 
  347. //-----------------------------------------------------------------------------
  348. HRESULT InitDirectPlay()
  349. {
  350.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  351.     HRESULT hr;
  352.  
  353.     // Create IDirectPlay8Peer
  354.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  355.                                        CLSCTX_INPROC_SERVER,
  356.                                        IID_IDirectPlay8Peer, 
  357.                                        (LPVOID*) &g_pDP ) ) )
  358.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  359.  
  360.     // Create IDirectPlay8LobbiedApplication
  361.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  362.                                        CLSCTX_INPROC_SERVER,
  363.                                        IID_IDirectPlay8LobbiedApplication, 
  364.                                        (LPVOID*) &g_pLobbiedApp ) ) )
  365.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  366.  
  367.     // Init the helper class, now that g_pDP and g_pLobbiedApp are valid
  368.     g_pNetConnectWizard->Init( g_pDP, g_pLobbiedApp );
  369.  
  370.     // Init IDirectPlay8Peer
  371.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  372.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  373.  
  374.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  375.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  376.     // so be prepared ahead of time.
  377.     if( FAILED( hr = g_pLobbiedApp->Initialize( NULL, DirectPlayLobbyMessageHandler, 
  378.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  379.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  380.  
  381.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connnection
  382.     // if we have been lobby launced.  Initialize is guanteeded to return after 
  383.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  384.     // multiple lobby connections, we do not need to remember the lobby connection
  385.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  386.     g_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  387.  
  388.     return S_OK;
  389. }
  390.  
  391.  
  392.  
  393.  
  394. //-----------------------------------------------------------------------------
  395. // Name: VoiceDlgProc()
  396. // Desc: Handles dialog messages
  397. //-----------------------------------------------------------------------------
  398. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  399. {
  400.     switch( msg ) 
  401.     {
  402.         case WM_INITDIALOG:
  403.             {
  404.                 g_hDlg = hDlg;
  405.  
  406.                 if( FAILED( g_hrDialog = g_pNetVoice->Init( hDlg, g_bHostPlayer, TRUE,
  407.                                                             g_pDP, DVSESSIONTYPE_PEER, 
  408.                                                             &g_guidDVSessionCT, &g_dvClientConfig ) ) )
  409.                 {
  410.                     if( g_hrDialog == DVERR_USERBACK )
  411.                     {
  412.                         MessageBox( hDlg, TEXT("The user backed out of the wizard.  ")
  413.                                     TEXT("This simple sample does not handle this case, so ")
  414.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  415.                         g_hrDialog = S_OK;
  416.                     }
  417.  
  418.                     if( g_hrDialog == DVERR_USERCANCEL )
  419.                     {
  420.                         MessageBox( hDlg, TEXT("The user canceled the wizard. ")
  421.                                     TEXT("This simple sample does not handle this case, so ")
  422.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  423.                         g_hrDialog = S_OK;
  424.                     }
  425.  
  426.                     if( g_hrDialog == DVERR_ALREADYPENDING )
  427.                     {
  428.                         MessageBox( hDlg, TEXT("Another instance of the Voice Setup Wizard is already running. ")
  429.                                     TEXT("This simple sample does not handle this case, so ")
  430.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  431.                         g_hrDialog = S_OK;
  432.                     }
  433.  
  434.                     if( FAILED(g_hrDialog) )
  435.                         DXTRACE_ERR( TEXT("Init"), g_hrDialog );
  436.  
  437.                     EndDialog( hDlg, 0 );
  438.                     break;
  439.                 }
  440.  
  441.                 if( g_pNetVoice->IsHalfDuplex() ) 
  442.                 {
  443.                     MessageBox( hDlg, TEXT("You are running in half duplex mode. In half duplex mode no recording takes place."), 
  444.                                 TEXT("DirectPlay Sample"), MB_OK );
  445.                 }
  446.  
  447.                 g_bVoiceSessionInProgress = TRUE;
  448.  
  449.                 if( FAILED( g_hrDialog = OnInitDialog( hDlg ) ) )
  450.                 {
  451.                     DXTRACE_ERR( TEXT("OnInitDialog"), g_hrDialog );
  452.                     EndDialog( hDlg, 0 );
  453.                     break;
  454.                 }
  455.             }
  456.             break;
  457.  
  458.         case WM_COMMAND:
  459.             switch( LOWORD(wParam) )
  460.             {
  461.                 case IDC_SETUP:
  462.                     {
  463.                         // Ask the user for DirectPlayVoice setup params
  464.                         DWORD dwResult = (DWORD)DialogBox( g_hInst, 
  465.                                                            MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  466.                                                            hDlg, (DLGPROC) VoiceConfigDlgProc );
  467.                         if( dwResult != IDCANCEL )
  468.                             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  469.                     }
  470.                     return TRUE;
  471.  
  472.                 case IDC_CYCLEGROUP:
  473.                     {
  474.                         if( g_pPlayerLocal )
  475.                         {
  476.                             g_pPlayerLocal->ps.dwGroup++;
  477.                             g_pPlayerLocal->ps.dwGroup %= MAX_GROUPS + 1;
  478.                         }
  479.  
  480.                         if( FAILED( g_hrDialog = SetGroupAndTarget() ) )
  481.                         {
  482.                             DXTRACE_ERR( TEXT("SetGroupAndTarget"), g_hrDialog );
  483.                             EndDialog( hDlg, 0 );
  484.                             break;
  485.                         }
  486.  
  487.                         if( FAILED( g_hrDialog = SendLocalStateToAll( hDlg ) ) )
  488.                         {
  489.                             DXTRACE_ERR( TEXT("SendLocalStateToAll"), g_hrDialog );
  490.                             EndDialog( hDlg, 0 );
  491.                             break;
  492.                         }
  493.  
  494.                         // Update the listbox 
  495.                         PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  496.                     }
  497.                     break;
  498.  
  499.                 case IDC_CYCLETARGET:
  500.                     {
  501.                         if( g_pPlayerLocal )
  502.                         {
  503.                             g_pPlayerLocal->ps.dwTarget++;
  504.                             g_pPlayerLocal->ps.dwTarget %= MAX_GROUPS + 1;
  505.                         }
  506.  
  507.                         if( FAILED( g_hrDialog = SetGroupAndTarget() ) )
  508.                         {
  509.                             DXTRACE_ERR( TEXT("SetGroupAndTarget"), g_hrDialog );
  510.                             EndDialog( hDlg, 0 );
  511.                             break;
  512.                         }
  513.  
  514.                         if( FAILED( g_hrDialog = SendLocalStateToAll( hDlg ) ) )
  515.                         {
  516.                             DXTRACE_ERR( TEXT("SendLocalStateToAll"), g_hrDialog );
  517.                             EndDialog( hDlg, 0 );
  518.                             break;
  519.                         }
  520.  
  521.                         // Update the listbox 
  522.                         PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  523.                     }
  524.                     break;
  525.  
  526.                 case IDCANCEL:
  527.                     g_hrDialog = S_OK;
  528.                     EndDialog( hDlg, 0 );
  529.                     return TRUE;
  530.             }
  531.             break;
  532.  
  533.         case WM_APP_DISPLAY_PLAYERS:
  534.         {
  535.             DisplayPlayersInChat( hDlg );
  536.             break;
  537.         }
  538.  
  539.         case WM_TIMER:
  540.         {
  541.             DWORD            dwNumPlayers;
  542.             DWORD            iIndex;
  543.             LVITEM           lvItem;
  544.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  545.             HWND             hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  546.  
  547.             dwNumPlayers = ListView_GetItemCount( hListView );
  548.  
  549.             // Now that they are added and the listview sorted them by name,
  550.             // run through them all caching the listview index with its dpnid
  551.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  552.             {
  553.                 HRESULT hr;
  554.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  555.                 DPNID dpnidPlayer;
  556.  
  557.                 lvItem.mask  = LVIF_PARAM;
  558.                 lvItem.iItem = iIndex;
  559.                 ListView_GetItem( hListView, &lvItem );
  560.  
  561.                 dpnidPlayer = (DPNID) lvItem.lParam;
  562.  
  563.                 PLAYER_LOCK(); // enter player context CS
  564.  
  565.                 // Get the player context accosicated with this DPNID
  566.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  567.                                               (LPVOID* const) &pPlayerInfo,
  568.                                               0);
  569.  
  570.  
  571.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  572.                 PLAYER_UNLOCK(); // leave player context CS
  573.  
  574.                 if( FAILED(hr) || pPlayerInfo == NULL )
  575.                 {
  576.                     // The player who sent this may have gone away before this 
  577.                     // message was handled, so just ignore it
  578.                     continue;
  579.                 }
  580.  
  581.                 TCHAR strStatus[255];
  582.  
  583.                 if( pPlayerInfo->bHalfDuplex )
  584.                 {
  585.                     _tcscpy( strStatus, TEXT("Can't talk") );
  586.                 }
  587.                 else
  588.                 {
  589.                     if( pPlayerInfo->bTalking )
  590.                         _tcscpy( strStatus, TEXT("Talking") );
  591.                     else
  592.                         _tcscpy( strStatus, TEXT("Silent") );
  593.                 }
  594.  
  595.                 lvItem.iItem      = iIndex;
  596.                 lvItem.iSubItem   = 1;
  597.                 lvItem.mask       = LVIF_TEXT;
  598.                 lvItem.pszText    = strStatus;
  599.  
  600.                 PLAYER_LOCK();
  601.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  602.                 PLAYER_UNLOCK();
  603.  
  604.                 SendMessage( hListView, LVM_SETITEM, 0, (LPARAM) &lvItem );
  605.             }
  606.             break;
  607.         }
  608.     }
  609.  
  610.     return FALSE; // Didn't handle message
  611. }
  612.  
  613.  
  614.  
  615.  
  616. //-----------------------------------------------------------------------------
  617. // Name: OnInitDialog()
  618. // Desc: Inits the dialog 
  619. //-----------------------------------------------------------------------------
  620. HRESULT OnInitDialog( HWND hDlg )
  621. {
  622.     HRESULT  hr;
  623.     LVCOLUMN column;
  624.     RECT     rctListView;
  625.     TCHAR    strHeader[255];
  626.     DWORD    dwVertScrollBar;
  627.     DWORD    dwListViewWidth;
  628.  
  629.     // Load and set the icon
  630.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  631.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  632.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  633.  
  634.     if( g_bHostPlayer )
  635.         SetWindowText( hDlg, TEXT("VoiceGroup (Session Host)") );
  636.     else
  637.         SetWindowText( hDlg, TEXT("VoiceGroup (Session Client)") );
  638.  
  639.     SetDlgItemText( hDlg, IDC_GROUP_TEXT, TEXT("Unassigned") );
  640.     SetDlgItemText( hDlg, IDC_TARGET_TEXT, TEXT("Everyone") );
  641.  
  642.     // Setup the listview
  643.     HWND hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  644.  
  645.     dwVertScrollBar = GetSystemMetrics( SM_CXVSCROLL );  
  646.     GetClientRect( hListView, &rctListView );
  647.     dwListViewWidth = rctListView.right - dwVertScrollBar;
  648.     column.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  649.     column.fmt      = LVCFMT_LEFT;
  650.     column.iSubItem = -1;
  651.  
  652.     // Insert the Name column
  653.     _tcscpy( strHeader, TEXT("Name") );
  654.     column.cx         = dwListViewWidth * 8 / 21;
  655.     column.pszText    = strHeader;
  656.     column.cchTextMax = _tcslen( strHeader );
  657.     ListView_InsertColumn( hListView, 0, &column );
  658.  
  659.     // Insert the Status column
  660.     _tcscpy( strHeader, TEXT("Status") );
  661.     column.cx         = dwListViewWidth * 4 / 21;
  662.     column.pszText    = strHeader;
  663.     column.cchTextMax = _tcslen( strHeader );
  664.     ListView_InsertColumn( hListView, 1, &column );
  665.  
  666.     // Insert the Group column
  667.     _tcscpy( strHeader, TEXT("Group") );
  668.     column.cx         = dwListViewWidth * 5 / 21;
  669.     column.pszText    = strHeader;
  670.     column.cchTextMax = _tcslen( strHeader );
  671.     ListView_InsertColumn( hListView, 2, &column );
  672.  
  673.     // Insert the Target column
  674.     _tcscpy( strHeader, TEXT("Target") );
  675.     column.cx         = dwListViewWidth * 4 / 21;
  676.     column.pszText    = strHeader;
  677.     column.cchTextMax = _tcslen( strHeader );
  678.     ListView_InsertColumn( hListView, 3, &column );
  679.  
  680.     if( FAILED( hr = SetGroupAndTarget() ) )
  681.         return DXTRACE_ERR( TEXT("SetGroupAndTarget"), hr );
  682.     if( FAILED( hr = SendLocalStateToAll( hDlg ) ) )
  683.         return DXTRACE_ERR( TEXT("SendLocalStateToAll"), hr );
  684.  
  685.     // Update the listbox 
  686.     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  687.  
  688.     // Make a timer to update the listbox 
  689.     // 'Status' column every so often 
  690.     SetTimer( hDlg, 0, 250, NULL );
  691.  
  692.     // Create the groups if we are the host player
  693.     if( g_bHostPlayer )
  694.     {
  695.         DWORD dwIndex;
  696.  
  697.         for( dwIndex = 1; dwIndex < MAX_GROUPS + 1; dwIndex++ )
  698.         {
  699.             DPN_GROUP_INFO dpGroupInfo;
  700.             DWORD* pdwData = new DWORD;
  701.             *pdwData = dwIndex;
  702.             ZeroMemory( &dpGroupInfo, sizeof(DPN_GROUP_INFO) );
  703.             dpGroupInfo.dwSize = sizeof( DPN_GROUP_INFO );
  704.             dpGroupInfo.dwInfoFlags = DPNINFO_DATA;
  705.             dpGroupInfo.pvData = pdwData;
  706.             dpGroupInfo.dwDataSize = sizeof(DWORD);
  707.  
  708.             DPNHANDLE hAsync;
  709.             hr = g_pDP->CreateGroup( &dpGroupInfo, NULL,
  710.                                      NULL, &hAsync, 0 );
  711.             if( FAILED( hr ) ) 
  712.                 return DXTRACE_ERR( TEXT("CreateGroup"), hr );
  713.         }
  714.     }
  715.  
  716.     return S_OK;
  717. }
  718.  
  719.  
  720.  
  721.  
  722. //-----------------------------------------------------------------------------
  723. // Name: DisplayPlayersInChat()
  724. // Desc: Displays the active players in the listview
  725. //-----------------------------------------------------------------------------
  726. HRESULT DisplayPlayersInChat( HWND hDlg )
  727. {
  728.     if( hDlg == NULL )
  729.         return S_OK;
  730.  
  731.     HRESULT hr;
  732.     LVITEM  lvItem;
  733.     HWND    hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  734.     TCHAR   strText[32];
  735.     TCHAR   strNumberPlayers[32];
  736.     DWORD   dwNumPlayers;
  737.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  738.  
  739.     // Remove all the players and re-add them in the player enum callback
  740.     ListView_DeleteAllItems( hListView );
  741.  
  742.     do
  743.     {
  744.         // Enum all players in the player ID array
  745.         dwNumPlayers = g_dwPlayersArraySize;
  746.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  747.         if( SUCCEEDED(hr) )
  748.             break;
  749.  
  750.         if( hr == DPNERR_BUFFERTOOSMALL )
  751.         {
  752.             // Resize player pointer array     
  753.             g_dwPlayersArraySize += 10;
  754.             g_pPlayers = (DPNID*) realloc( g_pPlayers, sizeof(DPNID)*g_dwPlayersArraySize );
  755.         }
  756.     } 
  757.     while( hr == DPNERR_BUFFERTOOSMALL );
  758.     if( FAILED(hr) )
  759.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  760.  
  761.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  762.     {
  763.         PLAYER_LOCK(); // enter player context CS
  764.  
  765.         do
  766.         {
  767.             // Get the player context accosicated with this DPNID
  768.             // Call GetPlayerContext() until it returns something other than DPNERR_NOTREADY
  769.             // DPNERR_NOTREADY will be returned if the callback thread has not 
  770.             // yet returned from DPN_MSGID_CREATE_PLAYER, which sets the player's context
  771.             hr = g_pDP->GetPlayerContext( g_pPlayers[i], 
  772.                                           (LPVOID* const) &pPlayerInfo,
  773.                                           0);
  774.         } 
  775.         while( hr == DPNERR_NOTREADY ); 
  776.  
  777.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  778.         PLAYER_UNLOCK(); // leave player context CS
  779.  
  780.         if( FAILED(hr) || pPlayerInfo == NULL )
  781.         {
  782.             // The player who sent this may have gone away before this 
  783.             // message was handled, so just ignore it
  784.             continue;
  785.         }
  786.  
  787.         ZeroMemory( &lvItem, sizeof(lvItem) );
  788.  
  789.         // Add the item, saving the player's name and dpnid in the listview
  790.         lvItem.mask       = LVIF_TEXT | LVIF_PARAM;
  791.         lvItem.iItem      = 0;
  792.         lvItem.iSubItem   = 0;
  793.         lvItem.pszText    = pPlayerInfo->strPlayerName;
  794.         lvItem.lParam     = g_pPlayers[i];
  795.         lvItem.cchTextMax = _tcslen( pPlayerInfo->strPlayerName );
  796.         int nIndex = ListView_InsertItem( hListView, &lvItem );
  797.  
  798.         if( pPlayerInfo->bHalfDuplex )
  799.         {
  800.             _tcscpy( strText, TEXT("Can't talk") );
  801.         }
  802.         else
  803.         {
  804.             if( pPlayerInfo->bTalking )
  805.                 _tcscpy( strText, TEXT("Talking") );
  806.             else
  807.                 _tcscpy( strText, TEXT("Silent") );
  808.         }
  809.  
  810.         // Start the player's status off as silent.  
  811.         lvItem.mask       = LVIF_TEXT;
  812.         lvItem.iItem      = nIndex;
  813.         lvItem.iSubItem   = 1;
  814.         lvItem.pszText    = strText;
  815.         lvItem.cchTextMax = _tcslen( strText );
  816.         ListView_SetItem( hListView, &lvItem );
  817.  
  818.         if( pPlayerInfo->ps.dwGroup == 0 )
  819.             _tcscpy( strText, TEXT("Unassigned") );
  820.         else
  821.             wsprintf( strText, TEXT("%d"), pPlayerInfo->ps.dwGroup );
  822.  
  823.         lvItem.mask       = LVIF_TEXT;
  824.         lvItem.iItem      = nIndex;
  825.         lvItem.iSubItem   = 2;
  826.         lvItem.pszText    = strText;
  827.         lvItem.cchTextMax = _tcslen( strText );
  828.         ListView_SetItem( hListView, &lvItem );
  829.  
  830.         if( pPlayerInfo->ps.dwTarget == 0 )
  831.             _tcscpy( strText, TEXT("Everyone") );
  832.         else
  833.             wsprintf( strText, TEXT("%d"), pPlayerInfo->ps.dwTarget );
  834.  
  835.         PLAYER_LOCK();
  836.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  837.         PLAYER_UNLOCK();
  838.  
  839.         lvItem.mask       = LVIF_TEXT;
  840.         lvItem.iItem      = nIndex;
  841.         lvItem.iSubItem   = 3;
  842.         lvItem.pszText    = strText;
  843.         lvItem.cchTextMax = _tcslen( strText );
  844.         ListView_SetItem( hListView, &lvItem );
  845.     }
  846.  
  847.     wsprintf( strNumberPlayers, TEXT("%d"), dwNumPlayers );
  848.     SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  849.  
  850.     if( g_pPlayerLocal )
  851.     {
  852.         if( g_pPlayerLocal->ps.dwGroup == 0 )
  853.             _tcscpy( strText, TEXT("Unassigned") );
  854.         else
  855.             wsprintf( strText, TEXT("Group #%d"), g_pPlayerLocal->ps.dwGroup );
  856.         SetDlgItemText( hDlg, IDC_GROUP_TEXT, strText );
  857.  
  858.         if( g_pPlayerLocal->ps.dwTarget == 0 )
  859.             _tcscpy( strText, TEXT("Everyone") );
  860.         else
  861.             wsprintf( strText, TEXT("Group #%d"), g_pPlayerLocal->ps.dwTarget );
  862.         SetDlgItemText( hDlg, IDC_TARGET_TEXT, strText );
  863.     }
  864.  
  865.  
  866.     return S_OK;
  867. }
  868.  
  869.  
  870.  
  871.  
  872. //-----------------------------------------------------------------------------
  873. // Name: SendLocalStateToAll()
  874. // Desc: Send the local player's state to all of the players
  875. //-----------------------------------------------------------------------------
  876. HRESULT SendLocalStateToAll( HWND hDlg )
  877. {
  878.     if( g_pPlayerLocal )
  879.     {
  880.         GAMEMSG_PLAYERSTATECHANGE msgPlayerStateChange;
  881.         msgPlayerStateChange.dwType = GAME_MSGID_PLAYERSTATECHANGE;
  882.         msgPlayerStateChange.ps     = g_pPlayerLocal->ps; 
  883.  
  884.         DPN_BUFFER_DESC bufferDesc;
  885.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_PLAYERSTATECHANGE);
  886.         bufferDesc.pBufferData  = (BYTE*) &msgPlayerStateChange;
  887.  
  888.         // DirectPlay will tell via the message handler 
  889.         // if there are any severe errors, so ignore any errors 
  890.         DPNHANDLE hAsync;
  891.         g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  892.                        0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  893.     }
  894.  
  895.     return S_OK;
  896. }
  897.  
  898.  
  899.  
  900.  
  901. //-----------------------------------------------------------------------------
  902. // Name: SetGroupAndTarget()
  903. // Desc: 
  904. //-----------------------------------------------------------------------------
  905. HRESULT SetGroupAndTarget()
  906. {
  907.     HRESULT hr;
  908.  
  909.     LPDIRECTPLAYVOICECLIENT pVoiceClient = g_pNetVoice->GetVoiceClient();
  910.     if( pVoiceClient && g_pPlayerLocal->ps.dwTarget == 0 )
  911.     {
  912.         // Talk to everyone in the session 
  913.         DVID dvid = DVID_ALLPLAYERS;
  914.         if( FAILED( hr = pVoiceClient->SetTransmitTargets( &dvid, 1, 0 ) ) )
  915.             return DXTRACE_ERR( TEXT("SetTransmitTargets"), hr );
  916.     }
  917.  
  918.     if( g_LocalGroupDPNID != 0 )
  919.     {
  920.         // Remove player from current group
  921.         DPNHANDLE hAsync;
  922.         hr = g_pDP->RemovePlayerFromGroup( g_LocalGroupDPNID, 
  923.                                            g_LocalPlayerDPNID,
  924.                                            NULL, &hAsync, 0 );
  925.         if( FAILED(hr) )
  926.             return DXTRACE_ERR( TEXT("RemovePlayerFromGroup"), hr );
  927.  
  928.         g_LocalGroupDPNID = 0;
  929.     }
  930.  
  931.     // Enumerate all groups to figure out which group we are target, and joining
  932.     DPNID* aGroupsDPNID = NULL;
  933.     DWORD dwCount = 0;
  934.  
  935.     do
  936.     {
  937.         SAFE_DELETE_ARRAY( aGroupsDPNID );
  938.         if( dwCount ) 
  939.             aGroupsDPNID = new DPNID[ dwCount ];
  940.         hr = g_pDP->EnumPlayersAndGroups( aGroupsDPNID, &dwCount, DPNENUM_GROUPS );
  941.     }
  942.     while( hr == DPNERR_BUFFERTOOSMALL && dwCount != 0 );
  943.     if( FAILED(hr) && dwCount != 0 )
  944.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  945.  
  946.     for( DWORD i=0; i<dwCount; i++ )
  947.     {
  948.         DWORD dwGroupNumber;
  949.  
  950.         // Get group info 
  951.         DWORD dwSize = 0;
  952.         DPN_GROUP_INFO* pdpGroupInfo = NULL;
  953.         hr = g_pDP->GetGroupInfo( aGroupsDPNID[i], pdpGroupInfo, &dwSize, 0 );
  954.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  955.             return DXTRACE_ERR( TEXT("GetGroupInfo"), hr );
  956.         pdpGroupInfo = (DPN_GROUP_INFO*) new BYTE[ dwSize ];
  957.         ZeroMemory( pdpGroupInfo, dwSize );
  958.         pdpGroupInfo->dwSize = sizeof(DPN_GROUP_INFO); 
  959.         hr = g_pDP->GetGroupInfo( aGroupsDPNID[i], pdpGroupInfo, &dwSize, 0 );
  960.         if( FAILED(hr) )
  961.             return DXTRACE_ERR( TEXT("GetGroupInfo"), hr );
  962.  
  963.         if( pdpGroupInfo->pvData )
  964.             dwGroupNumber = *( (DWORD*) pdpGroupInfo->pvData );
  965.         else
  966.             dwGroupNumber = 0;
  967.  
  968.         SAFE_DELETE_ARRAY( pdpGroupInfo );
  969.  
  970.         if( dwGroupNumber == 0 )
  971.             continue;
  972.  
  973.         if( dwGroupNumber == g_pPlayerLocal->ps.dwGroup )
  974.         {
  975.             g_LocalGroupDPNID = aGroupsDPNID[i];
  976.  
  977.             // Add player to this group
  978.             DPNHANDLE hAsync;
  979.             hr = g_pDP->AddPlayerToGroup( aGroupsDPNID[i], g_LocalPlayerDPNID, 
  980.                                                       NULL, &hAsync, 0 );
  981.             if( FAILED( hr ) ) 
  982.                 return DXTRACE_ERR( TEXT("AddPlayerToGroup"), hr );
  983.         }
  984.  
  985.         if( dwGroupNumber == g_pPlayerLocal->ps.dwTarget )
  986.         {
  987.             // Talk to just this group
  988.             hr = pVoiceClient->SetTransmitTargets( &aGroupsDPNID[i], 1, 0 );
  989.             if( FAILED( hr ) ) 
  990.                 return DXTRACE_ERR( TEXT("SetTransmitTargets"), hr );
  991.         }
  992.     }
  993.  
  994.     SAFE_DELETE_ARRAY( aGroupsDPNID );
  995.  
  996.     return S_OK;
  997. }
  998.  
  999.  
  1000.  
  1001.  
  1002. //-----------------------------------------------------------------------------
  1003. // Name: DirectPlayMessageHandler
  1004. // Desc: Handler for DirectPlay messages.  This function is called by
  1005. //       the DirectPlay message handler pool of threads, so be care of thread
  1006. //       synchronization problems with shared memory
  1007. //-----------------------------------------------------------------------------
  1008. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  1009.                                          DWORD dwMessageId, 
  1010.                                          PVOID pMsgBuffer )
  1011. {
  1012.     // Try not to stay in this message handler for too long, otherwise
  1013.     // there will be a backlog of data.  The best solution is to 
  1014.     // queue data as it comes in, and then handle it on other threads.
  1015.     
  1016.     // This function is called by the DirectPlay message handler pool of 
  1017.     // threads, so be care of thread synchronization problems with shared memory
  1018.  
  1019.     switch( dwMessageId )
  1020.     {
  1021.         case DPN_MSGID_CREATE_PLAYER:
  1022.         {
  1023.             HRESULT hr;
  1024.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1025.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER) pMsgBuffer;
  1026.  
  1027.             // Create a new and fill in a APP_PLAYER_INFO
  1028.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1029.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1030.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1031.             pPlayerInfo->lRefCount   = 1;
  1032.  
  1033.             // Get the peer info and extract its name
  1034.             DWORD dwSize = 0;
  1035.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1036.             hr = DPNERR_CONNECTING;
  1037.             
  1038.             // GetPeerInfo might return DPNERR_CONNECTING when connecting, 
  1039.             // so just keep calling it if it does
  1040.             while( hr == DPNERR_CONNECTING ) 
  1041.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );                                
  1042.                 
  1043.             if( hr == DPNERR_BUFFERTOOSMALL )
  1044.             {
  1045.                 pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1046.                 ZeroMemory( pdpPlayerInfo, dwSize );
  1047.                 pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1048.                 
  1049.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  1050.                 if( SUCCEEDED(hr) )
  1051.                 {
  1052.                     // This stores a extra TCHAR copy of the player name for 
  1053.                     // easier access.  This will be redundent copy since DPlay 
  1054.                     // also keeps a copy of the player name in GetPeerInfo()
  1055.                     DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1056.                                                        pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );    
  1057.                                                        
  1058.                     // See if this is the local player
  1059.                     if( (pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) != 0 )
  1060.                     {
  1061.                         g_pPlayerLocal = pPlayerInfo;
  1062.                         g_pPlayerLocal->ps.dwGroup  = 0;
  1063.                         g_pPlayerLocal->ps.dwTarget = 0;
  1064.                         g_LocalPlayerDPNID = pCreatePlayerMsg->dpnidPlayer;
  1065.                     }        
  1066.                 }
  1067.  
  1068.                 SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1069.             }
  1070.  
  1071.             // Tell DirectPlay to store this pPlayerInfo 
  1072.             // pointer in the pvPlayerContext.
  1073.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1074.  
  1075.             if( FAILED( hr = SendLocalStateToAll( g_hDlg ) ) )
  1076.                 return DXTRACE_ERR( TEXT("SendLocalStateToAll"), hr );
  1077.  
  1078.             // Post a message to the dialog thread to update the 
  1079.             // UI.  This keeps the DirectPlay message handler 
  1080.             // from blocking
  1081.             if( g_hDlg != NULL )
  1082.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1083.             break;
  1084.         }
  1085.  
  1086.         case DPN_MSGID_DESTROY_PLAYER:
  1087.         {
  1088.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1089.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1090.  
  1091.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1092.             
  1093.             PLAYER_LOCK();                  // enter player context CS
  1094.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1095.             PLAYER_UNLOCK();                // leave player context CS
  1096.  
  1097.             // Post a message to the dialog thread to update the 
  1098.             // UI.  This keeps the DirectPlay message handler 
  1099.             // from blocking
  1100.             if( g_hDlg != NULL )
  1101.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1102.  
  1103.             break;
  1104.         }
  1105.  
  1106.         case DPN_MSGID_RECEIVE:
  1107.         {
  1108.             PDPNMSG_RECEIVE pReceiveMsg;
  1109.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1110.  
  1111.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1112.             if( pMsg->dwType == GAME_MSGID_PLAYERSTATECHANGE )
  1113.             {
  1114.                 GAMEMSG_PLAYERSTATECHANGE* pPlayerStateChangedMsg;
  1115.                 pPlayerStateChangedMsg = (GAMEMSG_PLAYERSTATECHANGE*) pMsg;
  1116.  
  1117.                 PLAYER_LOCK(); // enter player context CS
  1118.  
  1119.                 APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1120.  
  1121.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1122.                 PLAYER_UNLOCK(); // leave player context CS
  1123.  
  1124.                 if( pPlayerInfo )
  1125.                     pPlayerInfo->ps = pPlayerStateChangedMsg->ps;
  1126.  
  1127.                 PLAYER_LOCK();
  1128.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1129.                 PLAYER_UNLOCK();
  1130.  
  1131.                 // Post a message to the dialog thread to update the 
  1132.                 // UI.  This keeps the DirectPlay message handler 
  1133.                 // from blocking
  1134.                 if( g_hDlg != NULL )
  1135.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1136.             }
  1137.             break;
  1138.         }
  1139.  
  1140.         case DPN_MSGID_TERMINATE_SESSION:
  1141.         {
  1142.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1143.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1144.  
  1145.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1146.             EndDialog( g_hDlg, 0 );
  1147.             break;
  1148.         }
  1149.     }
  1150.  
  1151.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1152.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  1153.     if( g_pNetConnectWizard )
  1154.         return g_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1155.     
  1156.     return S_OK;
  1157. }
  1158.  
  1159.  
  1160.  
  1161.  
  1162. //-----------------------------------------------------------------------------
  1163. // Name: DirectPlayLobbyMessageHandler
  1164. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  1165. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  1166. //       thread synchronization problems with shared memory
  1167. //-----------------------------------------------------------------------------
  1168. HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  1169.                                               DWORD dwMessageId, 
  1170.                                               PVOID pMsgBuffer )
  1171. {
  1172.     switch( dwMessageId )
  1173.     {
  1174.         case DPL_MSGID_CONNECT:
  1175.         {
  1176.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1177.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1178.  
  1179.             // The CNetConnectWizard will handle this message for us,
  1180.             // so there is nothing we need to do here for this simple
  1181.             // sample.
  1182.             break;
  1183.         }
  1184.  
  1185.         case DPL_MSGID_DISCONNECT:
  1186.         {
  1187.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  1188.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  1189.  
  1190.             // We should free any data associated with the lobby 
  1191.             // client here, but there is none.
  1192.             break;
  1193.         }
  1194.  
  1195.         case DPL_MSGID_RECEIVE:
  1196.         {
  1197.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  1198.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  1199.  
  1200.             // The lobby client sent us data.  This sample doesn't
  1201.             // expected data from the client, but it is useful 
  1202.             // for more complex apps.
  1203.             break;
  1204.         }
  1205.  
  1206.         case DPL_MSGID_CONNECTION_SETTINGS:
  1207.         {
  1208.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  1209.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  1210.  
  1211.             // The lobby client has changed the connection settings.  
  1212.             // This simple sample doesn't handle this, but more complex apps may
  1213.             // want to.
  1214.             break;
  1215.         }
  1216.     }
  1217.  
  1218.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1219.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  1220.     if( g_pNetConnectWizard )
  1221.         return g_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  1222.                                                          pMsgBuffer );
  1223.     
  1224.     return S_OK;
  1225. }
  1226.  
  1227.  
  1228.  
  1229.  
  1230. //-----------------------------------------------------------------------------
  1231. // Name: DirectPlayVoiceServerMessageHandler()
  1232. // Desc: The callback for DirectPlayVoice server messages.  
  1233. //-----------------------------------------------------------------------------
  1234. HRESULT CALLBACK DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1235.                                                       LPVOID lpMessage )
  1236. {
  1237.     // This simple sample doesn't respond to any server messages
  1238.     return S_OK;
  1239. }
  1240.  
  1241.  
  1242.  
  1243.  
  1244. //-----------------------------------------------------------------------------
  1245. // Name: DirectPlayVoiceClientMessageHandler()
  1246. // Desc: The callback for DirectPlayVoice client messages.  
  1247. //       This handles client messages and updates the UI the whenever a client 
  1248. //       starts or stops talking.  
  1249. //-----------------------------------------------------------------------------
  1250. HRESULT CALLBACK DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1251.                                                       LPVOID lpMessage )
  1252. {
  1253.     // Try not to stay in this message handler for too long, otherwise
  1254.     // there will be a backlog of data.  The best solution is to 
  1255.     // queue data as it comes in, and then handle it on other threads.
  1256.     
  1257.     // This function is called by the DirectPlay message handler pool of 
  1258.     // threads, so be care of thread synchronization problems with shared memory
  1259.     HRESULT hr;
  1260.     HWND hDlg = (HWND) lpvUserContext;
  1261.  
  1262.     switch( dwMessageType )
  1263.     {
  1264.         case DVMSGID_CREATEVOICEPLAYER:
  1265.             {
  1266.                 DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  1267.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  1268.  
  1269.                 PLAYER_LOCK(); // enter player context CS
  1270.  
  1271.                 // Get the player context accosicated with this DPNID
  1272.                 hr = g_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  1273.                                               (LPVOID* const) &pPlayerInfo,
  1274.                                               0);
  1275.  
  1276.                 if( FAILED(hr) || pPlayerInfo == NULL )
  1277.                 {
  1278.                     // The player who sent this may have gone away before this 
  1279.                     // message was handled, so just ignore it
  1280.                     PLAYER_UNLOCK();
  1281.                     break;
  1282.                 }
  1283.  
  1284.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, for voice context value
  1285.                 PLAYER_UNLOCK(); // leave player context CS
  1286.  
  1287.                 pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  1288.  
  1289.                 // Set voice context value
  1290.                 pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;                
  1291.  
  1292.                 // Post a message to the dialog thread to update the 
  1293.                 // UI.  This keeps the DirectPlay message handler 
  1294.                 // from blocking
  1295.                 if( g_hDlg != NULL )
  1296.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1297.             }
  1298.             break;
  1299.  
  1300.         case DVMSGID_DELETEVOICEPLAYER:
  1301.         {
  1302.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  1303.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  1304.  
  1305.             // Don't update the dlg if this message is for the local 
  1306.             // client since the dlg will be gone.
  1307.             if( pMsg->dvidPlayer != g_LocalPlayerDPNID )
  1308.             {
  1309.                 // Post a message to the dialog thread to update the 
  1310.                 // UI.  This keeps the DirectPlay message handler 
  1311.                 // from blocking
  1312.                 if( hDlg != NULL )
  1313.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1314.             }
  1315.  
  1316.             // Release our extra reference on the player info that we have for the voice
  1317.             // context value.  
  1318.             //
  1319.             PLAYER_LOCK();
  1320.             PLAYER_RELEASE( pPlayerInfo );  
  1321.             PLAYER_UNLOCK();
  1322.             break;
  1323.         } 
  1324.  
  1325.         case DVMSGID_SESSIONLOST:
  1326.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1327.             EndDialog( g_hDlg, 0 );
  1328.             break;
  1329.  
  1330.         case DVMSGID_HOSTMIGRATED:
  1331.         {
  1332.             DVMSG_HOSTMIGRATED* pMsg = (DVMSG_HOSTMIGRATED*) lpMessage;
  1333.  
  1334.             if( pMsg->pdvServerInterface != NULL )
  1335.             {           
  1336.                 // If we keep the pMsg->pdvServerInterface pointer around, then
  1337.                 // we must AddRef() it.  The CNetVoice::HostMigrate() automatically
  1338.                 // does this for us.
  1339.                 g_pNetVoice->HostMigrate( pMsg->pdvServerInterface );
  1340.  
  1341.                 g_bHostPlayer = TRUE;
  1342.                 SetWindowText( hDlg, TEXT("VoiceGroup (Session Host)") );
  1343.             }
  1344.             break;
  1345.         }
  1346.  
  1347.         case DVMSGID_GAINFOCUS:
  1348.         case DVMSGID_LOSTFOCUS:
  1349.         {
  1350.             TCHAR strWindowName[MAX_PATH];
  1351.             wsprintf( strWindowName, TEXT("%s%s%s"), g_strAppName,
  1352.                 (g_bHostPlayer)                      ? TEXT(" (Session Host)") : TEXT(""),
  1353.                 (dwMessageType == DVMSGID_LOSTFOCUS) ? TEXT(" (Focus Lost)") : TEXT("") );
  1354.  
  1355.             SetWindowText( hDlg, strWindowName );
  1356.             break;
  1357.         }
  1358.  
  1359.         case DVMSGID_RECORDSTART:             
  1360.         { 
  1361.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  1362.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, TRUE );
  1363.             break;
  1364.         }
  1365.         case DVMSGID_RECORDSTOP:             
  1366.         {
  1367.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  1368.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, FALSE );
  1369.             break;
  1370.         }
  1371.         case DVMSGID_PLAYERVOICESTART:
  1372.         {
  1373.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  1374.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, TRUE );
  1375.             break;
  1376.         }
  1377.  
  1378.         case DVMSGID_PLAYERVOICESTOP:
  1379.         {
  1380.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  1381.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, FALSE );            
  1382.             break;
  1383.         }
  1384.         
  1385.     }
  1386.  
  1387.     return S_OK;
  1388. }
  1389.  
  1390.  
  1391.  
  1392.  
  1393. //-----------------------------------------------------------------------------
  1394. // Name: SetPlayerTalking()
  1395. // Desc: Set player talking flag
  1396. //-----------------------------------------------------------------------------
  1397. void SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking )
  1398. {
  1399.     if( pPlayerInfo )
  1400.         pPlayerInfo->bTalking = bTalking;     
  1401. }
  1402.  
  1403.  
  1404.  
  1405.  
  1406. //-----------------------------------------------------------------------------
  1407. // Name: VoiceConfigDlgProc()
  1408. // Desc: Prompt the user for DirectPlayVoice setup options
  1409. //-----------------------------------------------------------------------------
  1410. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  1411. {
  1412.     DWORD dwSliderPos;
  1413.  
  1414.     switch( msg ) 
  1415.     {
  1416.         case WM_INITDIALOG:
  1417.             // Set the range on the sliders
  1418.             SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER,       TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1419.             SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER,         TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1420.             SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER,        TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERQUALITY_MIN, DVBUFFERQUALITY_MAX ) );
  1421.             SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER,    TBM_SETRANGE, FALSE, MAKELONG( DVTHRESHOLD_MIN,  DVTHRESHOLD_MAX ) );
  1422.             SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERAGGRESSIVENESS_MIN, DVBUFFERAGGRESSIVENESS_MAX ) );
  1423.  
  1424.             // Setup the dialog based on the globals 
  1425.  
  1426.             // Set the playback controls
  1427.             if( g_dvClientConfig.lPlaybackVolume == DVPLAYBACKVOLUME_DEFAULT )
  1428.             {
  1429.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_DEFAULT );
  1430.             }
  1431.             else
  1432.             {
  1433.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lPlaybackVolume - DSBVOLUME_MIN ) * 
  1434.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1435.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1436.                 SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1437.             }
  1438.  
  1439.             // Set the record controls
  1440.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTORECORDVOLUME )
  1441.             {
  1442.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_AUTO );
  1443.             }
  1444.             else if( g_dvClientConfig.lRecordVolume == DVPLAYBACKVOLUME_DEFAULT )
  1445.             {
  1446.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_DEFAULT );
  1447.             }
  1448.             else
  1449.             {
  1450.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lRecordVolume - DSBVOLUME_MIN ) * 
  1451.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1452.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1453.                 SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1454.             }
  1455.  
  1456.             // Set the threshold controls
  1457.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTOVOICEACTIVATED )
  1458.             {
  1459.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_AUTO );
  1460.             }
  1461.             else if( g_dvClientConfig.dwThreshold == DVTHRESHOLD_DEFAULT )
  1462.             {
  1463.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_DEFAULT );
  1464.             }
  1465.             else
  1466.             {
  1467.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1468.                 SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwThreshold );
  1469.             }
  1470.  
  1471.             // Set the quality controls
  1472.             if( g_dvClientConfig.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  1473.             {
  1474.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_DEFAULT );
  1475.             }
  1476.             else
  1477.             {
  1478.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1479.                 SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferQuality );
  1480.             }
  1481.  
  1482.             // Set the aggressiveness controls
  1483.             if( g_dvClientConfig.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  1484.             {
  1485.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_DEFAULT );
  1486.             }
  1487.             else
  1488.             {
  1489.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1490.                 SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferAggressiveness );
  1491.             }
  1492.  
  1493.             if( !g_bHostPlayer || g_bVoiceSessionInProgress )
  1494.             {
  1495.                 // We are are not the host player then disable all the server only options 
  1496.                 EnableWindow( GetDlgItem( hDlg, IDC_COMPRESSION_COMBO ), FALSE );
  1497.                 EnableWindow( GetDlgItem( hDlg, IDC_SESSIONCOMPRESION_GROUP ), FALSE );
  1498.             }
  1499.             else
  1500.             {
  1501.                 VoiceConfigEnumCompressionCodecs( hDlg );   
  1502.                 EnableWindow( GetDlgItem( hDlg, IDCANCEL ), FALSE );
  1503.             }
  1504.  
  1505.             return TRUE;
  1506.  
  1507.         case WM_NOTIFY:
  1508.             #ifndef NM_RELEASEDCAPTURE
  1509.                 #define NM_RELEASEDCAPTURE (NM_FIRST-16)
  1510.             #endif
  1511.             if( ((LPNMHDR) lParam)->code == NM_RELEASEDCAPTURE )
  1512.             {
  1513.                 // If this is a release capture from a slider, then automatically check 
  1514.                 // its 'Set' radio button.
  1515.                 switch( ((LPNMHDR) lParam)->idFrom )
  1516.                 {
  1517.                 case IDC_PLAYBACK_SLIDER:
  1518.                     CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1519.                     break;
  1520.     
  1521.                 case IDC_RECORD_SLIDER:
  1522.                     CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1523.                     break;
  1524.     
  1525.                 case IDC_THRESHOLD_SLIDER:
  1526.                     CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1527.                     break;
  1528.     
  1529.                 case IDC_QUALITY_SLIDER:
  1530.                     CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1531.                     break;
  1532.     
  1533.                 case IDC_AGGRESSIVENESS_SLIDER:
  1534.                     CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1535.                     break;
  1536.                 }
  1537.             }
  1538.             return TRUE;            
  1539.  
  1540.         case WM_COMMAND:
  1541.             switch( LOWORD(wParam) )
  1542.             {
  1543.                 case IDOK:
  1544.                     VoiceConfigDlgOnOK( hDlg );
  1545.                     return TRUE;
  1546.  
  1547.                 case IDCANCEL:
  1548.                     EndDialog( hDlg, IDCANCEL );
  1549.                     return TRUE;
  1550.             }
  1551.             break;
  1552.  
  1553.         case WM_DESTROY:
  1554.         {
  1555.             GUID* pGuid;
  1556.             int nCount = (int)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCOUNT, 0, 0 );
  1557.             for( int i=0; i<nCount; i++ )
  1558.             {
  1559.                 pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETITEMDATA, i, 0 );
  1560.                 SAFE_DELETE( pGuid );
  1561.             }
  1562.             break;
  1563.         }
  1564.    }
  1565.  
  1566.     return FALSE; // Didn't handle message
  1567. }
  1568.  
  1569.  
  1570.  
  1571.  
  1572. //-----------------------------------------------------------------------------
  1573. // Name: VoiceConfigEnumCompressionCodecs()
  1574. // Desc: Asks DirectPlayVoice what voice compression codecs are availible
  1575. //       and fills the combo box thier names and GUIDs.
  1576. //-----------------------------------------------------------------------------
  1577. HRESULT VoiceConfigEnumCompressionCodecs( HWND hDlg )
  1578. {
  1579.     LPDIRECTPLAYVOICECLIENT pVoiceClient        = NULL;
  1580.     LPDVCOMPRESSIONINFO     pdvCompressionInfo  = NULL;
  1581.     LPGUID  pGuid         = NULL;
  1582.     LPBYTE  pBuffer       = NULL;
  1583.     DWORD   dwSize        = 0;
  1584.     DWORD   dwNumElements = 0;
  1585.     HWND    hPulldown     = GetDlgItem( hDlg, IDC_COMPRESSION_COMBO );
  1586.     HRESULT hr;
  1587.     LONG    lIndex;
  1588.     LONG    lFirst;
  1589.  
  1590.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1591.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, 
  1592.                                        CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, 
  1593.                                        (VOID**) &pVoiceClient ) ) )
  1594.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  1595.  
  1596.     hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, &dwNumElements, 0 );
  1597.     if( hr != DVERR_BUFFERTOOSMALL && FAILED(hr) )
  1598.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1599.  
  1600.     pBuffer = new BYTE[dwSize];
  1601.     if( FAILED( hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, 
  1602.                                                         &dwNumElements, 0 ) ) )
  1603.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1604.  
  1605.     SAFE_RELEASE( pVoiceClient );
  1606.     CoUninitialize();
  1607.  
  1608.     pdvCompressionInfo = (LPDVCOMPRESSIONINFO) pBuffer;
  1609.     for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1610.     {
  1611.         TCHAR strName[MAX_PATH];
  1612.  
  1613.         DXUtil_ConvertWideStringToGeneric( strName, pdvCompressionInfo[dwIndex].lpszName );
  1614.         lIndex = (LONG)SendMessage( hPulldown, CB_ADDSTRING, 0, (LPARAM) strName );
  1615.  
  1616.         pGuid = new GUID;
  1617.         (*pGuid) = pdvCompressionInfo[dwIndex].guidType;
  1618.         SendMessage( hPulldown, CB_SETITEMDATA, lIndex, (LPARAM) pGuid );
  1619.  
  1620.         if( pdvCompressionInfo[dwIndex].guidType == DPVCTGUID_SC03 )
  1621.             lFirst = lIndex;
  1622.     }
  1623.  
  1624.     SAFE_DELETE_ARRAY( pBuffer );
  1625.     SendMessage( hPulldown, CB_SETCURSEL, lFirst, 0 );
  1626.  
  1627.     return S_OK;
  1628. }
  1629.  
  1630.  
  1631.  
  1632.  
  1633. //-----------------------------------------------------------------------------
  1634. // Name: VoiceConfigDlgOnOK()
  1635. // Desc: Figure out all the DirectPlayVoice setup params from the dialog box,
  1636. //       and store them in global vars.
  1637. //-----------------------------------------------------------------------------
  1638. VOID VoiceConfigDlgOnOK( HWND hDlg )
  1639. {
  1640.     DWORD dwSliderPos;
  1641.  
  1642.     g_dvClientConfig.dwFlags = 0;
  1643.  
  1644.     // Figure out the playback params
  1645.     if( IsDlgButtonChecked( hDlg, IDC_PLAYBACK_DEFAULT ) )
  1646.     {
  1647.         g_dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
  1648.     }
  1649.     else 
  1650.     {
  1651.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_GETPOS, 0, 0 );
  1652.         g_dvClientConfig.lPlaybackVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1653.                                                                     (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1654.     }
  1655.  
  1656.     // Figure out the record params
  1657.     if( IsDlgButtonChecked( hDlg, IDC_RECORD_AUTO ) )
  1658.     {
  1659.         g_dvClientConfig.lRecordVolume = 0;
  1660.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTORECORDVOLUME;
  1661.     }
  1662.     else if( IsDlgButtonChecked( hDlg, IDC_RECORD_DEFAULT ) )
  1663.     {
  1664.         g_dvClientConfig.lRecordVolume = DVPLAYBACKVOLUME_DEFAULT;
  1665.     }
  1666.     else 
  1667.     {
  1668.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_GETPOS, 0, 0 );
  1669.         g_dvClientConfig.lRecordVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1670.                                                                   (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1671.     }
  1672.  
  1673.     // Figure out the threshold params
  1674.     if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_AUTO ) )
  1675.     {
  1676.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
  1677.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTOVOICEACTIVATED;
  1678.     }
  1679.     else if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_DEFAULT ) )
  1680.     {
  1681.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_DEFAULT;
  1682.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1683.     }
  1684.     else 
  1685.     {
  1686.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_GETPOS, 0, 0 );
  1687.         g_dvClientConfig.dwThreshold = dwSliderPos;
  1688.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1689.     }
  1690.  
  1691.     // Figure out the quality params
  1692.     if( IsDlgButtonChecked( hDlg, IDC_QUALITY_DEFAULT ) )
  1693.     {
  1694.         g_dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  1695.     }
  1696.     else 
  1697.     {
  1698.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_GETPOS, 0, 0 );
  1699.         g_dvClientConfig.dwBufferQuality = dwSliderPos;
  1700.     }
  1701.  
  1702.     // Figure out the aggressiveness params
  1703.     if( IsDlgButtonChecked( hDlg, IDC_AGGRESSIVENESS_DEFAULT ) )
  1704.     {
  1705.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  1706.     }
  1707.     else 
  1708.     {
  1709.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_GETPOS, 0, 0 );
  1710.         g_dvClientConfig.dwBufferAggressiveness = dwSliderPos;
  1711.     }
  1712.  
  1713.     if( g_bHostPlayer )
  1714.     {
  1715.         // Figure out the compression codec
  1716.         LONG lCurSelection;
  1717.         LPGUID pGuidCT;
  1718.  
  1719.         lCurSelection = (LONG)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCURSEL, 0, 0 );
  1720.         if( lCurSelection != CB_ERR )
  1721.         {
  1722.             pGuidCT = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, 
  1723.                                                    CB_GETITEMDATA, lCurSelection, 0 );
  1724.             if( pGuidCT != NULL )
  1725.                 g_guidDVSessionCT = (*pGuidCT);
  1726.         }
  1727.     }
  1728.  
  1729.     EndDialog( hDlg, IDOK );
  1730. }
  1731.  
  1732.  
  1733.  
  1734.  
  1735.