SessionInfo.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:78k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: SessionInfo.cpp
  3. //
  4. // Desc: Implemenation for the CSessionInfo utility class. This utility stores
  5. //       player, group, and message information gathered from the application's
  6. //       DirectPlay message handler, and provides a dialog UI to display the
  7. //       data.
  8. //
  9. //       In order to use this class, simply create an instance using a
  10. //       pointer to the DirectPlay Peer, Client, or Server interface your 
  11. //       application uses. Add a call to the MessageHandler member function at 
  12. //       the beginning of your application's message handler, and call 
  13. //       ShowDialog to launch the UI. 
  14. //
  15. //       This class supports multiple concurrent modeless dialogs to help with
  16. //       debugging an application during runtime.  
  17. //
  18. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  19. //-----------------------------------------------------------------------------
  20. #include "sessioninfo.h"
  21. // Global variables
  22. CSessionInfo* g_pSI = NULL;    // Global instance pointer
  23.  
  24. // Custom fonts
  25. #ifdef UNDER_CE
  26. LOGFONT g_lfName =       { 20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("MS Sans Serif") };
  27. LOGFONT g_lfConnection = { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, TEXT("Courier New") };
  28. #else
  29. LOGFONT g_lfName =       { 24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("MS Sans Serif") };
  30. LOGFONT g_lfConnection = { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, TEXT("Courier New") };
  31. #endif
  32. //-----------------------------------------------------------------------------
  33. // Name: CSIGroup()
  34. // Desc: Constructor
  35. //-----------------------------------------------------------------------------
  36. CSIGroup::CSIGroup( DPNID dpnid )
  37. {
  38.     id = dpnid;
  39.     lstrcpy( strName, TEXT("") );
  40.     pMembers = new CArrayList( AL_VALUE, sizeof(DPNID) );
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Name: ~CSIGroup()
  44. // Desc: Destructor
  45. //-----------------------------------------------------------------------------
  46. CSIGroup::~CSIGroup()
  47. {
  48.     SAFE_DELETE( pMembers );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Name: CSIPlayer()
  52. // Desc: Constructor
  53. //-----------------------------------------------------------------------------
  54. CSIPlayer::CSIPlayer( DPNID dpnid ) 
  55. {
  56.     id = dpnid;
  57.     bIsHost = FALSE;
  58.     lstrcpy( strName, TEXT("") );
  59.     lstrcpy( strURL, TEXT("") );
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Name: AddMember()
  63. // Desc: Adds the given player ID to the list of member players in this group
  64. //-----------------------------------------------------------------------------
  65. HRESULT CSIGroup::AddMember( DPNID id )
  66. {
  67.     // Check to see if this Member is already present
  68.     if( IsMember( id ) )
  69.         return S_OK;
  70.     // Add the new player id
  71.     return pMembers->Add( &id );
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Name: RemoveMember
  75. // Desc: Removes the given player ID from the list of member players in this
  76. //       group
  77. //-----------------------------------------------------------------------------
  78. HRESULT CSIGroup::RemoveMember( DPNID id )
  79. {
  80.     // Find the Member
  81.     for( UINT i=0; i < pMembers->Count(); i++ )
  82.     {
  83.         DPNID* pID = (DPNID*) pMembers->GetPtr( i );
  84.     
  85.         // Member found
  86.         if( id == *pID )
  87.         {
  88.             // Remove the id and return
  89.             pMembers->Remove( i );
  90.             return S_OK;
  91.         }
  92.     }
  93.     // Not found
  94.     return E_FAIL;
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Name: CSessionInfo()
  98. // Desc: Constructor
  99. //-----------------------------------------------------------------------------
  100. CSessionInfo::CSessionInfo( IDirectPlay8Peer* pPeer ) 
  101. {
  102.     Initialize();
  103.   
  104.     m_eType         = PEER;
  105.     m_pPeer         = pPeer;
  106.     
  107.     m_pPeer->AddRef();
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Name: CSessionInfo()
  111. // Desc: Constructor
  112. //-----------------------------------------------------------------------------
  113. CSessionInfo::CSessionInfo( IDirectPlay8Client* pClient ) 
  114. {
  115.     Initialize();
  116.     m_eType        = CLIENT;
  117.     m_pClient      = pClient;
  118.     
  119.     m_pClient->AddRef();
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Name: CSessionInfo()
  123. // Desc: Constructor
  124. //-----------------------------------------------------------------------------
  125. CSessionInfo::CSessionInfo( IDirectPlay8Server* pServer ) 
  126. {
  127.     Initialize();
  128.     m_eType         = SERVER;
  129.     m_pServer       = pServer;
  130.     
  131.     m_pServer->AddRef();
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Name: Initialize()
  135. // Desc: Performs common initialization for all connection types
  136. //-----------------------------------------------------------------------------
  137. VOID CSessionInfo::Initialize()
  138. {
  139.     g_pSI   = this;
  140.     m_pPlayers       = new CArrayList( AL_REFERENCE );
  141.     m_pGroups        = new CArrayList( AL_REFERENCE );
  142.     m_eType         = INVALID;
  143.     m_pPeer         = NULL;
  144.     m_pClient       = NULL;
  145.     m_pServer       = NULL;
  146.     m_dpnidLocal    = 0;
  147.     
  148.     m_hDlg          = NULL;
  149.     m_hDlgParent    = NULL;
  150.     m_hDlgPlayers   = NULL;
  151.     m_hDlgMessages  = NULL;
  152.     m_hDlgThread    = NULL;
  153.     // Load custom fonts and resources
  154. #ifndef UNDER_CE 
  155.     HMODULE hShellLib = LoadLibraryEx( TEXT("Shell32.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE );
  156.     if( hShellLib )
  157.     {
  158.         m_hPlayerIcon = (HICON) LoadImage( hShellLib, MAKEINTRESOURCE(18),  
  159.                                            IMAGE_ICON, 24, 24, LR_LOADTRANSPARENT);
  160.         m_hGroupIcon =  (HICON) LoadImage( hShellLib, MAKEINTRESOURCE(273), 
  161.                                            IMAGE_ICON, 24, 24, LR_LOADTRANSPARENT);
  162.         FreeLibrary( hShellLib );
  163.     }
  164. #endif // !UNDER_CE
  165.     // Create display fonts
  166.     m_hNameFont = CreateFontIndirect( &g_lfName );
  167.     m_hConnectionFont = CreateFontIndirect( &g_lfConnection );
  168.     InitializeCriticalSection( &m_csLock );
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Name: ~CSessionInfo()
  172. // Desc: Destructor
  173. //-----------------------------------------------------------------------------
  174. CSessionInfo::~CSessionInfo()
  175. {
  176.     // Cleanup dialog
  177.     if( m_hDlg )
  178.         SendMessage( m_hDlg, WM_CLOSE, 0, 0 );
  179.     
  180.     SafeDestroyThread( &m_hDlgThread );
  181.     // Cleanup interfaces
  182.     SAFE_RELEASE( m_pPeer );
  183.     SAFE_RELEASE( m_pClient );
  184.     SAFE_RELEASE( m_pServer );
  185.     for( UINT i=0; i < m_pPlayers->Count(); i++ )
  186.     {
  187.         CSIPlayer* pPlayer = (CSIPlayer*) m_pPlayers->GetPtr( i );
  188.         SAFE_DELETE( pPlayer );
  189.     }
  190.     for( i=0; i < m_pGroups->Count(); i++ )
  191.     {
  192.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  193.         SAFE_DELETE( pGroup );
  194.     }
  195.     SAFE_DELETE( m_pPlayers );
  196.     SAFE_DELETE( m_pGroups );
  197.     DeleteObject( m_hNameFont );
  198.     DeleteObject( m_hConnectionFont );
  199.     DeleteCriticalSection( &m_csLock );
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Name: InitializeLocalPlayer()
  203. // Desc: Initialize the local player given the guessed local dpnid. 
  204. //-----------------------------------------------------------------------------
  205. HRESULT CSessionInfo::InitializeLocalPlayer( DPNID idLocal )
  206. {
  207.     HRESULT hr = S_OK;
  208.     DPN_PLAYER_INFO* pInfo = NULL;
  209. #ifdef _DEBUG
  210.     if( NULL == idLocal )
  211.         return E_INVALIDARG;
  212. #endif // _DEBUG
  213.     hr = GetDpPlayerInfo( idLocal, &pInfo );
  214.     switch( m_eType )
  215.     {
  216.         // Peer types can query information for any peer, including
  217.         // themselves, so simply check the returned playerinfo structure
  218.         // for the local flag
  219.         case PEER:
  220.             if( SUCCEEDED(hr) )
  221.             {
  222.                 if( pInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  223.                     m_dpnidLocal = idLocal;
  224.                 if( pInfo->dwPlayerFlags & DPNPLAYER_HOST )
  225.                     m_dpnidHost = idLocal;
  226.             }
  227.             break;
  228.         // Server types can't query for local information. In a typical game,
  229.         // the player context would be checked to determine whether the created
  230.         // player is the server; to avoid changing the player contexts for
  231.         // every application this class is used with, we'll simply take a best
  232.         // guess and assume that if the new player isn't a client it must be
  233.         // the server.
  234.         case SERVER:
  235.             if( hr == DPNERR_INVALIDPLAYER )
  236.             {
  237.                 m_dpnidLocal = m_dpnidHost = idLocal;
  238.                 hr = S_OK;
  239.             }
  240.             break;
  241.         // Client types can simply wait for the server to send their local
  242.         // information.
  243.         case CLIENT:
  244.             break;
  245.     }
  246.     return hr;
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Name: FindPlayer
  250. // Desc: Search for and return the player based on dpnid
  251. //-----------------------------------------------------------------------------
  252. CSIPlayer* CSessionInfo::FindPlayer( DPNID id )
  253. {
  254.     // Find the player
  255.     for( UINT i=0; i < m_pPlayers->Count(); i++ )
  256.     {
  257.        CSIPlayer* pPlayer = (CSIPlayer*)m_pPlayers->GetPtr( i );
  258.        
  259.         // Player found
  260.         if( id == pPlayer->id )
  261.             return pPlayer;
  262.     }
  263.     // Not found
  264.     return NULL;
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Name: FindGroup
  268. // Desc: Search for and return the group based on dpnid
  269. //-----------------------------------------------------------------------------
  270. CSIGroup* CSessionInfo::FindGroup( DPNID id )
  271. {
  272.     // Find the group
  273.     for( UINT i=0; i < m_pGroups->Count(); i++ )
  274.     {
  275.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  276.         // Group found
  277.         if( id == pGroup->id )
  278.             return pGroup;
  279.     }
  280.     // Not found
  281.     return NULL;
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Name: CreatePlayer()
  285. // Desc: Creates a new player with the given ID and name, and adds the new node
  286. //       to the player list
  287. //-----------------------------------------------------------------------------
  288. HRESULT CSessionInfo::CreatePlayer( DPNID id )
  289. {
  290.     HRESULT hr;
  291.     // Create a new player object
  292.     CSIPlayer* pNewPlayer = new CSIPlayer( id );
  293.     if( NULL == pNewPlayer )
  294.         return E_OUTOFMEMORY;
  295.     // Add the new object to the list
  296.     hr = m_pPlayers->Add( pNewPlayer );
  297.     if( FAILED(hr) )
  298.     {
  299.         // Release the allocated memory and return the error code
  300.         SAFE_DELETE( pNewPlayer );
  301.         return hr;
  302.     }
  303.    return S_OK;
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Name: DestroyPlayer()
  307. // Desc: Removes the player with the given ID from the player list
  308. //-----------------------------------------------------------------------------
  309. HRESULT CSessionInfo::DestroyPlayer( DPNID id )
  310. {
  311.     // Find the player
  312.     for( UINT i=0; i < m_pPlayers->Count(); i++ )
  313.     {
  314.         CSIPlayer* pPlayer = (CSIPlayer*)m_pPlayers->GetPtr( i );
  315.         // Player found
  316.         if( id == pPlayer->id )
  317.         {
  318.             // Zero out the spot and return
  319.             m_pPlayers->Remove( i );
  320.             SAFE_DELETE( pPlayer );
  321.             return S_OK;
  322.         }
  323.     }
  324.     // Not found
  325.     return E_FAIL;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Name: CreateGroup()
  329. // Desc: Creates a group with the given ID and name, and adds the new node to
  330. //       the group list
  331. //-----------------------------------------------------------------------------
  332. HRESULT CSessionInfo::CreateGroup( DPNID id )
  333. {
  334.     HRESULT hr;
  335.     // Create a new group object
  336.     CSIGroup* pNewGroup = new CSIGroup( id );
  337.     if( NULL == pNewGroup )
  338.         return E_OUTOFMEMORY;
  339.     // Add the new object to the list
  340.     hr = m_pGroups->Add( pNewGroup );
  341.     if( FAILED(hr) )
  342.     {
  343.         // Release the allocated memory and return the error code
  344.         SAFE_DELETE( pNewGroup);
  345.         return hr;
  346.     }
  347.    return S_OK;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Name: DestroyGroup()
  351. // Desc: Removes the group with the given ID from the group list
  352. //-----------------------------------------------------------------------------
  353. HRESULT CSessionInfo::DestroyGroup( DPNID id )
  354. {
  355.     // Find the group
  356.     for( UINT i=0; i < m_pGroups->Count(); i++ )
  357.     {
  358.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  359.         // Group found
  360.         if( id == pGroup->id )
  361.         {
  362.             // Zero out the spot and return
  363.             m_pGroups->Remove( i );
  364.             SAFE_DELETE( pGroup );
  365.             return S_OK;
  366.         }
  367.     }
  368.     // Not found
  369.     return E_FAIL;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Name: AddPlayerToGroup()
  373. // Desc: Adds the given player ID to the list of member players in the group
  374. //       with the given group ID 
  375. //-----------------------------------------------------------------------------
  376. HRESULT CSessionInfo::AddPlayerToGroup( DPNID idPlayer, DPNID idGroup )
  377. {
  378.     // Find the group
  379.     for( UINT i=0; i < m_pGroups->Count(); i++ )
  380.     {
  381.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  382.         // Group found
  383.         if( idGroup == pGroup->id )
  384.         {
  385.             // Add the dpnid and return
  386.             return pGroup->AddMember( idPlayer );
  387.         }
  388.     }
  389.     // Not found
  390.     return E_FAIL;
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Name: RemovePlayerFromGroup()
  394. // Desc: Removes the given player ID from the list of member players in the 
  395. //       group with the given group ID
  396. //-----------------------------------------------------------------------------
  397. HRESULT CSessionInfo::RemovePlayerFromGroup( DPNID idPlayer, DPNID idGroup )
  398. {
  399.     // Find the group
  400.     for( UINT i=0; i < m_pGroups->Count(); i++ )
  401.     {
  402.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  403.         // Group found
  404.         if( idGroup == pGroup->id )
  405.         {
  406.             // Remove the dpnid and return
  407.             return pGroup->RemoveMember( idPlayer );
  408.         }
  409.     }
  410.     // Not found
  411.     return E_FAIL;
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Name: RefreshPlayerInfo()
  415. // Desc: Use DirectPlay to refresh all info for the player with the given ID
  416. //-----------------------------------------------------------------------------
  417. HRESULT CSessionInfo::RefreshPlayerInfo( DPNID id )
  418. {
  419.     HRESULT                 hr              = S_OK;
  420.     LPWSTR                  strURL          = NULL;
  421.     DWORD                   dwNumChars      = 0;
  422.     DPN_PLAYER_INFO*        pDpPlayerInfo   = NULL;
  423.     IDirectPlay8Address*    rpAddress[16]   = {0};
  424.     DWORD                   dwNumAddresses  = 16;
  425. #ifdef _DEBUG
  426.     // Parameter validation
  427.     if( NULL == id )
  428.         return E_INVALIDARG;
  429. #endif // _DEBUG
  430.     // Attempt to get the name and flags
  431.     hr = GetDpPlayerInfo( id, &pDpPlayerInfo );
  432.     if( FAILED(hr) )
  433.         goto LCleanReturn;
  434.     // If receiving information about the local player, determine
  435.     // whether this app is the session host
  436.     if( id == m_dpnidLocal )
  437.     {
  438.         // Attempt to get the local address
  439.         switch( m_eType )
  440.         {
  441.             case PEER:
  442.                 hr = m_pPeer->GetLocalHostAddresses( rpAddress, &dwNumAddresses, 0 );
  443.                 break;
  444.             case SERVER:
  445.                 hr = m_pServer->GetLocalHostAddresses( rpAddress, &dwNumAddresses, 0 );
  446.                 break;
  447.             default:
  448.                 hr = E_FAIL;
  449.                 break;
  450.         }
  451.     }
  452.     else
  453.     {
  454.         // Attempt to get the remote address
  455.         dwNumAddresses = 1;
  456.         switch( m_eType )
  457.         {
  458.             case PEER:
  459.                 hr = m_pPeer->GetPeerAddress( id, rpAddress, 0 );
  460.                 break;
  461.             case SERVER:
  462.                 hr = m_pServer->GetClientAddress( id, rpAddress, 0 );
  463.                 break;
  464.             case CLIENT:
  465.                 if( id == m_dpnidHost )
  466.                     hr = m_pClient->GetServerAddress( rpAddress, 0 );
  467.                 else
  468.                     hr = DPNERR_INVALIDPLAYER;
  469.                 break;
  470.             default:
  471.                 hr = E_FAIL;
  472.                 break;
  473.         }
  474.     }
  475.     
  476.     // If the address was retrieved, extract the URL
  477.     if( SUCCEEDED(hr) )
  478.     {
  479.         // Get needed allocation size for the URL string
  480.         hr = rpAddress[0]->GetURLW( NULL, &dwNumChars );
  481.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  482.             goto LCleanReturn;
  483.         // Allocate the URL string
  484.         strURL = new WCHAR[ dwNumChars ];
  485.         if( NULL == strURL )
  486.         {
  487.             hr = E_OUTOFMEMORY;
  488.             goto LCleanReturn;
  489.         }
  490.         // Get the URL
  491.         hr = rpAddress[0]->GetURLW( strURL, &dwNumChars );
  492.         if( FAILED(hr) )
  493.             goto LCleanReturn;
  494.     }
  495.     // Locate the stored player data
  496.     Lock();
  497.     CSIPlayer* pPlayer;
  498.     pPlayer = FindPlayer( id );  
  499.     if( pPlayer )
  500.     {
  501.         // Set the player data
  502.         pPlayer->bIsHost = ( pDpPlayerInfo->dwPlayerFlags & DPNPLAYER_HOST );
  503.         if( strURL )
  504.         {
  505.             DXUtil_ConvertWideStringToGenericCch( pPlayer->strURL, strURL, 256 );
  506.         }
  507.         if( pDpPlayerInfo->pwszName)
  508.         {
  509.             DXUtil_ConvertWideStringToGenericCch( pPlayer->strName, 
  510.                                                   pDpPlayerInfo->pwszName, 256 ); 
  511.         }
  512.     }
  513.     Unlock();
  514. LCleanReturn:
  515.     // Release resources
  516.     SAFE_DELETE_ARRAY( strURL );
  517.  
  518.     for( UINT i=0; i < dwNumAddresses; i++ )
  519.         SAFE_RELEASE( rpAddress[i] );
  520.     SAFE_DELETE_ARRAY( pDpPlayerInfo );
  521.    
  522.     return hr;
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Name: RefreshGroupInfo()
  526. // Desc: Use DirectPlay to refresh all info for the group with the given ID
  527. //-----------------------------------------------------------------------------
  528. HRESULT CSessionInfo::RefreshGroupInfo( DPNID id )
  529. {
  530.     HRESULT hr       = S_OK;
  531.     DPN_GROUP_INFO* pDpGroupInfo    = NULL;
  532.     
  533.     // Attempt to get the name
  534.     hr = GetDpGroupInfo( id, &pDpGroupInfo );
  535.     if( FAILED(hr) )
  536.         goto LCleanReturn;
  537.     // Locate the stored player data
  538.     Lock();
  539.     CSIGroup* pGroup;
  540.     pGroup = FindGroup( id );
  541.     if( pGroup )
  542.     {
  543.         // Set the group data
  544.         DXUtil_ConvertWideStringToGenericCch( pGroup->strName, pDpGroupInfo->pwszName, 256 ); 
  545.     }
  546.     Unlock();
  547. LCleanReturn:
  548.     // Release resources
  549.     SAFE_DELETE_ARRAY( pDpGroupInfo );
  550.     return hr;
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Name: MessageHandler
  554. // Desc: Sift the information headed for the application's DirectPlay message
  555. //       handler, remove any messages used exclusively by this utility class,
  556. //       and store any useful information before the message is passed off to
  557. //       the application.
  558. //-----------------------------------------------------------------------------
  559. BOOL CSessionInfo::MessageHandler( DWORD dwMessageId, PVOID pMsgBuffer )
  560. {
  561.     HRESULT hr = S_OK;
  562.     TCHAR strMessage[ 256 ]; 
  563.     switch( dwMessageId )
  564.     {
  565.         case DPN_MSGID_ADD_PLAYER_TO_GROUP:
  566.         {
  567.             DPNMSG_ADD_PLAYER_TO_GROUP* pMsg = (DPNMSG_ADD_PLAYER_TO_GROUP*) pMsgBuffer;
  568.         
  569.             Lock();
  570.             hr = AddPlayerToGroup( pMsg->dpnidPlayer, pMsg->dpnidGroup );
  571.             Unlock();
  572.             
  573.             // Invalidate the dialog
  574.             m_bDlgValid = FALSE;
  575.     
  576.             // Log the message
  577.             _sntprintf( strMessage, 
  578.                         200, 
  579.                         TEXT("Add Player To Group: player 0x%x, group 0x%x"), 
  580.                         pMsg->dpnidPlayer, 
  581.                         pMsg->dpnidGroup ); 
  582.             
  583.             strMessage[ 200 ] = TEXT('');
  584.             break;
  585.         }
  586.         case DPN_MSGID_APPLICATION_DESC:
  587.         {
  588.             // Set the window title
  589.             DPN_APPLICATION_DESC* pAppDesc;
  590.             if( SUCCEEDED( GetDpAppDesc( &pAppDesc ) ) )
  591.             {
  592.                 TCHAR strTitle[ 256 ];
  593.                 
  594.                 DXUtil_ConvertWideStringToGenericCch( strTitle, 
  595.                                                       pAppDesc->pwszSessionName, 
  596.                                                       256-50 );
  597.                 lstrcat( strTitle, TEXT(" - Session Info") );
  598.                 SendMessage( m_hDlg, WM_SETTEXT, 0, (LPARAM) strTitle ); 
  599.             }
  600.             SAFE_DELETE_ARRAY( pAppDesc );
  601.             // Log the message
  602.             _sntprintf( strMessage, 200, TEXT("Application Desc") );
  603.             strMessage[ 200 ] = TEXT('');
  604.             break;
  605.         }
  606.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  607.         {
  608.             DPNMSG_ASYNC_OP_COMPLETE* pMsg = (DPNMSG_ASYNC_OP_COMPLETE*) pMsgBuffer;
  609.             // The messages sent by this helper class always use the same context.
  610.             // If the completed operation was initiated by this class, we can
  611.             // safely hide the message from the application.
  612.             if( SI_ASYNC_CONTEXT == pMsg->pvUserContext )
  613.                 return TRUE;
  614.             // Log the message
  615.             _sntprintf( strMessage, 
  616.                         200, 
  617.                         TEXT("Async Op Complete: handle 0x%x, result 0x%x"), 
  618.                         pMsg->hAsyncOp, 
  619.                         pMsg->hResultCode );
  620.             strMessage[ 200 ] = TEXT('');
  621.             break;
  622.         }
  623.         case DPN_MSGID_CLIENT_INFO:
  624.         {
  625.             DPNMSG_CLIENT_INFO* pMsg = (DPNMSG_CLIENT_INFO*) pMsgBuffer;
  626.             OnDpInfoChange( pMsg->dpnidClient );
  627.             // Log the message
  628.             _sntprintf( strMessage, 
  629.                         200, 
  630.                         TEXT("Client Info: client 0x%x"), 
  631.                         pMsg->dpnidClient );
  632.             strMessage[ 200 ] = TEXT('');
  633.             break;
  634.         }
  635.         case DPN_MSGID_CONNECT_COMPLETE:
  636.         {
  637.             DPNMSG_CONNECT_COMPLETE* pMsg = (DPNMSG_CONNECT_COMPLETE*) pMsgBuffer;
  638.         
  639.             // Log the message
  640.             _sntprintf( strMessage, 
  641.                         200, 
  642.                         TEXT("Connect Complete: handle 0x%x, result 0x%x"), 
  643.                         pMsg->hAsyncOp, 
  644.                         pMsg->hResultCode );
  645.             strMessage[ 200 ] = TEXT('');
  646.             break;
  647.         }
  648.         case DPN_MSGID_CREATE_GROUP:
  649.         {
  650.             DPNMSG_CREATE_GROUP* pMsg = (DPNMSG_CREATE_GROUP*) pMsgBuffer;
  651.         
  652.             Lock();
  653.             hr = CreateGroup( pMsg->dpnidGroup );
  654.             Unlock();
  655.             
  656.             RefreshGroupInfo( pMsg->dpnidGroup );
  657.             
  658.             if( m_eType == SERVER )
  659.                 SendGroupInfoToAll( pMsg->dpnidGroup );
  660.             // Invalidate the dialog
  661.             m_bDlgValid = FALSE;
  662.             // Log the message
  663.             _sntprintf( strMessage, 
  664.                         200, 
  665.                         TEXT("Create Group: group 0x%x, owner 0x%x"), 
  666.                         pMsg->dpnidGroup, 
  667.                         pMsg->dpnidOwner );
  668.             strMessage[ 200 ] = TEXT('');
  669.             break;
  670.         }
  671.         case DPN_MSGID_CREATE_PLAYER:
  672.         {
  673.             DPNMSG_CREATE_PLAYER* pMsg = (DPNMSG_CREATE_PLAYER*) pMsgBuffer;
  674.         
  675.             Lock();
  676.             hr = CreatePlayer( pMsg->dpnidPlayer );
  677.             Unlock();      
  678.            
  679.             // If we don't know our local dpnid yet, try to initialize
  680.             if( m_dpnidLocal == NULL )
  681.                 InitializeLocalPlayer( pMsg->dpnidPlayer );
  682.             // Update information about the new player
  683.             RefreshPlayerInfo( pMsg->dpnidPlayer );
  684.             
  685.             if( m_eType == SERVER )
  686.             {
  687.                 // Clients receive all their information from the server,
  688.                 // so bundle up the new player's name and flags, and broadcast
  689.                 // to the session.
  690.                 SendPlayerInfoToAll( pMsg->dpnidPlayer );
  691.                 SynchronizeWithPlayer( pMsg->dpnidPlayer );
  692.             }   
  693.             // Invalidate the dialog
  694.             m_bDlgValid = FALSE;
  695.             // Log the message
  696.             _sntprintf( strMessage, 
  697.                         200, 
  698.                         TEXT("Create Player: player 0x%x"), 
  699.                         pMsg->dpnidPlayer );
  700.             strMessage[ 200 ] = TEXT('');
  701.             break;
  702.         }
  703.         case DPN_MSGID_DESTROY_GROUP:
  704.         {
  705.             DPNMSG_DESTROY_GROUP* pMsg = (DPNMSG_DESTROY_GROUP*) pMsgBuffer;
  706.         
  707.             Lock();
  708.             hr = DestroyGroup( pMsg->dpnidGroup );
  709.             Unlock();
  710.              
  711.             // Invalidate the dialog
  712.             m_bDlgValid = FALSE;
  713.             // Log the message
  714.             _sntprintf( strMessage, 
  715.                         200, 
  716.                         TEXT("Destroy Group: group 0x%x"), 
  717.                         pMsg->dpnidGroup );
  718.             strMessage[ 200 ] = TEXT('');
  719.             break;
  720.         }
  721.         case DPN_MSGID_DESTROY_PLAYER:
  722.         {
  723.             DPNMSG_DESTROY_PLAYER* pMsg = (DPNMSG_DESTROY_PLAYER*) pMsgBuffer;
  724.         
  725.             Lock();
  726.             hr = DestroyPlayer( pMsg->dpnidPlayer );
  727.             Unlock();   
  728.             
  729.             // Invalidate the dialog
  730.             m_bDlgValid = FALSE;
  731.             // Log the message
  732.             _sntprintf( strMessage, 
  733.                         200, 
  734.                         TEXT("Destroy Player: player 0x%x"), 
  735.                         pMsg->dpnidPlayer );
  736.             strMessage[ 200 ] = TEXT('');
  737.             break;
  738.         }
  739.         case DPN_MSGID_ENUM_HOSTS_QUERY:
  740.         {
  741.             // Log the message
  742.             _sntprintf( strMessage, 
  743.                         200, 
  744.                         TEXT("Enum Hosts Query") );
  745.             strMessage[ 200 ] = TEXT('');
  746.             break;
  747.         }
  748.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  749.         {
  750.             DPNMSG_ENUM_HOSTS_RESPONSE* pMsg = (DPNMSG_ENUM_HOSTS_RESPONSE*) pMsgBuffer;
  751.         
  752.             // Log the message
  753.             TCHAR szSessionName[200];
  754.             DXUtil_ConvertWideStringToGenericCch( szSessionName, pMsg->pApplicationDescription->pwszSessionName, 200 ); 
  755.             _sntprintf( strMessage, 
  756.                         200, 
  757.                         TEXT("Enum Hosts Response: latency %d ms, session "%s""), 
  758.                         pMsg->dwRoundTripLatencyMS, 
  759.                         szSessionName );
  760.             strMessage[ 200 ] = TEXT('');
  761.             break;
  762.         }
  763.         case DPN_MSGID_GROUP_INFO:
  764.         {
  765.             DPNMSG_GROUP_INFO* pMsg = (DPNMSG_GROUP_INFO*) pMsgBuffer;
  766.             
  767.             RefreshGroupInfo( pMsg->dpnidGroup );
  768.              
  769.             if( m_eType == SERVER )
  770.                 SendGroupInfoToAll( pMsg->dpnidGroup );
  771.             // Invalidate the dialog
  772.             m_bDlgValid = FALSE;
  773.             
  774.             // Log the message
  775.             _sntprintf( strMessage, 
  776.                         200, 
  777.                         TEXT("Group Info: group 0x%x"), 
  778.                         pMsg->dpnidGroup );
  779.             strMessage[ 200 ] = TEXT('');
  780.             break;
  781.         }
  782.         case DPN_MSGID_HOST_MIGRATE:
  783.         {
  784.             DPNMSG_HOST_MIGRATE* pMsg = (DPNMSG_HOST_MIGRATE*) pMsgBuffer;
  785.             m_dpnidHost = pMsg->dpnidNewHost;
  786.             RefreshPlayerInfo( pMsg->dpnidNewHost );
  787.             // Invalidate the dialog
  788.             m_bDlgValid = FALSE;
  789.             // Log the message
  790.             _sntprintf( strMessage, 
  791.                         200, 
  792.                         TEXT("Host Migrate: new host 0x%x"), 
  793.                         pMsg->dpnidNewHost );
  794.             strMessage[ 200 ] = TEXT('');
  795.             break;
  796.         }
  797.         case DPN_MSGID_INDICATE_CONNECT:
  798.         {
  799.             DPNMSG_INDICATE_CONNECT* pMsg = (DPNMSG_INDICATE_CONNECT*) pMsgBuffer;
  800.         
  801.             // Log the message
  802.             _sntprintf( strMessage, 
  803.                         200, 
  804.                     #ifdef _WIN64
  805.                         TEXT("Indicate Connect: player context 0x%I64x"), 
  806.                         (ULONGLONG) pMsg->pvPlayerContext );
  807.                     #else
  808.                         TEXT("Indicate Connect: player context 0x%x"), 
  809.                         (DWORD) pMsg->pvPlayerContext );
  810.                     #endif // _WIN64
  811.                         
  812.             strMessage[ 200 ] = TEXT('');
  813.             break;
  814.         }
  815.         case DPN_MSGID_INDICATED_CONNECT_ABORTED:
  816.         {
  817.             DPNMSG_INDICATED_CONNECT_ABORTED* pMsg = (DPNMSG_INDICATED_CONNECT_ABORTED*) pMsgBuffer;
  818.         
  819.             // Log the message
  820.             _sntprintf( strMessage, 
  821.                         200, 
  822.                     #ifdef _WIN64
  823.                         TEXT("Indicated Connect Aborted: player context 0x%I64x"), 
  824.                         (ULONGLONG) pMsg->pvPlayerContext );
  825.                     #else
  826.                         TEXT("Indicated Connect Aborted: player context 0x%x"), 
  827.                         (DWORD) pMsg->pvPlayerContext );
  828.                     #endif // _WIN64
  829.             strMessage[ 200 ] = TEXT('');
  830.             break;
  831.         }
  832.         case DPN_MSGID_PEER_INFO:
  833.         {
  834.             DPNMSG_PEER_INFO* pMsg = (DPNMSG_PEER_INFO*) pMsgBuffer;
  835.             OnDpInfoChange( pMsg->dpnidPeer );
  836.             // Log the message
  837.             _sntprintf( strMessage, 
  838.                         200, 
  839.                         TEXT("Peer Info: peer 0x%x"), 
  840.                         pMsg->dpnidPeer );
  841.             strMessage[ 200 ] = TEXT('');
  842.             break;
  843.         }
  844.         case DPN_MSGID_RECEIVE:
  845.         {
  846.             DPNMSG_RECEIVE* pMsg = (DPNMSG_RECEIVE*) pMsgBuffer;
  847.             
  848.             if( pMsg->dwSize < sizeof(SI_MSG) )
  849.                 break;
  850.             
  851.             SI_MSG* pSIMsg = (SI_MSG*) pMsg->pReceiveData;
  852.             switch( pSIMsg->dwMsgID )
  853.             {
  854.                 case SI_MSGID_PLAYERINFO:
  855.                 {
  856.                     if( pMsg->dwReceiveDataSize < sizeof(SI_MSG_PLAYERINFO) )
  857.                         break;
  858.                     SI_MSG_PLAYERINFO* pPlayerInfo = (SI_MSG_PLAYERINFO*) pMsg->pReceiveData;
  859.                     // Verify the message is properly sized
  860.                     if( pMsg->dwReceiveDataSize != sizeof(SI_MSG_PLAYERINFO) +
  861.                         ( sizeof(WCHAR) * ( pPlayerInfo->dwNameLength + 1 ) ) )
  862.                         break;
  863.                     
  864.                     // Pass the data off to the message handler function
  865.                     OnPlayerInfoReceive( pPlayerInfo );
  866.                     // Attempt to get additional information about the player
  867.                     RefreshPlayerInfo( pPlayerInfo->dpnID );
  868.                     
  869.                     // Invalidate the dialog
  870.                     m_bDlgValid = FALSE;
  871.                     return TRUE;
  872.                 }
  873.                 case SI_MSGID_GROUPINFO:
  874.                 {
  875.                     if( pMsg->dwReceiveDataSize < sizeof(SI_MSG_GROUPINFO) )
  876.                         break;
  877.                     SI_MSG_GROUPINFO* pGroupInfo = (SI_MSG_GROUPINFO*) pMsg->pReceiveData;
  878.                     if( pMsg->dwReceiveDataSize != sizeof(SI_MSG_GROUPINFO) +
  879.                         ( sizeof(WCHAR) * ( pGroupInfo->dwNameLength + 1 ) ) )
  880.                     {
  881.                         break;
  882.                     }
  883.                     // Pass the data off to the message handler function
  884.                     OnGroupInfoReceive( pGroupInfo );
  885.                     // Invalidate the dialog
  886.                     m_bDlgValid = FALSE;
  887.                     return TRUE;
  888.                 }
  889.             }
  890.             // Log the message
  891.             _sntprintf( strMessage, 
  892.                         200, 
  893.                         TEXT("Receive: sender 0x%x, data size %d bytes"), 
  894.                         pMsg->dpnidSender, 
  895.                         pMsg->dwReceiveDataSize );
  896.             strMessage[ 200 ] = TEXT('');
  897.             break;
  898.         }
  899.         case DPN_MSGID_REMOVE_PLAYER_FROM_GROUP:
  900.         {
  901.             DPNMSG_REMOVE_PLAYER_FROM_GROUP* pMsg = (DPNMSG_REMOVE_PLAYER_FROM_GROUP*) pMsgBuffer;
  902.         
  903.             Lock();
  904.             hr = RemovePlayerFromGroup( pMsg->dpnidPlayer, pMsg->dpnidGroup );
  905.             Unlock();
  906.             
  907.             // Invalidate the dialog
  908.             m_bDlgValid = FALSE;
  909.             // Log the message
  910.             _sntprintf( strMessage, 
  911.                         200, 
  912.                         TEXT("Remove Player From Group: player 0x%x, group 0x%x"), 
  913.                         pMsg->dpnidPlayer, 
  914.                         pMsg->dpnidGroup );
  915.             strMessage[ 200 ] = TEXT('');
  916.             break;
  917.         }
  918.         case DPN_MSGID_RETURN_BUFFER:
  919.         {
  920.             DPNMSG_RETURN_BUFFER* pMsg = (DPNMSG_RETURN_BUFFER*) pMsgBuffer;
  921.             
  922.             // Log the message
  923.             _sntprintf( strMessage, 
  924.                         200, 
  925.                     #ifdef _WIN64
  926.                         TEXT("Return Buffer: user context 0x%I64x, result 0x%x"), 
  927.                         (ULONGLONG) pMsg->pvUserContext,
  928.                     #else
  929.                         TEXT("Return Buffer: user context 0x%x, result 0x%x"), 
  930.                         (DWORD) pMsg->pvUserContext,
  931.                     #endif // _WIN64
  932.                         pMsg->hResultCode );
  933.             strMessage[ 200 ] = TEXT('');
  934.             break;
  935.         }
  936.         case DPN_MSGID_SEND_COMPLETE:
  937.         {
  938.             DPNMSG_SEND_COMPLETE* pMsg = (DPNMSG_SEND_COMPLETE*) pMsgBuffer;
  939.             
  940.             // Log the message
  941.             _sntprintf( strMessage, 
  942.                         200, 
  943.                         TEXT("Send Complete: handle 0x%x, result 0x%x, send time %d ms"), 
  944.                         pMsg->hAsyncOp, 
  945.                         pMsg->hResultCode, 
  946.                         pMsg->dwSendTime );
  947.             strMessage[ 200 ] = TEXT('');
  948.             break;
  949.         }
  950.         
  951.         case DPN_MSGID_SERVER_INFO:
  952.         {
  953.             DPNMSG_SERVER_INFO* pMsg = (DPNMSG_SERVER_INFO*) pMsgBuffer;
  954.             OnDpInfoChange( pMsg->dpnidServer );
  955.             // Log the message
  956.             _sntprintf( strMessage, 
  957.                         200, 
  958.                         TEXT("Server Info: server 0x%x"), 
  959.                         pMsg->dpnidServer );
  960.             strMessage[ 200 ] = TEXT('');
  961.             break;
  962.         }
  963.         case DPN_MSGID_TERMINATE_SESSION:
  964.         {
  965.             DPNMSG_TERMINATE_SESSION* pMsg = (DPNMSG_TERMINATE_SESSION*) pMsgBuffer;
  966.             
  967.             // Log the message
  968.             _sntprintf( strMessage, 
  969.                         200, 
  970.                         TEXT("Terminate Session: result 0x%x"), 
  971.                         pMsg->hResultCode );
  972.             strMessage[ 200 ] = TEXT('');
  973.             break;
  974.         }
  975.         
  976.     }
  977.     CMessageList* pMsgList = NULL;
  978.     int nDlgID = 0;
  979.     // Add the message string to the stored list
  980.     switch( dwMessageId )
  981.     {
  982.         case DPN_MSGID_RECEIVE:
  983.         case DPN_MSGID_SEND_COMPLETE:
  984.         {
  985.             pMsgList = &m_AppMessages;
  986.             nDlgID = IDC_SI_APPMSG;
  987.             break; 
  988.         }
  989.         default:
  990.         {
  991.             pMsgList = &m_DPlayMessages;
  992.             nDlgID = IDC_SI_DPLAYMSG;
  993.             break;   
  994.         }
  995.     }
  996.     
  997.     // Lock the message list
  998.     pMsgList->Lock();
  999.     // If the message queue is already full, remove the bottom item from the dialog box 
  1000.     if( pMsgList->IsFull() )
  1001.         SendMessage( GetDlgItem( m_hDlgMessages, nDlgID ), LB_DELETESTRING, SI_MAX_MESSAGES-1, 0 );
  1002.     // Add the message to the stored list
  1003.     TCHAR* strTimeStamped = pMsgList->AddMessage( strMessage );
  1004.     // Unlock the message list
  1005.     pMsgList->Unlock();
  1006.     // Post the new string to the top of the list box
  1007.     if( m_hDlgMessages )
  1008.         SendMessage( GetDlgItem( m_hDlgMessages, nDlgID ), LB_INSERTSTRING, 0, (LPARAM) strTimeStamped );
  1009.     // Return false to indicate that either the message was not handled, or the
  1010.     // handled message should also be sent to the application message handler.
  1011.     return FALSE;
  1012. }
  1013. //-----------------------------------------------------------------------------
  1014. // Name: OnPlayerInfoReceive()
  1015. // Desc: Handles the extraction and storage of incoming player data
  1016. //-----------------------------------------------------------------------------
  1017. HRESULT CSessionInfo::OnPlayerInfoReceive( SI_MSG_PLAYERINFO* pPlayerInfo )
  1018. {
  1019.     HRESULT hr = S_OK;
  1020.     // Extract the player name
  1021.     LPWSTR pStrName = (LPWSTR) (pPlayerInfo + 1);
  1022.     pStrName[ pPlayerInfo->dwNameLength ] = 0;
  1023.     Lock();
  1024.       
  1025.     // Search for the player with the given ID
  1026.     CSIPlayer* pPlayer = FindPlayer( pPlayerInfo->dpnID ); 
  1027.     // If not found, create a new player
  1028.     if( NULL == pPlayer )
  1029.     {
  1030.         hr = CreatePlayer( pPlayerInfo->dpnID );
  1031.         if( FAILED(hr) )
  1032.             goto LCleanReturn;
  1033.             
  1034.         pPlayer = FindPlayer( pPlayerInfo->dpnID );
  1035.     }
  1036.     // Set updated information
  1037.     pPlayer->bIsHost = pPlayerInfo->dwFlags & DPNPLAYER_HOST;
  1038.     
  1039.     DXUtil_ConvertWideStringToGenericCch( pPlayer->strName, pStrName, 256 ); 
  1040.     
  1041.     if( pPlayerInfo->dwFlags & DPNPLAYER_LOCAL )
  1042.         m_dpnidLocal = pPlayerInfo->dpnID;
  1043.     if( pPlayerInfo->dwFlags & DPNPLAYER_HOST )
  1044.         m_dpnidHost = pPlayerInfo->dpnID;
  1045.     hr = S_OK;
  1046. LCleanReturn:
  1047.     Unlock();
  1048.     return hr;
  1049. }
  1050. //-----------------------------------------------------------------------------
  1051. // Name: OnGroupInfoReceive()
  1052. // Desc: Handles the extraction and storage of incoming group data
  1053. //-----------------------------------------------------------------------------
  1054. HRESULT CSessionInfo::OnGroupInfoReceive( SI_MSG_GROUPINFO* pGroupInfo )
  1055. {
  1056.     HRESULT hr = S_OK;
  1057.     // Extract the name
  1058.     LPWSTR pStr = (LPWSTR) (pGroupInfo+1);
  1059.     pStr[ pGroupInfo->dwNameLength ] = 0;
  1060.     // Set the data
  1061.     Lock();
  1062.     
  1063.     // Search for the group with the given ID
  1064.     CSIGroup* pGroup = FindGroup( pGroupInfo->dpnID );
  1065.     
  1066.     // If not found, create a new group
  1067.     if( NULL == pGroup )
  1068.     {
  1069.         hr = CreateGroup( pGroupInfo->dpnID );
  1070.         if( FAILED(hr) )
  1071.             goto LCleanReturn;
  1072.         pGroup = FindGroup( pGroupInfo->dpnID );
  1073.     }
  1074.     // Set updated information
  1075.     DXUtil_ConvertWideStringToGenericCch( pGroup->strName, pStr, 256 ); 
  1076.     
  1077.     hr = S_OK;
  1078. LCleanReturn:
  1079.     Unlock();
  1080.     return hr;
  1081. }
  1082. //-----------------------------------------------------------------------------
  1083. // Name: OnDpInfoChange()
  1084. // Desc: Handles PEER_INFO, CLIENT_INFO, and SERVER_INFO messages
  1085. //-----------------------------------------------------------------------------
  1086. HRESULT CSessionInfo::OnDpInfoChange( DPNID dpnid )
  1087. {
  1088.     RefreshPlayerInfo( dpnid );
  1089.     
  1090.     if( m_eType == SERVER )
  1091.         SendPlayerInfoToAll( dpnid );
  1092.     // Invalidate the dialog
  1093.     m_bDlgValid = FALSE;
  1094.     return S_OK;
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Name: GetDpPlayerInfo()
  1098. // Desc: Get the DirectPlay player info using the stored connection interface
  1099. //-----------------------------------------------------------------------------
  1100. HRESULT CSessionInfo::GetDpPlayerInfo( DPNID dpnid, DPN_PLAYER_INFO** ppPlayerInfo )
  1101. {
  1102.     HRESULT hr;
  1103.     DWORD dwSize = 0;
  1104. #ifdef _DEBUG
  1105.     if( NULL == ppPlayerInfo || NULL == dpnid )
  1106.         return E_INVALIDARG;
  1107. #endif // _DEBUG
  1108.     
  1109.     switch( m_eType )
  1110.     {
  1111.         case PEER:
  1112.         {
  1113.             // GetPeerInfo might return DPNERR_CONNECTING when connecting, 
  1114.             // so just keep calling it if it does
  1115.             do 
  1116.             {
  1117.                 hr = m_pPeer->GetPeerInfo( dpnid, *ppPlayerInfo, &dwSize, 0 ); 
  1118.             }
  1119.             while( hr == DPNERR_CONNECTING );
  1120.             break;
  1121.         }
  1122.         case SERVER:
  1123.         {
  1124.             // Special case: Server can't query for local information, so
  1125.             // this should be filled in manually
  1126.             if( m_dpnidLocal == dpnid )
  1127.             {
  1128.                 dwSize = sizeof( DPN_PLAYER_INFO );
  1129.                 hr = DPNERR_BUFFERTOOSMALL;
  1130.             }
  1131.             else
  1132.             {
  1133.                 hr = m_pServer->GetClientInfo( dpnid, *ppPlayerInfo, &dwSize, 0 );
  1134.             }
  1135.             break;
  1136.         }
  1137.         case CLIENT:
  1138.         {
  1139.             if( m_dpnidHost == dpnid )
  1140.                 hr = m_pClient->GetServerInfo( *ppPlayerInfo, &dwSize, 0 );
  1141.             else
  1142.                 hr = DPNERR_INVALIDPLAYER;
  1143.             break;
  1144.         }
  1145.         default:
  1146.             // Unknown type
  1147.             return E_FAIL;
  1148.     }
  1149.       
  1150.     // DirectPlay should return BufferTooSmall to give the correct allocation size
  1151.     if( hr != DPNERR_BUFFERTOOSMALL )
  1152.         return hr;
  1153.     // Allocate the memory
  1154.     *ppPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1155.     if( NULL == *ppPlayerInfo )
  1156.         return E_OUTOFMEMORY;
  1157.     // Initialize the struct
  1158.     ZeroMemory( *ppPlayerInfo, dwSize );
  1159.     (*ppPlayerInfo)->dwSize = sizeof(DPN_PLAYER_INFO);
  1160.     
  1161.     // Get peer info
  1162.     switch( m_eType )
  1163.     {
  1164.         case PEER: 
  1165.             hr = m_pPeer->GetPeerInfo( dpnid, *ppPlayerInfo, &dwSize, 0 ); 
  1166.             break;
  1167.         case SERVER: 
  1168.             // Special case: Server can't query for local information, so
  1169.             // this should be filled in manually
  1170.             if( m_dpnidLocal == dpnid )
  1171.             {  
  1172.                 (*ppPlayerInfo)->dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA;
  1173.                 (*ppPlayerInfo)->pwszName = L"(Server)";
  1174.                 (*ppPlayerInfo)->dwPlayerFlags = DPNPLAYER_LOCAL | DPNPLAYER_HOST;
  1175.                 hr = S_OK;
  1176.             }
  1177.             else
  1178.             {
  1179.                 hr = m_pServer->GetClientInfo( dpnid, *ppPlayerInfo, &dwSize, 0 ); 
  1180.             }
  1181.             break;
  1182.         case CLIENT:
  1183.             hr = m_pClient->GetServerInfo( *ppPlayerInfo, &dwSize, 0 );
  1184.             break;
  1185.         default: 
  1186.             SAFE_DELETE_ARRAY( *ppPlayerInfo );
  1187.             return E_FAIL;
  1188.     }
  1189.     return hr;
  1190. }
  1191. //-----------------------------------------------------------------------------
  1192. // Name: GetDpGroupInfo
  1193. // Desc: Get the DirectPlay group info using the stored connection interface
  1194. //-----------------------------------------------------------------------------
  1195. HRESULT CSessionInfo::GetDpGroupInfo( DPNID dpnid, DPN_GROUP_INFO** ppGroupInfo )
  1196. {
  1197.     HRESULT hr;
  1198.     DWORD dwSize = 0;
  1199. #ifdef _DEBUG
  1200.     if( NULL == ppGroupInfo )
  1201.         return E_INVALIDARG;
  1202. #endif // _DEBUG
  1203.     
  1204.     switch( m_eType )
  1205.     {
  1206.         case PEER:
  1207.             hr = m_pPeer->GetGroupInfo( dpnid, NULL, &dwSize, NULL );
  1208.             break;
  1209.         case SERVER:
  1210.             hr = m_pServer->GetGroupInfo( dpnid, NULL, &dwSize, NULL );
  1211.             break;
  1212.         default:
  1213.             return E_FAIL;
  1214.     }
  1215.     // DirectPlay should return BufferTooSmall to give the correct allocation size
  1216.     if( hr != DPNERR_BUFFERTOOSMALL )
  1217.         return hr;
  1218.     // Allocate the memory
  1219.     *ppGroupInfo = (DPN_GROUP_INFO*) new BYTE[ dwSize ];
  1220.     if( NULL == *ppGroupInfo )
  1221.         return E_OUTOFMEMORY;
  1222.     // Initialize the struct
  1223.     ZeroMemory( *ppGroupInfo, dwSize );
  1224.     (*ppGroupInfo)->dwSize = sizeof(DPN_GROUP_INFO);
  1225.     
  1226.     // Get group info
  1227.     switch( m_eType )
  1228.     {
  1229.         case PEER:
  1230.             hr = m_pPeer->GetGroupInfo( dpnid, *ppGroupInfo, &dwSize, 0 );
  1231.             break;
  1232.         case SERVER:
  1233.             hr = m_pServer->GetGroupInfo( dpnid, *ppGroupInfo, &dwSize, 0 );
  1234.             break;
  1235.         default:
  1236.             SAFE_DELETE_ARRAY( *ppGroupInfo );
  1237.             return E_FAIL;
  1238.     }
  1239.     return hr;
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Name: GetDpAppDesc
  1243. // Desc: Get the DirectPlay application description using the stored connection 
  1244. //       interface
  1245. //-----------------------------------------------------------------------------
  1246. HRESULT CSessionInfo::GetDpAppDesc( DPN_APPLICATION_DESC** ppAppDesc )
  1247. {
  1248.     HRESULT hr;
  1249.     DWORD dwSize = 0;
  1250. #ifdef _DEBUG
  1251.     if( NULL == ppAppDesc )
  1252.         return E_INVALIDARG;
  1253. #endif // _DEBUG
  1254.     
  1255.     switch( m_eType )
  1256.     {
  1257.         case PEER:
  1258.             hr = m_pPeer->GetApplicationDesc( NULL, &dwSize, NULL );
  1259.             break;
  1260.         case SERVER:
  1261.             hr = m_pServer->GetApplicationDesc( NULL, &dwSize, NULL );
  1262.             break;
  1263.         case CLIENT:
  1264.             hr = m_pClient->GetApplicationDesc( NULL, &dwSize, NULL );
  1265.             break;
  1266.         default:
  1267.             return E_FAIL;
  1268.     }
  1269.     // DirectPlay should return BufferTooSmall to give the correct allocation size
  1270.     if( hr != DPNERR_BUFFERTOOSMALL )
  1271.         return hr;
  1272.     // Allocate the memory
  1273.     *ppAppDesc = (DPN_APPLICATION_DESC*) new BYTE[ dwSize ];
  1274.     if( NULL == *ppAppDesc )
  1275.         return E_OUTOFMEMORY;
  1276.     // Initialize the struct
  1277.     ZeroMemory( *ppAppDesc, dwSize );
  1278.     (*ppAppDesc)->dwSize = sizeof(DPN_APPLICATION_DESC);
  1279.     
  1280.     // Get group info
  1281.     switch( m_eType )
  1282.     {
  1283.            case PEER:
  1284.             hr = m_pPeer->GetApplicationDesc( *ppAppDesc, &dwSize, NULL );
  1285.             break;
  1286.         case SERVER:
  1287.             hr = m_pServer->GetApplicationDesc( *ppAppDesc, &dwSize, NULL );
  1288.             break;
  1289.         case CLIENT:
  1290.             hr = m_pClient->GetApplicationDesc( *ppAppDesc, &dwSize, NULL );
  1291.             break;
  1292.         default:
  1293.             return E_FAIL;
  1294.     }
  1295.     return hr;
  1296. }
  1297. //-----------------------------------------------------------------------------
  1298. // Name: SendPlayerInfoToPlayer()
  1299. // Desc: Send all stored player information with the given player ID to the
  1300. //       player(s) with the given target ID
  1301. //-----------------------------------------------------------------------------
  1302. HRESULT CSessionInfo::SendPlayerInfoToPlayer( DPNID idPlayer, DPNID idTarget )
  1303. {
  1304.     HRESULT hr = S_OK;
  1305.     Lock();
  1306.     
  1307.     CSIPlayer* pPlayer = FindPlayer( idPlayer );
  1308.     if( NULL == pPlayer )
  1309.     {
  1310.         Unlock();
  1311.         return E_INVALIDARG;
  1312.     }
  1313.     // Package and send the given player info
  1314.     DWORD dwNameLen = lstrlen( pPlayer->strName );
  1315.     
  1316.     DPN_BUFFER_DESC dpBufDesc = {0};
  1317.     dpBufDesc.dwBufferSize = sizeof(SI_MSG_PLAYERINFO) + 
  1318.                            ( sizeof( WCHAR ) * (dwNameLen + 1) );
  1319.                            
  1320.     // Allocate space
  1321.     SI_MSG_PLAYERINFO* pMsg = (SI_MSG_PLAYERINFO*) new BYTE[ dpBufDesc.dwBufferSize ];
  1322.     if( NULL == pMsg )
  1323.     {
  1324.         Unlock();
  1325.         return E_OUTOFMEMORY;
  1326.     }
  1327.     // Set the data pointer
  1328.     dpBufDesc.pBufferData = (BYTE*) pMsg;
  1329.     // Store values
  1330.     pMsg->dwMsgID       = SI_MSGID_PLAYERINFO;
  1331.     pMsg->dpnID         = pPlayer->id;
  1332.     pMsg->dwFlags       = 0;
  1333.     pMsg->dwNameLength  = dwNameLen;
  1334.     
  1335.     // Set flags
  1336.     if( pPlayer->bIsHost )
  1337.         pMsg->dwFlags |= DPNPLAYER_HOST;
  1338.     if( idPlayer == idTarget )
  1339.         pMsg->dwFlags |= DPNPLAYER_LOCAL;
  1340.     // Pack the string
  1341.     LPWSTR pStr = (LPWSTR) (pMsg+1);
  1342.     DXUtil_ConvertGenericStringToWideCch( pStr, pPlayer->strName, dwNameLen+1 );
  1343.     
  1344.     // Release the lock
  1345.     Unlock();
  1346.     // Send the information
  1347.     DPNHANDLE dpAsync;
  1348.     switch( m_eType )
  1349.     {
  1350.         case PEER:
  1351.             hr = m_pPeer->SendTo( idTarget, &dpBufDesc, 1, 0, SI_ASYNC_CONTEXT, &dpAsync, DPNSEND_NOCOMPLETE | DPNSEND_NOLOOPBACK );
  1352.             break;
  1353.         case SERVER:
  1354.             hr = m_pServer->SendTo( idTarget, &dpBufDesc, 1, 0, SI_ASYNC_CONTEXT, &dpAsync, DPNSEND_NOCOMPLETE | DPNSEND_NOLOOPBACK );
  1355.             break;
  1356.         case CLIENT:
  1357.             hr = m_pClient->Send( &dpBufDesc, 1, 0, SI_ASYNC_CONTEXT, &dpAsync, DPNSEND_NOCOMPLETE | DPNSEND_NOLOOPBACK );
  1358.             break;
  1359.         default:
  1360.             hr = E_FAIL;
  1361.             break;
  1362.     }
  1363.     // Release allocated memory and return
  1364.     SAFE_DELETE_ARRAY( pMsg );
  1365.     return hr;
  1366. }
  1367. //-----------------------------------------------------------------------------
  1368. // Name: SendGroupInfoToPlayer
  1369. // Desc: Send all stored information about the given group ID to the player(s)
  1370. //       with the given target ID
  1371. //-----------------------------------------------------------------------------
  1372. HRESULT CSessionInfo::SendGroupInfoToPlayer( DPNID idGroup, DPNID idTarget )
  1373. {
  1374.     HRESULT hr = S_OK;
  1375.     Lock();
  1376.     CSIGroup* pGroup = FindGroup( idGroup ); 
  1377.     if( NULL == pGroup )
  1378.     {
  1379.         Unlock();
  1380.         return E_INVALIDARG;
  1381.     }
  1382.     // Package and send the given player info
  1383.     DWORD dwNameLen = lstrlen( pGroup->strName );
  1384.    
  1385.     DPN_BUFFER_DESC dpBufDesc = {0};
  1386.     dpBufDesc.dwBufferSize = sizeof(SI_MSG_GROUPINFO) + 
  1387.                            ( sizeof( WCHAR ) * (dwNameLen + 1) ); 
  1388.     // Allocate space
  1389.     SI_MSG_GROUPINFO* pMsg = (SI_MSG_GROUPINFO*) new BYTE[ dpBufDesc.dwBufferSize ];
  1390.     if( NULL == pMsg )
  1391.     {
  1392.         Unlock();
  1393.         return E_OUTOFMEMORY;
  1394.     }
  1395.     // Set the data pointer
  1396.     dpBufDesc.pBufferData = (BYTE*) pMsg;
  1397.     // Store values
  1398.     pMsg->dwMsgID       = SI_MSGID_GROUPINFO;
  1399.     pMsg->dpnID         = idGroup;
  1400.     pMsg->dwNameLength  = dwNameLen;
  1401.     // Pack the strings
  1402.     LPWSTR pStr = (LPWSTR) (pMsg+1);
  1403.     DXUtil_ConvertGenericStringToWideCch( pStr, pGroup->strName, dwNameLen+1 );
  1404.     
  1405.     // Release the lock
  1406.     Unlock();
  1407.     // Send the information
  1408.     DPNHANDLE dpAsync;
  1409.             
  1410.     switch( m_eType )
  1411.     {
  1412.         case PEER:
  1413.             hr = m_pPeer->SendTo( idTarget, &dpBufDesc, 1, 0, SI_ASYNC_CONTEXT, &dpAsync, DPNSEND_NOCOMPLETE | DPNSEND_NOLOOPBACK );
  1414.             break;
  1415.         case SERVER:
  1416.             hr = m_pServer->SendTo( idTarget, &dpBufDesc, 1, 0, SI_ASYNC_CONTEXT, &dpAsync, DPNSEND_NOCOMPLETE | DPNSEND_NOLOOPBACK );
  1417.             break;
  1418.         default:
  1419.             hr = E_FAIL;
  1420.             break;
  1421.     }
  1422.     // Release allocated memory and return
  1423.     SAFE_DELETE_ARRAY( pMsg );
  1424.     return hr;
  1425. }
  1426. //-----------------------------------------------------------------------------
  1427. // Name: SynchronizeWithPlayer()
  1428. // Desc: Send all stored group and player information to the player with the 
  1429. //       given ID
  1430. //-----------------------------------------------------------------------------
  1431. HRESULT CSessionInfo::SynchronizeWithPlayer( DPNID id )
  1432. {
  1433.     HRESULT hr = S_OK;
  1434.     Lock();
  1435.     // Send all player and group information
  1436.     for( UINT i=0; i < m_pPlayers->Count(); i++ )
  1437.     {
  1438.         CSIPlayer* pPlayer = (CSIPlayer*) m_pPlayers->GetPtr( i );
  1439.         // Attempt to send 
  1440.         hr = SendPlayerInfoToPlayer( pPlayer->id, id );
  1441.         if( FAILED(hr) )
  1442.             break;
  1443.     }
  1444.     for( i=0; i < m_pGroups->Count(); i++ )
  1445.     {
  1446.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  1447.         // Attempt to send 
  1448.         hr = SendGroupInfoToPlayer( pGroup->id, id );
  1449.         if( FAILED(hr) )
  1450.             break;
  1451.     }
  1452.     Unlock();
  1453.     return hr;
  1454. }
  1455. //-----------------------------------------------------------------------------
  1456. // Name: ShowDialog()
  1457. // Desc: Show the dialog UI for all stored player, group, and message data.
  1458. //-----------------------------------------------------------------------------
  1459. HRESULT CSessionInfo::ShowDialog( HWND hParent )
  1460. {
  1461.     // If a dialog already exists, bring it to the front
  1462.     if( m_hDlg )
  1463.     {
  1464.         if( FALSE == BringWindowToTop( m_hDlg ) )
  1465.             return E_FAIL;
  1466.     }
  1467.     else
  1468.     {
  1469.         // If there is an old thread handle, release it now
  1470.         SafeDestroyThread( &m_hDlgThread );
  1471.         // Launch a new dialog thread
  1472.         DWORD dwThreadID;
  1473.         m_hDlgParent = hParent;
  1474.         m_hDlgThread = chBEGINTHREADEX( NULL, 0, StaticDialogThread, (void*) this, 0, &dwThreadID );
  1475.     }
  1476.     return S_OK;
  1477. }
  1478. //-----------------------------------------------------------------------------
  1479. // Name: StaticDialogThread()
  1480. // Desc: Message pump thread for modeless dialogs
  1481. //-----------------------------------------------------------------------------
  1482. DWORD WINAPI CSessionInfo::StaticDialogThread( void* pvRef )
  1483. {
  1484.     CSessionInfo* pThis = (CSessionInfo*) pvRef;
  1485.     pThis->m_hDlgPlayers = CreateDialog( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SI_PLAYERS), pThis->m_hDlgParent, StaticDlgProcPlayers );
  1486.     pThis->m_hDlgMessages = CreateDialog( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SI_MESSAGES), pThis->m_hDlgParent, StaticDlgProcMessages );
  1487.     pThis->m_hDlg = CreateDialog( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SI_MAIN), pThis->m_hDlgParent, StaticDlgProcMain );   
  1488.     
  1489.     ShowWindow( pThis->m_hDlg, SW_SHOW );
  1490.     MSG msg;
  1491.     while( GetMessage( &msg, NULL, 0, 0) )
  1492.     {  
  1493.         // Forward the message to the dialog
  1494.         if( IsDialogMessage( pThis->m_hDlg, &msg ) )
  1495.             continue;
  1496.         if( IsDialogMessage( pThis->m_hDlgPlayers, &msg ) )
  1497.             continue;
  1498.         if( IsDialogMessage( pThis->m_hDlgMessages, &msg ) )
  1499.             continue;
  1500.     }
  1501.     // Release the window resources
  1502.     DestroyWindow( pThis->m_hDlgMessages ); 
  1503.     pThis->m_hDlgMessages = NULL;
  1504.     DestroyWindow( pThis->m_hDlgPlayers );  
  1505.     pThis->m_hDlgPlayers = NULL;
  1506.     DestroyWindow( pThis->m_hDlg );         
  1507.     pThis->m_hDlg = NULL;
  1508.     return 0;
  1509. }
  1510. //-----------------------------------------------------------------------------
  1511. // Name: StaticDlgProcMain()
  1512. // Desc: Static dialog procedure sorts incoming messages according to the
  1513. //       window handle and assigns them to the member dialog procedure for the
  1514. //       correct instance
  1515. //-----------------------------------------------------------------------------
  1516. INT_PTR CALLBACK CSessionInfo::StaticDlgProcMain( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1517. {
  1518.     if( g_pSI )
  1519.         return g_pSI->DlgProcMain( hDlg, uMsg, wParam, lParam );
  1520.     return FALSE;
  1521. }
  1522. //-----------------------------------------------------------------------------
  1523. // Name: StaticDlgProcPlayers()
  1524. // Desc: Static dialog procedure sorts incoming messages according to the
  1525. //       window handle and assigns them to the member dialog procedure for the
  1526. //       correct instance
  1527. //-----------------------------------------------------------------------------
  1528. INT_PTR CALLBACK CSessionInfo::StaticDlgProcPlayers( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1529. {
  1530.     if( g_pSI )
  1531.         return g_pSI->DlgProcPlayers( hDlg, uMsg, wParam, lParam );
  1532.     return FALSE;
  1533. }
  1534. //-----------------------------------------------------------------------------
  1535. // Name: StaticDlgProcMessages()
  1536. // Desc: Static dialog procedure sorts incoming messages according to the
  1537. //       window handle and assigns them to the member dialog procedure for the
  1538. //       correct instance
  1539. //-----------------------------------------------------------------------------
  1540. INT_PTR CALLBACK CSessionInfo::StaticDlgProcMessages( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1541. {
  1542.     if( g_pSI )
  1543.         return g_pSI->DlgProcMessages( hDlg, uMsg, wParam, lParam );
  1544.     return FALSE;
  1545. }
  1546.   
  1547. //-----------------------------------------------------------------------------
  1548. // Name: DlgProcMain()
  1549. // Desc: Dialog procedure for the UI
  1550. //-----------------------------------------------------------------------------
  1551. INT_PTR CALLBACK CSessionInfo::DlgProcMain( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1552. {
  1553.     switch( uMsg )
  1554.     {
  1555.         case WM_INITDIALOG:
  1556.         {
  1557.             SetParent( m_hDlgPlayers, GetDlgItem( hDlg, IDC_SI_TAB ) );
  1558.             SetParent( m_hDlgMessages, GetDlgItem( hDlg, IDC_SI_TAB ) );
  1559.             // Set the window title
  1560.             DPN_APPLICATION_DESC* pAppDesc;
  1561.             if( SUCCEEDED( GetDpAppDesc( &pAppDesc ) ) )
  1562.             {
  1563.                 TCHAR strTitle[ 256 ];
  1564.                 
  1565.                 DXUtil_ConvertWideStringToGenericCch( strTitle, pAppDesc->pwszSessionName, 256-50 );
  1566.                 lstrcat( strTitle, TEXT(" - Session Info") );
  1567.                 SendMessage( hDlg, WM_SETTEXT, 0, (LPARAM) strTitle ); 
  1568.             }
  1569.             // Add tabs
  1570.             TCITEM tcItem = {0};
  1571.             tcItem.mask = TCIF_TEXT;
  1572.             tcItem.pszText = TEXT("Players");
  1573.             SendMessage( GetDlgItem( hDlg, IDC_SI_TAB ), TCM_INSERTITEM, 0, (LPARAM) &tcItem );
  1574.             tcItem.pszText = TEXT("Messages");
  1575.             SendMessage( GetDlgItem( hDlg, IDC_SI_TAB ), TCM_INSERTITEM, 1, (LPARAM) &tcItem );
  1576.             RECT rcWindow = {0};
  1577.             GetWindowRect( GetDlgItem( hDlg, IDC_SI_TAB ), &rcWindow );
  1578.             SendMessage( GetDlgItem( hDlg, IDC_SI_TAB ), TCM_ADJUSTRECT, FALSE, (LPARAM) &rcWindow );
  1579.             POINT ptWindow = { rcWindow.left, rcWindow.top };
  1580.             ScreenToClient( GetDlgItem( hDlg, IDC_SI_TAB ), &ptWindow );
  1581.             MoveWindow( m_hDlgPlayers, ptWindow.x, ptWindow.y, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, FALSE );
  1582.             MoveWindow( m_hDlgMessages, ptWindow.x, ptWindow.y, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, FALSE );
  1583.             ShowWindow( m_hDlgPlayers, SW_SHOW );
  1584.             SAFE_DELETE_ARRAY( pAppDesc );
  1585.             return TRUE;
  1586.         }
  1587.         case WM_COMMAND:
  1588.             switch( LOWORD(wParam) )
  1589.             {
  1590.                 case IDCANCEL:
  1591.                     SendMessage( hDlg, WM_CLOSE, 0, 0 );
  1592.                     return TRUE;
  1593.             }
  1594.             break;
  1595.         case WM_NOTIFY:
  1596.         {
  1597.             NMHDR* pHdr = (NMHDR*) lParam; 
  1598.             switch( pHdr->code )
  1599.             {
  1600.                 case TCN_SELCHANGE:
  1601.                     DWORD dwCurSel = SendMessage( GetDlgItem( hDlg, IDC_SI_TAB ), TCM_GETCURSEL, 0, 0 );
  1602.                     ShowWindow( m_hDlgPlayers,  ( 0 == dwCurSel ) ? SW_SHOW : SW_HIDE );
  1603.                     ShowWindow( m_hDlgMessages, ( 1 == dwCurSel ) ? SW_SHOW : SW_HIDE ); 
  1604.                     return TRUE;
  1605.             }
  1606.             break;
  1607.         }
  1608.         case WM_CLOSE:
  1609.             if( m_hDlgThread )
  1610.                 PostQuitMessage( 0 );
  1611.             else
  1612.                 EndDialog( hDlg, 0 );
  1613.             
  1614.             return TRUE;
  1615.     }
  1616.     return FALSE;
  1617. }
  1618. //-----------------------------------------------------------------------------
  1619. // Name: DlgProcPlayers()
  1620. // Desc: Dialog procedure for the UI
  1621. //-----------------------------------------------------------------------------
  1622. INT_PTR CALLBACK CSessionInfo::DlgProcPlayers( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1623. {
  1624.     switch( uMsg )
  1625.     {
  1626.         case WM_INITDIALOG:
  1627.         {
  1628.             // Set custom dialog settings
  1629.             if( m_hNameFont )
  1630.                 SendMessage( GetDlgItem( hDlg, IDC_SI_NAME ), WM_SETFONT, (WPARAM) m_hNameFont, TRUE );
  1631.             if( m_hConnectionFont )
  1632.                 SendMessage( GetDlgItem( hDlg, IDC_SI_DESCRIPTION ), WM_SETFONT, (WPARAM) m_hConnectionFont, TRUE );
  1633.             
  1634.             // Refresh the dialog contents
  1635.             PaintDialog( hDlg );
  1636.             m_bDlgValid = TRUE;
  1637.             
  1638.             // Set the refresh timer
  1639.             SetTimer( hDlg, SI_REFRESH_TIMER, SI_REFRESH_INTERVAL, NULL );
  1640.             return TRUE;
  1641.         }
  1642.         case WM_TIMER:
  1643.         {
  1644.             if( FALSE == m_bDlgValid )
  1645.                 PaintDialog( hDlg );
  1646.             return TRUE;
  1647.         }
  1648.         case WM_COMMAND:
  1649.         {
  1650.             switch( LOWORD(wParam) )
  1651.             {
  1652.                 case IDC_SI_PLAYERS:
  1653.                 {
  1654.                     if( LBN_SELCHANGE == HIWORD(wParam) )
  1655.                     {
  1656.                         DWORD dwCurSel;
  1657.                         DWORD dwItemData;
  1658.                         if( LB_ERR != ( dwCurSel   = SendMessage( (HWND) lParam, LB_GETCURSEL, 0, 0 ) ) &&
  1659.                             LB_ERR != ( dwItemData = SendMessage( (HWND) lParam, LB_GETITEMDATA, dwCurSel, 0 ) ) )
  1660.                             DisplayPlayer( dwItemData, hDlg );
  1661.                             
  1662.                         return TRUE;
  1663.                     }
  1664.                     break;
  1665.                 }
  1666.                 case IDC_SI_GROUPS:
  1667.                 {
  1668.                     if( LBN_SELCHANGE == HIWORD(wParam) )
  1669.                     {
  1670.                         DWORD dwCurSel;
  1671.                         DWORD dwItemData;
  1672.                         if( LB_ERR != ( dwCurSel   = SendMessage( (HWND) lParam, LB_GETCURSEL, 0, 0 ) ) &&
  1673.                             LB_ERR != ( dwItemData = SendMessage( (HWND) lParam, LB_GETITEMDATA, dwCurSel, 0 ) ) )
  1674.                             DisplayGroup( dwItemData, hDlg );
  1675.                             
  1676.                         return TRUE;
  1677.                     }
  1678.                     break;
  1679.                 }
  1680.                 case IDC_SI_MEMBERSHIP:
  1681.                 {
  1682.                     if( LBN_SELCHANGE == HIWORD(wParam) )
  1683.                     {
  1684.                         DWORD dwCurSel;
  1685.                         DWORD dwItemData;
  1686.                         if( LB_ERR != ( dwCurSel   = SendMessage( (HWND) lParam, LB_GETCURSEL, 0, 0 ) ) &&
  1687.                             LB_ERR != ( dwItemData = SendMessage( (HWND) lParam, LB_GETITEMDATA, dwCurSel, 0 ) ) )
  1688.                         {
  1689.                             if( LB_ERR != SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_GETCURSEL, 0, 0 ) )
  1690.                                 DisplayGroup( dwItemData, hDlg );   
  1691.                             else if( LB_ERR != SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_GETCURSEL, 0, 0 ) )
  1692.                                 DisplayPlayer( dwItemData, hDlg );
  1693.                         }
  1694.                         return TRUE;
  1695.                     }
  1696.                     break;
  1697.                 }
  1698.             }
  1699.             break;
  1700.         }
  1701.     }
  1702.     return FALSE;
  1703. }
  1704. //-----------------------------------------------------------------------------
  1705. // Name: DlgProcMessages()
  1706. // Desc: Dialog procedure for the UI
  1707. //-----------------------------------------------------------------------------
  1708. INT_PTR CALLBACK CSessionInfo::DlgProcMessages( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1709. {
  1710.     switch( uMsg )
  1711.     {
  1712.         case WM_INITDIALOG:
  1713.         {
  1714.             // List box settings
  1715.             PostMessage( GetDlgItem( hDlg, IDC_SI_DPLAYMSG ), LB_INITSTORAGE, SI_MAX_MESSAGES, sizeof(TCHAR) * 256 );
  1716.             PostMessage( GetDlgItem( hDlg, IDC_SI_APPMSG ),   LB_INITSTORAGE, SI_MAX_MESSAGES, sizeof(TCHAR) * 256 );
  1717.             PostMessage( GetDlgItem( hDlg, IDC_SI_DPLAYMSG ), LB_SETHORIZONTALEXTENT, 400, 0 );
  1718.             PostMessage( GetDlgItem( hDlg, IDC_SI_APPMSG ),   LB_SETHORIZONTALEXTENT, 400, 0 );
  1719.             // Fill the message windows
  1720.             m_DPlayMessages.Lock();
  1721.             for( UINT i=0; i < m_DPlayMessages.GetNumOfMessages(); i++ )
  1722.             {
  1723.                 SendMessage( GetDlgItem( hDlg, IDC_SI_DPLAYMSG ), LB_INSERTSTRING, 0, (LPARAM) m_DPlayMessages.GetMessage( i ) );
  1724.             }
  1725.             m_DPlayMessages.Unlock();
  1726.             
  1727.             m_AppMessages.Lock();
  1728.             for( i=0; i < m_AppMessages.GetNumOfMessages(); i++ )
  1729.             {
  1730.                 SendMessage( GetDlgItem( hDlg, IDC_SI_APPMSG ), LB_INSERTSTRING, 0, (LPARAM) m_AppMessages.GetMessage( i ) );
  1731.             }
  1732.             m_AppMessages.Unlock();
  1733.             return TRUE;
  1734.         }
  1735.     }
  1736.     return FALSE;
  1737. }
  1738. //-----------------------------------------------------------------------------
  1739. // Name: PaintDialog()
  1740. // Desc: Fill the dialog with the stored player/group data
  1741. //-----------------------------------------------------------------------------
  1742. VOID CSessionInfo::PaintDialog( HWND hDlg )
  1743. {
  1744.     m_bDlgValid = TRUE;
  1745.     // Store the current selection
  1746.     enum { NONE, PLAYER, GROUP } eSelected = NONE;
  1747.     DWORD dwItemData = 0;
  1748.     DWORD dwCurSel = 0;
  1749.     if( LB_ERR != ( dwCurSel   = SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_GETCURSEL, 0, 0 ) ) &&
  1750.         LB_ERR != ( dwItemData = SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_GETITEMDATA, dwCurSel, 0 ) ) )
  1751.     {
  1752.         eSelected = PLAYER;
  1753.     }
  1754.     else if( LB_ERR != ( dwCurSel   = SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_GETCURSEL, 0, 0 ) ) &&
  1755.              LB_ERR != ( dwItemData = SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_GETITEMDATA, dwCurSel, 0 ) ) )
  1756.     {
  1757.         eSelected = GROUP;
  1758.     }
  1759.     // Clear the current contents
  1760.     SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_RESETCONTENT, 0, 0 );
  1761.     SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_RESETCONTENT, 0, 0 );
  1762.     Lock();
  1763.     
  1764.     // Add Players
  1765.     for( UINT i=0; i < m_pPlayers->Count(); i++ )
  1766.     {
  1767.         CSIPlayer* pPlayer = (CSIPlayer*) m_pPlayers->GetPtr( i );
  1768.         DWORD dwIndex = SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_ADDSTRING, 0, (LPARAM) pPlayer->strName );
  1769.         SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_SETITEMDATA, dwIndex, pPlayer->id );
  1770.     }
  1771.     // Add Groups
  1772.     for( i=0; i < m_pGroups->Count(); i++ )
  1773.     {
  1774.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  1775.         DWORD dwIndex = SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_ADDSTRING, 0, (LPARAM) pGroup->strName );
  1776.         SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_SETITEMDATA, dwIndex, pGroup->id );
  1777.     }
  1778.     Unlock();
  1779.     // Restore the selection
  1780.     switch( eSelected )
  1781.     {
  1782.         case PLAYER: 
  1783.             if( FAILED( DisplayPlayer( dwItemData, hDlg ) ) )
  1784.                 DisplayPlayer( m_dpnidLocal, hDlg );
  1785.             break;
  1786.         case GROUP:  
  1787.             if( FAILED( DisplayGroup( dwItemData, hDlg ) ) )
  1788.                 DisplayPlayer( m_dpnidLocal, hDlg );
  1789.             break;
  1790.         default: 
  1791.             DisplayPlayer( m_dpnidLocal, hDlg );
  1792.             break;
  1793.     }
  1794. }
  1795. //-----------------------------------------------------------------------------
  1796. // Name: DisplayPlayer()
  1797. // Desc: Display all stored information about the given player in the dialog UI
  1798. //-----------------------------------------------------------------------------
  1799. HRESULT CSessionInfo::DisplayPlayer( DPNID id, HWND hDlg )
  1800. {
  1801.     HRESULT hr;
  1802.     // Set the icon
  1803. #ifndef UNDER_CE
  1804.     if( m_hPlayerIcon )
  1805.         SendMessage( GetDlgItem( hDlg, IDC_SI_NAME_ICON ), STM_SETICON, (LPARAM) m_hPlayerIcon, 0 );
  1806. #endif // !UNDER_CE
  1807.     // Clear the dialog data
  1808.     SendMessage( GetDlgItem( hDlg, IDC_SI_NAME ), WM_SETTEXT, 0, (LPARAM) TEXT("") );
  1809.     SendMessage( GetDlgItem( hDlg, IDC_SI_GROUPS ), LB_SETCURSEL, (WPARAM) -1, 0 );
  1810.     SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_RESETCONTENT, 0, 0 );
  1811.     SendMessage( GetDlgItem( hDlg, IDC_SI_DESCRIPTION ), WM_SETTEXT, (WPARAM) 0, (LPARAM) TEXT("") );
  1812.     SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP_TEXT ), WM_SETTEXT, 0, (LPARAM) TEXT("Member Of") );
  1813.     
  1814.     Lock();
  1815.     // Search for the given player
  1816.     CSIPlayer* pPlayer = FindPlayer( id );
  1817.     if( NULL == pPlayer )
  1818.     {
  1819.         hr = E_INVALIDARG;
  1820.         goto LCleanReturn;
  1821.     }
  1822.     // Set the selected item
  1823.     SelectListboxItem( GetDlgItem( hDlg, IDC_SI_PLAYERS ), pPlayer->id, pPlayer->strName );
  1824.     // Show the player name
  1825.     SendMessage( GetDlgItem( hDlg, IDC_SI_NAME ), WM_SETTEXT, 0, (LPARAM) pPlayer->strName );
  1826.     // Fill the description box
  1827.     PrintPlayerInfo( GetDlgItem( hDlg, IDC_SI_DESCRIPTION ), pPlayer );
  1828.     // Search for the player id in the group list
  1829.     UINT i;
  1830.     for( i=0; i < m_pGroups->Count(); i++ )
  1831.     {
  1832.         CSIGroup* pGroup = (CSIGroup*) m_pGroups->GetPtr( i );
  1833.         if( pGroup->IsMember( id ) )
  1834.         {
  1835.             DWORD dwIndex = SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_ADDSTRING, 0, (LPARAM) pGroup->strName );
  1836.             if( LB_ERR != dwIndex )
  1837.                 SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_SETITEMDATA, dwIndex, pGroup->id );
  1838.         }
  1839.     }
  1840.     
  1841.     hr = S_OK;
  1842. LCleanReturn:
  1843.     Unlock();
  1844.     return hr;
  1845. }
  1846. //-----------------------------------------------------------------------------
  1847. // Name: DisplayGroup()
  1848. // Desc: Display all stored information about the given group in the dialog UI
  1849. //-----------------------------------------------------------------------------
  1850. HRESULT CSessionInfo::DisplayGroup( DPNID id, HWND hDlg )
  1851. {
  1852.     HRESULT hr;
  1853.     // Set the icon
  1854. #ifndef UNDER_CE
  1855.     if( m_hPlayerIcon )
  1856.         SendMessage( GetDlgItem( hDlg, IDC_SI_NAME_ICON ), STM_SETICON, (LPARAM) m_hGroupIcon, 0 );
  1857. #endif // !UNDER_CE
  1858.     // Clear the dialog data
  1859.     SendMessage( GetDlgItem( hDlg, IDC_SI_NAME ), WM_SETTEXT, 0, (LPARAM) TEXT("") );
  1860.     SendMessage( GetDlgItem( hDlg, IDC_SI_PLAYERS ), LB_SETCURSEL, (WPARAM) -1, 0 );
  1861.     SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_RESETCONTENT, 0, 0 );
  1862.     SendMessage( GetDlgItem( hDlg, IDC_SI_DESCRIPTION ), WM_SETTEXT, 0, (LPARAM) TEXT("") );
  1863.     SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP_TEXT ), WM_SETTEXT, 0, (LPARAM) TEXT("Members") );
  1864.     
  1865.     Lock();
  1866.     // Search for the given group
  1867.     CSIGroup* pGroup = FindGroup( id );
  1868.     if( NULL == pGroup )
  1869.     {
  1870.         hr = E_INVALIDARG;
  1871.         goto LCleanReturn;
  1872.     }
  1873.     // Set the selected item
  1874.     SelectListboxItem( GetDlgItem( hDlg, IDC_SI_GROUPS ), pGroup->id, pGroup->strName );
  1875.     // Fill the description box
  1876.     PrintGroupInfo( GetDlgItem( hDlg, IDC_SI_DESCRIPTION ), pGroup );
  1877.     // Show the group name
  1878.     SendMessage( GetDlgItem( hDlg, IDC_SI_NAME ), WM_SETTEXT, 0, (LPARAM) pGroup->strName );
  1879.     // List member players
  1880.     UINT i;
  1881.     for( i=0; i < pGroup->pMembers->Count(); i++ )
  1882.     {
  1883.         DPNID* pID = (DPNID*) pGroup->pMembers->GetPtr( i );
  1884.         CSIPlayer* pPlayer = FindPlayer( *pID );
  1885.         if( pPlayer )
  1886.         {
  1887.             DWORD dwIndex;
  1888.             dwIndex = SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_ADDSTRING, 0, (LPARAM) pPlayer->strName );
  1889.             if( LB_ERR != dwIndex )
  1890.                 SendMessage( GetDlgItem( hDlg, IDC_SI_MEMBERSHIP ), LB_SETITEMDATA, dwIndex, pPlayer->id );
  1891.         }
  1892.     }
  1893.     hr = S_OK;
  1894. LCleanReturn:
  1895.     Unlock();
  1896.     return hr;
  1897. }
  1898. //-----------------------------------------------------------------------------
  1899. // Name: PrintPlayerInfo()
  1900. // Desc: Print the player description to the given edit box
  1901. //-----------------------------------------------------------------------------
  1902. HRESULT CSessionInfo::PrintPlayerInfo( HWND hWndEdit, CSIPlayer* pPlayer)
  1903. {
  1904.     TCHAR strBuf[51] = {0};
  1905.     // Validate parameters
  1906. #ifdef _DEBUG
  1907.     if( NULL == pPlayer )
  1908.         return E_INVALIDARG;
  1909. #endif // _DEBUG
  1910.     // Output DPNID info
  1911.     _sntprintf( strBuf, 50, TEXT("dpnid     0x%x (%u)1512"), pPlayer->id, pPlayer->id );
  1912.     strBuf[ 50 ] = TEXT('');
  1913.     SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strBuf );
  1914.     // Output flags
  1915.     ZeroMemory( strBuf, sizeof( strBuf ) );
  1916.     lstrcpy( strBuf, TEXT("flags     ") );
  1917.     if( pPlayer->bIsHost )
  1918.     {
  1919.         lstrcat( strBuf, TEXT("Host") );
  1920.     }
  1921.     if( m_dpnidLocal == pPlayer->id )
  1922.     {
  1923.         if( pPlayer->bIsHost )
  1924.             lstrcat( strBuf, TEXT(", ") );
  1925.         lstrcat( strBuf, TEXT("Local") );
  1926.     }
  1927.     lstrcat( strBuf, TEXT("1512") );
  1928.     SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strBuf );
  1929.     // If the player has an associated URL address, print the
  1930.     // encoded information
  1931.     if( pPlayer->strURL && lstrlen( pPlayer->strURL ) > lstrlen( TEXT("x-directplay:/") ) )
  1932.     {
  1933.         // Duplicate input string since it will be modified
  1934.         TCHAR* strCopy = _tcsdup( pPlayer->strURL + lstrlen( TEXT("x-directplay:/") ) );
  1935.         if( NULL == strCopy )
  1936.             return E_OUTOFMEMORY;
  1937.         TCHAR* strToken = NULL;
  1938.         strToken = _tcstok( strCopy, TEXT("=") );
  1939.         // While more URL information is encoded in input string
  1940.         while( strToken )
  1941.         {
  1942.             TCHAR strSpacing[] = TEXT("           ");
  1943.             // output key
  1944.             SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strToken );
  1945.             strSpacing[ 10 - lstrlen( strToken ) ] = L'';
  1946.             // insert column spacing
  1947.             SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strSpacing );
  1948.             // output value
  1949.             strToken = _tcstok( NULL, TEXT(";") );
  1950.             SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strToken );
  1951.             SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) TEXT("1512") );
  1952.             // find next key
  1953.             strToken = _tcstok( NULL, TEXT("=") );
  1954.         }
  1955.         // release resources
  1956.         if( strCopy )
  1957.             free( strCopy );
  1958.     }
  1959.     return S_OK;
  1960. }
  1961. //-----------------------------------------------------------------------------
  1962. // Name: PrintGroupInfo()
  1963. // Desc: Print the group description to the given edit box
  1964. //-----------------------------------------------------------------------------
  1965. HRESULT CSessionInfo::PrintGroupInfo( HWND hWndEdit, CSIGroup* pGroup )
  1966. {
  1967.     TCHAR strBuf[51] = {0};
  1968.     // Validate parameters
  1969. #ifdef _DEBUG
  1970.     if( NULL == pGroup )
  1971.         return E_INVALIDARG;
  1972. #endif // _DEBUG
  1973.     // Output DPNID info
  1974.     _sntprintf( strBuf, 50, TEXT("dpnid     0x%x (%u)1512"), pGroup->id, pGroup->id );
  1975.     strBuf[ 50 ] = TEXT('');
  1976.     SendMessage( hWndEdit, EM_REPLACESEL, FALSE, (LPARAM) strBuf );
  1977.     return S_OK;
  1978. }
  1979. //-----------------------------------------------------------------------------
  1980. // Name: CMessageList()
  1981. // Desc: Constructor
  1982. //-----------------------------------------------------------------------------
  1983. CMessageList::CMessageList() : m_dwStartIndex( 0 ), m_dwNumMessages( 0 )
  1984. {
  1985.     InitializeCriticalSection( &m_csLock );
  1986. }
  1987. //-----------------------------------------------------------------------------
  1988. // Name: ~CMessageList()
  1989. // Desc: Destructor
  1990. //-----------------------------------------------------------------------------
  1991. CMessageList::~CMessageList()
  1992. {
  1993.     DeleteCriticalSection( &m_csLock );
  1994. }
  1995. //-----------------------------------------------------------------------------
  1996. // Name: GetMessage()
  1997. // Desc: Returns the string pointer for the given message number
  1998. //-----------------------------------------------------------------------------
  1999. TCHAR* CMessageList::GetMessage( DWORD dwMessageNum )
  2000. {
  2001.     if( dwMessageNum >= m_dwNumMessages )
  2002.         return NULL;
  2003.     return m_rStrMessage[ ( m_dwStartIndex + dwMessageNum ) % SI_MAX_MESSAGES ];
  2004. }
  2005. //-----------------------------------------------------------------------------
  2006. // Name: AddMessage()
  2007. // Desc: Adds and time-stamp and copies the string to the end of the message
  2008. //       list. If the list is full, the oldest item is removed to make room
  2009. //-----------------------------------------------------------------------------
  2010. TCHAR* CMessageList::AddMessage( LPCTSTR strMessage )
  2011. {
  2012.     TCHAR* strDest = NULL;
  2013.  
  2014.     if( m_dwNumMessages < SI_MAX_MESSAGES )
  2015.     {
  2016.         // If there is still room in the array, increment the number of messages
  2017.         // and get the newly added string pointer
  2018.         strDest = GetMessage( m_dwNumMessages++ );
  2019.     }
  2020.     else
  2021.     {
  2022.         // Else, increment the start index and get the last element
  2023.         m_dwStartIndex++;
  2024.         strDest = GetMessage( SI_MAX_MESSAGES - 1 );
  2025.     }
  2026.     // Copy the string, adding a time stamp
  2027.     SYSTEMTIME sysTime;
  2028.     GetLocalTime( &sysTime );
  2029.     _sntprintf( strDest, 56, TEXT("[%02d:%02d:%02d]  "),
  2030.                sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
  2031.     _tcsncat( strDest, strMessage, 200 );
  2032.     strDest[ 255 ] = TEXT('');
  2033.     return strDest;
  2034. }
  2035. //-----------------------------------------------------------------------------
  2036. // Name: SelectListboxItem
  2037. // Desc: Search for and select the matching item in the list box
  2038. //-----------------------------------------------------------------------------
  2039. HRESULT CSessionInfo::SelectListboxItem( HWND hListBox, DWORD dwData, const TCHAR* strItem )
  2040. {
  2041.     int nIndex = -1;
  2042.     int nItemData = LB_ERR; 
  2043.     do 
  2044.     {
  2045.         // Find the string in the list
  2046.         nIndex = SendMessage( hListBox, LB_FINDSTRING, nIndex, (LPARAM) strItem );
  2047.         if( LB_ERR == nIndex )
  2048.             break;
  2049.         // Confirm the id number matches
  2050.         nItemData = SendMessage( hListBox, LB_GETITEMDATA, nIndex, 0 );
  2051.         if( LB_ERR == nItemData )
  2052.             break;
  2053.         // Match found, select the item and return
  2054.         if( (DWORD) nItemData == dwData )
  2055.         {
  2056.             SendMessage( hListBox, LB_SETCURSEL, nIndex, 0 );
  2057.             return S_OK;
  2058.         }
  2059.     }
  2060.     while( nIndex != LB_ERR );
  2061.     return E_FAIL;
  2062. }
  2063. //-----------------------------------------------------------------------------
  2064. // Name: SafeDestroyThread
  2065. // Desc: Signal the window close event and wait for the thread to shut down  
  2066. //-----------------------------------------------------------------------------
  2067. VOID CSessionInfo::SafeDestroyThread( LPHANDLE phThread )
  2068. {
  2069.     if( *phThread )
  2070.     {
  2071.         WaitForSingleObject( *phThread, INFINITE );
  2072.         CloseHandle( *phThread );
  2073.         *phThread = NULL;
  2074.     }
  2075. }