//----------------------------------------------------------------------------- // File: Lobby.cpp // // Desc: DP lobby related routines // // Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved. //----------------------------------------------------------------------------- #include "duel.h" #include "lobby.h" //----------------------------------------------------------------------------- // Definitions //----------------------------------------------------------------------------- #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } #define TIMERID 1 // Timer ID to use #define TIMERINTERVAL 250 // Timer interval //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- extern LPDIRECTPLAY4 g_pDP; // DirectPlay object pointer extern LPDPLCONNECTION g_pDPLConnection; // Connection settings extern LPDIRECTPLAYLOBBY3 g_pDPLobby; // Lobby object pointer extern BOOL g_bHostPlayer; // Flag indicating if we are hosting extern HWND g_hwndMain; // Main application window handle extern HINSTANCE g_hInst; // Application instance handle BOOL g_bLobbyMsgSupported; // Lobby messages are supported GUID g_guidPlayer; // This player in this session //----------------------------------------------------------------------------- // Name: DPLobbyRelease() // Desc: Wrapper for DirectPlayLobby Release API //----------------------------------------------------------------------------- HRESULT DPLobbyRelease() { // Cleanup lobby SAFE_DELETE_ARRAY( g_pDPLConnection ); SAFE_RELEASE( g_pDPLobby ); return S_OK; } //----------------------------------------------------------------------------- // Name: DoingLobbyMessages() // Desc: Return TRUE if connected to a lobby and messages are supported. //----------------------------------------------------------------------------- BOOL DoingLobbyMessages() { return( g_pDPLobby && g_bLobbyMsgSupported ); } //----------------------------------------------------------------------------- // Name: LobbyMessageInit() // Desc: Initialize lobby message processing. Must be done while a lobby // connection is open. //----------------------------------------------------------------------------- HRESULT LobbyMessageInit() { if( NULL ==g_pDPLobby ) // Not connected to a lobby return E_FAIL; g_bLobbyMsgSupported = FALSE; // Until we find out otherwise. // Find out if lobby messages are supported by the lobby DPLMSG_GETPROPERTY msgGetProp; ZeroMemory( &msgGetProp, sizeof(DPLMSG_GETPROPERTY) ); msgGetProp.dwType = DPLSYS_GETPROPERTY; msgGetProp.dwRequestID = 1; // guidPlayer is not used msgGetProp.guidPropertyTag = DPLPROPERTY_MessagesSupported; return g_pDPLobby->SendLobbyMessage( DPLMSG_STANDARD, 0, &msgGetProp, sizeof(DPLMSG_GETPROPERTY) ); } //----------------------------------------------------------------------------- // Name: LobbyMessageReceive() // Desc: Check for any lobby messages and handle them // There are two modes: // LMR_CONNECTIONSETTINGS - Waiting only for settings from a lobby // LMR_PROPERTIES - Handle property message responses //----------------------------------------------------------------------------- HRESULT LobbyMessageReceive( DWORD dwMode ) { HRESULT hr = NOERROR; LPVOID lpMsgBuffer = NULL; DWORD dwBufferSize = 0; DWORD dwRequiredSize; DWORD dwMsgFlags; if( NULL == g_pDPLobby ) // No lobby interface return DPERR_NOINTERFACE; while( SUCCEEDED(hr) ) // Get all queued messages { dwRequiredSize = dwBufferSize; hr = g_pDPLobby->ReceiveLobbyMessage( 0, 0, &dwMsgFlags, lpMsgBuffer, &dwRequiredSize ); if( hr == DPERR_BUFFERTOOSMALL ) // Alloc msg buffer and try again { if( NULL == lpMsgBuffer ) lpMsgBuffer = GlobalAllocPtr( GHND, dwRequiredSize ); else lpMsgBuffer = GlobalReAllocPtr( lpMsgBuffer, dwRequiredSize, 0 ); if( NULL == lpMsgBuffer) return DPERR_NOMEMORY; dwBufferSize = dwRequiredSize; hr = S_OK; } else if( SUCCEEDED(hr) && dwRequiredSize >= sizeof(DPLMSG_GENERIC) ) { // Decode the message // Are we just looking for the CONNECTIONSETTINGS msg? if( dwMode == LMR_CONNECTIONSETTINGS ) { if( (dwMsgFlags & DPLMSG_SYSTEM) && ((DPLMSG_GENERIC*)lpMsgBuffer)->dwType == DPLSYS_NEWCONNECTIONSETTINGS ) break; else TRACE(_T("Non CONNECTIONSETTINGS lobby message ignored\n")); } // Otherwise we handle only GetProperty responses else if( (dwMsgFlags & DPLMSG_STANDARD) && ((DPLMSG_GENERIC*)lpMsgBuffer)->dwType == DPLSYS_GETPROPERTYRESPONSE ) { DPLMSG_GETPROPERTYRESPONSE* lpMsgGPR = (DPLMSG_GETPROPERTYRESPONSE*)lpMsgBuffer; if( IsEqualGUID( lpMsgGPR->guidPropertyTag, DPLPROPERTY_MessagesSupported ) ) { if( (BOOL)lpMsgGPR->dwPropertyData[0] ) // Supported { // So request our player instance guid DPLMSG_GETPROPERTY msgGetProp; ZeroMemory(&msgGetProp, sizeof(DPLMSG_GETPROPERTY)); msgGetProp.dwType = DPLSYS_GETPROPERTY; msgGetProp.dwRequestID = 2; // guidPlayer is left NULL msgGetProp.guidPropertyTag = DPLPROPERTY_PlayerGuid; hr = g_pDPLobby->SendLobbyMessage( DPLMSG_STANDARD, 0, &msgGetProp, sizeof(DPLMSG_GETPROPERTY) ); hr = S_OK; // keep fetching messages } else // not supported so close up shop { TRACE(_T("Lobby Messages not supported\n")); DPLobbyRelease(); break; } } else if( IsEqualGUID( lpMsgGPR->guidPropertyTag, DPLPROPERTY_PlayerGuid ) ) { // Have our player guid, ready to send property msgs g_guidPlayer = ( (DPLDATA_PLAYERGUID*) &lpMsgGPR->dwPropertyData)->guidPlayer; g_bLobbyMsgSupported = TRUE; } } else TRACE(_T("Unrecognized lobby message ignored\n")); } } if( lpMsgBuffer ) GlobalFreePtr( lpMsgBuffer ); return hr; } //----------------------------------------------------------------------------- // Name: LobbyMessageSetProperty() // Desc: Send a SetProperty message //----------------------------------------------------------------------------- HRESULT LobbyMessageSetProperty( const GUID* pPropTagGUID, VOID* pData, DWORD dwDataSize ) { HRESULT hr; LPBYTE lpBuffer; LPDPLMSG_SETPROPERTY lpMsgSP; DWORD dwMsgSize; if( NULL == g_pDPLobby ) return DPERR_NOCONNECTION; if( NULL == g_bLobbyMsgSupported ) return DPERR_UNAVAILABLE; // Allocate and pack up the message // Property data starts at dwPropertyData[0] for the size calculation dwMsgSize = sizeof(DPLMSG_SETPROPERTY) - sizeof(DWORD) + dwDataSize; lpBuffer = (LPBYTE)GlobalAllocPtr(GHND, dwMsgSize); if( NULL == lpBuffer ) return (DPERR_NOMEMORY); lpMsgSP = (LPDPLMSG_SETPROPERTY)lpBuffer; lpMsgSP->dwType = DPLSYS_SETPROPERTY; lpMsgSP->dwRequestID = DPL_NOCONFIRMATION; lpMsgSP->guidPlayer = g_guidPlayer; // player property assumed lpMsgSP->guidPropertyTag = (*pPropTagGUID); lpMsgSP->dwDataSize = dwDataSize; memcpy( lpMsgSP->dwPropertyData, pData, dwDataSize ); hr = g_pDPLobby->SendLobbyMessage( DPLMSG_STANDARD, 0, lpBuffer, dwMsgSize ); GlobalFreePtr( lpBuffer ); return hr; }