|
|
/*==========================================================================
* * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved. * * File: DPLApp.cpp * Content: DirectPlay Lobbied Application Functions *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 02/21/00 mjn Created * 03/22/2000 jtk Changed interface names * 04/18/2000 rmt Added additional parameter validation * 04/25/2000 rmt Bug #s 33138, 33145, 33150 * 04/26/00 mjn Removed dwTimeOut from Send() API call * 05/03/00 rmt DPL_UnRegister was not implemented!! * 05/08/00 rmt Bug #34301 - Add flag to SetAppAvail to allow for multiple connects * 06/15/00 rmt Bug #33617 - Must provide method for providing automatic launch of DirectPlay instances * 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched * rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns * rmt Bug #38755 - No way to specify player name in Connection Settings * rmt Bug #38758 - DPLOBBY8.H has incorrect comments * rmt Bug #38783 - pvUserApplicationContext is only partially implemented * rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs). * 07/14/2000 rmt Bug #39257 - LobbyClient::ReleaseApp returns E_OUTOFMEMORY when called when no one connected * rmt Bug #39487 - Remove WaitForConnect * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 08/15/2000 rmt Bug #42273 - DPLAY8: Samples sometimes get a DPNERR_ALREADYREGISTERED error. (Double connections) * 08/18/2000 rmt Bug #42751 - DPLOBBY8: Prohibit more than one lobby client or lobby app per process *@@END_MSINTERNAL * ***************************************************************************/
#include "dnlobbyi.h"
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
typedef STDMETHODIMP AppQueryInterface(IDirectPlay8LobbiedApplication *pInterface,REFIID ridd,PVOID *ppvObj); typedef STDMETHODIMP_(ULONG) AppAddRef(IDirectPlay8LobbiedApplication *pInterface); typedef STDMETHODIMP_(ULONG) AppRelease(IDirectPlay8LobbiedApplication *pInterface); typedef STDMETHODIMP AppRegisterMessageHandler(IDirectPlay8LobbiedApplication *pInterface,const PVOID pvUserContext,const PFNDPNMESSAGEHANDLER pfn, DPNHANDLE * const pdpnhConnection, const DWORD dwFlags); typedef STDMETHODIMP AppSend(IDirectPlay8LobbiedApplication *pInterface,const DPNHANDLE hTarget,BYTE *const pBuffer,const DWORD pBufferSize,const DWORD dwFlags); typedef STDMETHODIMP AppClose(IDirectPlay8LobbiedApplication *pInterface, const DWORD dwFlags); typedef STDMETHODIMP AppGetConnectionSettings(IDirectPlay8LobbiedApplication *pInterface, const DPNHANDLE hLobbyClient, DPL_CONNECTION_SETTINGS * const pdplSessionInfo, DWORD *pdwInfoSize, const DWORD dwFlags ); typedef STDMETHODIMP AppSetConnectionSettings(IDirectPlay8LobbiedApplication *pInterface, const DPNHANDLE hTarget, const DPL_CONNECTION_SETTINGS * const pdplSessionInfo, const DWORD dwFlags );
IDirectPlay8LobbiedApplicationVtbl DPL_8LobbiedApplicationVtbl = { (AppQueryInterface*) DPL_QueryInterface, (AppAddRef*) DPL_AddRef, (AppRelease*) DPL_Release, (AppRegisterMessageHandler*) DPL_RegisterMessageHandler, DPL_RegisterProgram, DPL_UnRegisterProgram, (AppSend*) DPL_Send, DPL_SetAppAvailable, DPL_UpdateStatus, (AppClose*) DPL_Close, (AppGetConnectionSettings*) DPL_GetConnectionSettings, (AppSetConnectionSettings*) DPL_SetConnectionSettings };
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_RegisterProgram"
STDMETHODIMP DPL_RegisterProgram(IDirectPlay8LobbiedApplication *pInterface, DPL_PROGRAM_DESC *const pdplProgramDesc, const DWORD dwFlags) { HRESULT hResultCode;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pdplProgramDesc [0x%p], dwFlags [0x%lx]", pInterface,pdplProgramDesc,dwFlags);
#ifndef DPNBUILD_NOPARAMVAL
DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
TRY { pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DPL_ValidateRegisterProgram( pInterface , pdplProgramDesc, dwFlags ) ) ) { DPFX(DPFPREP, 0, "Error validating register params hr=[0x%lx]", hResultCode ); DPF_RETURN( hResultCode ); } } } EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPFERR("Invalid object" ); DPF_RETURN(DPNERR_INVALIDOBJECT); } #endif // !DPNBUILD_NOPARAMVAL
hResultCode = DPLWriteProgramDesc(pdplProgramDesc);
DPF_RETURN(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_UnRegisterProgram"
STDMETHODIMP DPL_UnRegisterProgram(IDirectPlay8LobbiedApplication *pInterface, GUID *const pGuidApplication, const DWORD dwFlags) { HRESULT hResultCode;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pGuidApplication [0x%p], dwFlags [0x%lx]", pInterface,pGuidApplication,dwFlags);
#ifndef DPNBUILD_NOPARAMVAL
DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
TRY { pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DPL_ValidateUnRegisterProgram( pInterface , pGuidApplication, dwFlags ) ) ) { DPFX(DPFPREP, 0, "Error validating unregister params hr=[0x%lx]", hResultCode ); DPF_RETURN( hResultCode ); } } } EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPFERR("Invalid object" ); DPF_RETURN(DPNERR_INVALIDOBJECT); } #endif // !DPNBUILD_NOPARAMVAL
hResultCode = DPLDeleteProgramDesc( pGuidApplication );
DPF_RETURN(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_SetAppAvailable"
STDMETHODIMP DPL_SetAppAvailable(IDirectPlay8LobbiedApplication *pInterface, const BOOL fAvailable, const DWORD dwFlags ) { DIRECTPLAYLOBBYOBJECT *pdpLobbyObject; HRESULT hResultCode;
DPFX(DPFPREP, 3,"Parameters: (none)");
#ifndef DPNBUILD_NOPARAMVAL
TRY { #endif // !DPNBUILD_NOPARAMVAL
pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); #ifndef DPNBUILD_NOPARAMVAL
if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DPL_ValidateSetAppAvailable( pInterface, fAvailable, dwFlags ) ) ) { DPFX(DPFPREP, 0, "Error validating makeappavail params hr=[0x%lx]", hResultCode ); DPF_RETURN( hResultCode ); } }
// Ensure we've been initialized
if (pdpLobbyObject->pReceiveQueue == NULL) { DPFERR("Not initialized"); DPF_RETURN(DPNERR_UNINITIALIZED); } } EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPFERR("Invalid object" ); DPF_RETURN(DPNERR_INVALIDOBJECT); } #endif // !DPNBUILD_NOPARAMVAL
if( fAvailable ) { // Indicate that we are waiting
pdpLobbyObject->pReceiveQueue->MakeAvailable();
if( dwFlags & DPLAVAILABLE_ALLOWMULTIPLECONNECT ) { pdpLobbyObject->dwFlags |= DPL_OBJECT_FLAG_MULTICONNECT; } else { pdpLobbyObject->dwFlags &= ~(DPL_OBJECT_FLAG_MULTICONNECT); } } else { pdpLobbyObject->pReceiveQueue->MakeUnavailable(); }
hResultCode = DPN_OK;
DPF_RETURN(hResultCode); }
// DPL_UpdateStatus
//
// Send session status information to the lobby client. This should be called whenever
// the lobbied application connects to the game, fails to connect, disconnects, or is
// terminated (booted).
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_UpdateStatus"
STDMETHODIMP DPL_UpdateStatus(IDirectPlay8LobbiedApplication *pInterface, const DPNHANDLE hLobbyClient, const DWORD dwStatus, const DWORD dwFlags ) { HRESULT hResultCode; DIRECTPLAYLOBBYOBJECT *pdpLobbyObject; DPL_CONNECTION *pdplConnection; DPL_INTERNAL_MESSAGE_UPDATE_STATUS Msg; DPNHANDLE *hTargets = NULL; DWORD dwNumTargets = 0; DWORD dwTargetIndex = 0;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], hLobbyClient [0x%lx], dwStatus [0x%lx]", pInterface,hLobbyClient,dwStatus);
#ifndef DPNBUILD_NOPARAMVAL
TRY { #endif // !DPNBUILD_NOPARAMVAL
pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); #ifndef DPNBUILD_NOPARAMVAL
if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DPL_ValidateUpdateStatus( pInterface, hLobbyClient, dwStatus, dwFlags ) ) ) { DPFX(DPFPREP, 0, "Error validating updatestatus params hr=[0x%lx]", hResultCode ); DPF_RETURN( hResultCode ); } }
// Ensure we've been initialized
if (pdpLobbyObject->pReceiveQueue == NULL) { DPFERR("Not initialized"); DPF_RETURN(DPNERR_UNINITIALIZED); } } EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPFERR("Invalid object" ); DPF_RETURN(DPNERR_INVALIDOBJECT); } #endif // !DPNBUILD_NOPARAMVAL
Msg.dwMsgId = DPL_MSGID_INTERNAL_UPDATE_STATUS; Msg.dwStatus = dwStatus;
if( hLobbyClient == DPLHANDLE_ALLCONNECTIONS ) { dwNumTargets = 0;
// We need loop so if someone adds a connection during our run
// it gets added to our list
//
while( 1 ) { hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
if( hResultCode == DPNERR_BUFFERTOOSMALL ) { if( hTargets ) { delete [] hTargets; }
hTargets = new DPNHANDLE[dwNumTargets];
if( hTargets == NULL ) { DPFERR("Error allocating memory" ); hResultCode = DPNERR_OUTOFMEMORY; dwNumTargets = 0; goto EXIT_AND_CLEANUP; }
memset( hTargets, 0x00, sizeof(DPNHANDLE)*dwNumTargets);
continue; } else if( FAILED( hResultCode ) ) { DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode ); break; } else { break; } }
// Failed getting connection information
if( FAILED( hResultCode ) ) { if( hTargets ) { delete [] hTargets; hTargets = NULL; } dwNumTargets = 0; goto EXIT_AND_CLEANUP; }
} else { hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
if( hTargets == NULL ) { DPFERR("Error allocating memory" ); hResultCode = DPNERR_OUTOFMEMORY; dwNumTargets = 0; goto EXIT_AND_CLEANUP; }
dwNumTargets = 1; hTargets[0] = hLobbyClient; } for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ ) { if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hTargets[dwTargetIndex],&pdplConnection,TRUE)) != DPN_OK) { DPFERR("Invalid send target"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDHANDLE; goto EXIT_AND_CLEANUP; }
DNASSERT(pdplConnection->pSendQueue != NULL);
if (!pdplConnection->pSendQueue->IsReceiving()) { DPFERR("Other side is not listening"); hResultCode = DPNERR_INVALIDHANDLE; goto EXIT_AND_CLEANUP; }
hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(&Msg), sizeof(DPL_INTERNAL_MESSAGE_UPDATE_STATUS), INFINITE, DPL_MSGQ_MSGFLAGS_USER1, 0);
if( FAILED( hResultCode ) ) { DPFX(DPFPREP, 0, "Error sending to connection 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode ); } }
EXIT_AND_CLEANUP:
for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ ) { if( hTargets[dwTargetIndex] ) DPLConnectionRelease(pdpLobbyObject,hTargets[dwTargetIndex]); }
if( hTargets ) delete [] hTargets;
DPF_RETURN(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DPLAttemptLobbyConnection"
HRESULT DPLAttemptLobbyConnection(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject) { PTSTR pszCommandLine; TCHAR *c; DWORD dwCommandLineSize; TCHAR pszObjectName[(sizeof(DWORD)*2)*2 + 1 + 1]; DNHANDLE hSyncEvent; HRESULT hResultCode; DNHANDLE hFileMap; DPL_SHARED_CONNECT_BLOCK *pSharedBlock; DWORD dwError; DWORD dwReturnValue;
DPFX(DPFPREP, 3,"Parameters: (none)");
// Need a copy of the command line
dwCommandLineSize = (_tcslen(GetCommandLine()) + 1) * sizeof(TCHAR); if ((pszCommandLine = static_cast<PTSTR>(DNMalloc(dwCommandLineSize))) == NULL) { DPFERR("Allocating memory failed"); return(DPNERR_OUTOFMEMORY); } _tcscpy(pszCommandLine,GetCommandLine());
DPFX(DPFPREP, 5,"Got command line [%s]",pszCommandLine);
// Try to find Lobby Launch ID string
c = _tcsstr(pszCommandLine,DPL_ID_STR); if (c == NULL) { DNFree(pszCommandLine); return(DPNERR_GENERIC); } c += _tcslen(DPL_ID_STR); c--; // We are going to overwrite the '=' with a IDCHAR below
_tcsncpy(pszObjectName,c,(sizeof(DWORD)*2)*2 + 1); pszObjectName[(sizeof(DWORD)*2)*2 + 1] = _T('\0'); // Ensure null terminated
DPFX(DPFPREP, 5,"Got object name [%s]",pszObjectName);
DNFree(pszCommandLine);
// Try to open shared memory
*pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_FILEMAP; hFileMap = DNCreateFileMapping(INVALID_HANDLE_VALUE,(LPSECURITY_ATTRIBUTES) NULL, PAGE_READWRITE,0,sizeof(DPL_SHARED_CONNECT_BLOCK),pszObjectName); if (hFileMap == NULL) { DPFERR("CreateFileMapping() failed"); dwError = GetLastError(); DNASSERT(FALSE); return(DPNERR_GENERIC); }
// Ensure it existed already
dwError = GetLastError(); if (dwError != ERROR_ALREADY_EXISTS) { DPFERR("File mapping did not already exist"); // DNASSERT(FALSE);
DNCloseHandle(hFileMap); return(DPNERR_GENERIC); }
// Map file
pSharedBlock = reinterpret_cast<DPL_SHARED_CONNECT_BLOCK*>(MapViewOfFile(HANDLE_FROM_DNHANDLE(hFileMap),FILE_MAP_ALL_ACCESS,0,0,0)); if (pSharedBlock == NULL) { DPFERR("MapViewOfFile() failed"); dwError = GetLastError(); DNASSERT(FALSE); DNCloseHandle(hFileMap); return(DPNERR_GENERIC); }
// Try to open connection event
*pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_EVENT; hSyncEvent = DNOpenEvent(EVENT_MODIFY_STATE,FALSE,pszObjectName); if (hSyncEvent == NULL) { DPFERR("OpenEvent() failed"); dwError = GetLastError(); DNASSERT(FALSE); UnmapViewOfFile(pSharedBlock); DNCloseHandle(hFileMap); return(DPNERR_GENERIC); } DPFX(DPFPREP, 5,"Opened sync event");
DNResetEvent(pdpLobbyObject->hConnectEvent);
// Look for lobby launch -- set lobby launch value if connection is received
pdpLobbyObject->dwFlags |= DPL_OBJECT_FLAG_LOOKINGFORLOBBYLAUNCH;
// Make application available for connection by lobby client
DNASSERT(pdpLobbyObject->pReceiveQueue != NULL);
// Signal lobby client
pSharedBlock->dwPID = pdpLobbyObject->dwPID; DNSetEvent(hSyncEvent);
dwReturnValue = DNWaitForSingleObject(pdpLobbyObject->hConnectEvent,DPL_LOBBYLAUNCHED_CONNECT_TIMEOUT);
// Turn off the looking for lobby launch flag
pdpLobbyObject->dwFlags &= ~(DPL_OBJECT_FLAG_LOOKINGFORLOBBYLAUNCH);
if (dwReturnValue == WAIT_OBJECT_0) { hResultCode = DPN_OK; } else { hResultCode = DPNERR_TIMEDOUT; }
// Clean up
DNCloseHandle(hSyncEvent); UnmapViewOfFile(pSharedBlock); DNCloseHandle(hFileMap);
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
//------------------------------------------------------------------------
|