Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7123 lines
196 KiB

/*==========================================================================
*
* Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
*
* File: Common.cpp
* Content: DNET common interface routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 07/21/99 mjn Created
* 12/23/99 mjn Hand all NameTable update sends from Host to worker thread
* 12/23/99 mjn Fixed use of Host and AllPlayers short cut pointers
* 12/28/99 mjn Moved Async Op stuff to Async.h
* 12/29/99 mjn Reformed DN_ASYNC_OP to use hParentOp instead of lpvUserContext
* 12/29/99 mjn Added Instance GUID generation in DN_Host
* 01/05/00 mjn Return DPNERR_NOINTERFACE if CoCreateInstance fails
* 01/06/00 mjn Moved NameTable stuff to NameTable.h
* 01/07/00 mjn Implemented DNSEND_NOCOPY flag in DN_SendTo
* 01/07/00 mjn Moved Misc Functions to DNMisc.h
* 01/08/00 mjn Implemented GetApplicationDesc
* 01/09/00 mjn Application Description stuff
* 01/10/00 mjn Implemented SetApplicationDesc
* 01/11/00 mjn Use CPackedBuffers instead of DN_ENUM_BUFFER_INFOs
* 01/13/00 mjn Removed DIRECTNETOBJECT from Pack/UnpackApplicationDesc
* 01/14/00 mjn Added pvUserContext to Host API call
* 01/14/00 mjn Removed pvUserContext from DN_NAMETABLE_ENTRY
* 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer
* 01/16/00 mjn Moved User callback stuff to User.h
* 01/18/00 mjn Implemented DNGROUP_AUTODESTRUCT
* 01/18/00 rmt Added calls into voice layer for Close
* 01/19/00 mjn Replaced DN_SYNC_EVENT with CSyncEvent
* 01/20/00 mjn Clean up NameTable operation list in DN_Close
* 01/23/00 mjn Added DN_DestroyPlayer and DNTerminateSession
* 01/28/00 mjn Added DN_ReturnBuffer
* 02/01/00 mjn Added DN_GetCaps, DN_SetCaps
* 02/01/00 mjn Implement Player/Group context values
* 02/09/00 mjn Implemented DNSEND_COMPLETEONPROCESS
* 02/15/00 mjn Implement INFO flags in SetInfo and return context in GetInfo
* 02/17/00 mjn Implemented GetPlayerContext and GetGroupContext
* 02/17/00 mjn Reordered parameters in EnumServiceProviders,EnumHosts,Connect,Host
* 02/18/00 mjn Converted DNADDRESS to IDirectPlayAddress8
* 03/17/00 rmt Moved caps funcs to caps.h/caps.cpp
* 03/23/00 mjn Set group context through CreateGroup
* mjn Set player context through Host and Connect
* mjn Implemented RegisterLobby()
* 03/24/00 mjn Release SP when EnumHost completes
* 03/25/00 rmt Added call into DPNSVR when host begins
* 04/04/00 rmt Added flag to disable calls to DPNSVR and flag to disable
* parameter validation
* 04/05/00 mjn Fixed DestroyClient API call
* 04/06/00 mjn Added DN_GetHostAddress()
* 04/07/00 mjn Prevent Initialize() API from being called twice
* mjn Ensure Host addresses have SP included
* mjn Fixed DN_GetHostAddress() to get address
* 04/09/00 mjn Convert DN_Host() and DN_Connect() to use CAsyncOp
* 04/10/00 mjn Fixed DN_Close() to use flags
* 04/11/00 mjn Use CAsyncOp for ENUMs
* mjn Moved ProcessEnumQuery and ProcessEnumResponse to EnumHosts.cpp
* mjn DNCancelEnum() uses CAsyncOp
* 04/12/00 mjn DNTerminateSession() cancels outstanding ENUMs
* mjn DN_Close() cancels ENUMs instead of DNTerminateSession
* mjn DN_Close() clears DN_OBJECT_FLAG_DISCONNECTING
* 04/13/00 rmt More parameter validation
* 04/14/00 mjn Default Host SP to Device SP if not specified
* mjn Crack LISTENs in DN_Host for DPNSVR
* 04/16/00 mjn DNSendMessage uses CAsyncOp
* 04/17/00 mjn DNCancelSend() uses CAsyncOp
* 04/17/00 mjn Fixed DN_EnumHosts to use Handle parent and SYNC operation
* mjn DN_Close tries to cancel SENDs and ENUMs
* 04/18/00 mjn CConnection tracks connection status better
* mjn Deinitialize HandleTable, and release addresses in DN_Close
* mjn Fixed DN_GetApplicationDesc to return correct size
* 04/19/00 mjn Changed DN_SendTo to accept a range of DPN_BUFFER_DESCs and a count
* mjn Shut down LISTENs earlier in Close sequence
* 04/20/00 mjn Convert ReceiveBuffers to CAsyncOp and reclaim at Close
* mjn DN_SendTo() may be invoked by IDirectPlay8Client::DN_Send()
* 04/23/00 mjn Added parameter to DNPerformChildSend()
* mjn Reimplemented SEND_COMPLETEONPROCESS
* 04/24/00 mjn Updated Group and Info operations to use CAsyncOp's
* 04/25/00 mjn Added DNCancelConnect to DN_CancelAsyncOperation
* 04/26/00 mjn Fixed DN_GetSendQueueInfo to use CAsyncOp's
* 04/26/00 mjn Removed DN_ASYNC_OP and related functions
* 04/27/00 mjn Cause DN_GetPlayerContext()/DN_GetGroupContext() to fail if disconnecting
* 04/28/00 mjn Allow a NULL Device Address in DN_Connect() - steal SP from Host Address
* mjn Save user connect data to be passed during CONNECT sequence
* mjn Prevent infinite loops in group SENDs
* 05/01/00 rmt Bug #33403 - Require DPNSESSION_CLIENT_SERVER mode in client/server mode
* 05/01/00 mjn Prevent unusable SPs from being enumerated.
* 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer()
* 05/04/00 mjn Clean up address list in DN_Host()
* 05/05/00 mjn Free pvConnectData in DN_Close()
* mjn Fixed leak in DN_GetHostAddress()
* 05/16/00 mjn Force return code from ASYNC DN_SendTo() to return DPNERR_PENDING
* mjn Better locking for User notifications
* 05/30/00 mjn Modified logic for group sends to target connected players only
* mjn ASSERT if operations cannot be cancelled in DN_Close()
* 05/31/00 mjn Added operation specific SYNC flags
* 05/31/00 mjn Prevent ALL_PLAYERS group from being enum'd in DN_EnumClientsAndGroups()
* mjn Skip invalid Host addresses
* 06/05/00 mjn Fixed DN_SendTo to handle some errors gracefully
* 06/19/00 mjn DN_Connect and DN_Host enumerate adapters if ALL_ADAPTERS specified
* 06/20/00 mjn Fixed DN_GetHostAddress() to extract host address from LISTENs
* mjn DOH! Forgot to change a line in DN_Host() so that LISTENs use enum'd adapter rather than ALL_ADAPTER
* 06/22/00 mjn Replace CConnection::MakeConnected() with SetStatus()
* 06/23/00 mjn Removed dwPriority from DN_SendTo()
* 06/24/00 mjn Added parent CONNECT AsyncOp to DN_Connect()
* mjn Return DPNERR_UNINITIALIZED from DN_Close() if not initialized (called twice)
* 06/25/00 mjn Added DNUpdateLobbyStatus(), update status for CONNECTED,DISCONNECTED
* mjn Set DirectNetObject as CONNECTED earlier in DN_Host()
* 06/26/00 mjn Replaced DPNADDCLIENTTOGROUP_SYNC DPNADDPLAYERTOGROUP_SYNC
* mjn Replaced DPNREMOVECLIENTFROMGROUP_SYNC with DPNREMOVEPLAYERFROMGROUP_SYNC
* mjn Fixed for() loop counter problem - nested counters used the same variable - DOH !
* 06/27/00 mjn Allow priorities to be specified to GetSendQueueInfo() API calls
* rmt Added abstraction for COM_Co(Un)Initialize
* mjn Removed ASSERT player not found in DN_GetPlayerContext()
* mjn Added DPNSEND_NONSEQUENTIAL flag to Send/SendTo
* mjn Allow mix-n-match of priorities in GetSendQueueInfo() API call
* 07/02/00 mjn Modified DN_SendTo() to use DNSendGroupMessage()
* 07/06/00 mjn Added missing completions for group sends
* mjn Fixed locking problem in CNameTable::MakeLocalPlayer,MakeHostPlayer,MakeAllPlayersGroup
* mjn Turned DPNSEND_NONSEQUENTIAL flag back on in DN_SendTo()
* mjn Use SP handle instead of interface
* 07/07/00 mjn Cleanup pNewHost on DirectNetObject at close
* 07/08/00 mjn Fixed CAsyncOp to contain m_bilinkParent
* 07/09/00 rmt Bug #38323 - RegisterLobby needs a DPNHANDLE parameter.
* 07/11/00 mjn Added NOLOOPBACK capability to group sends
* mjn Fixed DN_EnumHosts() to handle multiple adapters
* 07/12/00 mjn Copy user data on EnumHosts()
* 07/17/00 mjn Removed redundant SyncEvent->Reset() in DN_Initialize
* mjn Clear DN_OBJECT_FLAG_HOST_CONNECTED in DN_Close()
* mjn Check correct return value of DNSendGroupMessage() in DN_SendTo()
* 07/19/00 aarono Bug#39751 add CancelAsyncOperation flag support.
* 07/20/00 mjn Cleaned up DN_Connect()
* 07/21/00 RichGr IA64: Use %p format specifier for 32/64-bit pointers.
* 07/21/00 mjn Cleaned up DN_Close() to release connection object reference
* 07/23/00 mjn Moved assertion in DN_CanceAsyncOperation
* 07/25/00 mjn Fail DN_EnumHosts() if no valid device adapters exist
* 07/26/00 mjn Fix error codes returned from DN_Connect(),DN_GetSendQueueInfo(),DN_DestroyGroup()
* DN_AddClientToGroup(),DN_RemoveClientFromGroup(),DN_SetGroupInfo()
* DN_GetGroupInfo(),DN_EnumGroupMembers()
* mjn Fix DN_GetApplicationDesc() to always return buffer size
* 07/26/00 mjn Fixed locking problem with CAsyncOp::MakeChild()
* 07/28/00 mjn Revised DN_GetSendQueueInfo() to use queue info on CConnection objects
* mjn Cleaned up DN_GetPlayerContext() and DN_GetGroupContext()
* 07/29/00 mjn Better clean up of pending Connect()'s during Close()
* mjn Check user data size in DN_EnumHosts()
* mjn Added fUseCachedCaps to DN_SPEnsureLoaded()
* 07/30/00 mjn Replaced DN_NAMETABLE_PENDING_OP with CPendingDeletion
* 07/31/00 mjn Added hrReason to DNTerminateSession()
* mjn Added dwDestroyReason to DNHostDisconnect()
* mjn Cleaned up DN_TerminateSession()
* 08/03/00 rmt Bug #41244 - Wrong return codes -- part 2
* 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage()
* mjn Ensure cancelled operations don't proceed
* mjn Prevent hosting players from calling DN_EnumHosts()
* mjn Generate TERMINATE_SESSION notification for host player
* 08/06/00 mjn Added CWorkerJob
* 08/09/00 mjn Moved no-loop-back test in DN_SendTo()
* 08/15/00 rmt Bug #42506 - DPLAY8: LOBBY: Automatic connection settings not being sent
* 08/15/00 mjn Remapped DPNERR_INVALIDENDPOINT from DPNERR_INVALIDPLAYER to DPNERR_NOCONNECTION in DN_SendTo()
* mjn Addef hProtocol to DNRegisterWithDPNSVR() and removed registration from DN_Host()
* 08/16/00 mjn Return DPNERR_INVALIDHOSTADDRESS from DN_EnumHosts() if host address is invalid
* 08/20/00 mjn Removed fUseCachedCaps from DN_SPEnsureLoaded()
* 08/23/00 mjn Flag DirectNetObject as registered with DPNSVR
* 08/24/00 mjn Replace DN_NAMETABLE_OP with CNameTableOp
* 08/29/00 mjn Remap DPNERR_INVALIDPLAYER to DPNERR_CONNECTIONLOST in DN_SendTo()
* 09/01/00 masonb Modified DN_Close to call CloseHandle on hWorkerThread
* 09/04/00 mjn Added CApplicationDesc
* 09/05/00 mjn Set NameTable DPNID mask when hosting
* 09/06/00 mjn Fixed register with DPNSVR problem
* 09/13/00 rmt Bug #44625 - DPVOICE: Multihomed machines are not always enumerable
* Moved registration for DPNSVR into ListenComplete
* 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
* 10/11/00 mjn Take locks for CNameTableEntry::PackInfo()
* 10/12/00 mjn Set async handle completion after succeeding in DN_EnumHosts()
* 10/17/00 mjn Fixed clean up for unreachable players
* 11/16/00 mjn Fixed uninitialized variable problem in DN_CancelAsyncOperation()
* 12/11/00 mjn Allow API calls after TERMINATE_SESSION without calling Close() first
* 01/09/01 mjn CancelAsyncOperations() returns DPNERR_CANNOTCANCEL if operation doesn't allow it
* 01/10/01 mjn DN_Connect() cancels ENUMs with DPNERR_CONNECTING
* 01/22/01 mjn Check closing instead of disconnecting in getting player/group context and info
* mjn Fixed debug text
* 02/12/01 mjn GetPlayerContext() and GetGroupContext() return DPNERR_NOTREADY if context not yet set
* 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
* mjn Use cached enum frame size
* 04/11/01 mjn Save hosting flag for query for addressing when listening
* 05/02/01 vpo Whistler 380319: "DPLAY8: CORE: Starts listening before creating local nametable entry"
* 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes"
* 05/14/01 mjn Fix client error handling when completing connect if server not available
* 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect
* 06/03/01 mjn Clean up connect parent in DNTerminateSession()
* 06/12/01 mjn Ensure DN_Initialize() returns non-DPN_OK value when creating new CSyncEvent or thread fails
* 06/25/01 mjn Unregister from DPNSVR in DNTerminateSession()
* 07/24/01 mjn Added DPNBUILD_NOPARAMVAL compile flag
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject,
IDirectPlay8Address **const prgpAddress,
DWORD *const pcAddress);
//
// Store the user-supplied message handler and context value for call backs
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Initialize"
STDMETHODIMP DN_Initialize(PVOID pInterface,
PVOID const pvUserContext,
const PFNDPNMESSAGEHANDLER pfn,
const DWORD dwFlags)
{
HRESULT hResultCode = DPN_OK;
DIRECTNETOBJECT *pdnObject;
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
CSyncEvent *pThreadPoolSyncEvent;
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
CSyncEvent *pProtocolSyncEvent;
BOOL fApplicationDesc;
BOOL fHandleTable;
BOOL fProtocol;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvUserContext [0x%p], pfn [0x%p], dwFlags [0x%lx]",
pInterface,pvUserContext,pfn,dwFlags);
#ifndef DPNBUILD_NOPARAMVAL
if( !IsValidDirectPlay8Object( pInterface ) )
{
DPFERR("Invalid object specified" );
DPF_RETURN( DPNERR_INVALIDOBJECT );
}
if( pfn == NULL )
{
DPFERR("You must specify a callback function" );
DPF_RETURN( DPNERR_INVALIDPARAM );
}
if( dwFlags & ~(DPNINITIALIZE_DISABLEPARAMVAL
#ifdef DIRECTPLAYDIRECTX9
| DPNINITIALIZE_HINT_LANSESSION
#endif // DIRECTPLAYDIRECTX9
) )
{
DPFERR("Invalid flags specified" );
DPF_RETURN( DPNERR_INVALIDFLAGS );
}
#endif // !DPNBUILD_NOPARAMVAL
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
// Ensure not already initialized
if (pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)
{
DPFERR("Initialize has already been called" );
DPF_RETURN(DPNERR_ALREADYINITIALIZED);
}
#ifndef DPNBUILD_NOPARAMVAL
// Disable parameter validation flag if DPNINITIALIZE_DISABLEPARAMVAL
// is specified
if( dwFlags & DPNINITIALIZE_DISABLEPARAMVAL )
{
pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_PARAMVALIDATION);
}
#endif // !DPNBUILD_NOPARAMVAL
fApplicationDesc = FALSE;
fHandleTable = FALSE;
fProtocol = FALSE;
pProtocolSyncEvent = NULL;
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
pThreadPoolSyncEvent = NULL;
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// Lock DirectNetObject in case someone's trying something funny
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
//
// Initialize ApplicationDescription
//
if ((hResultCode = pdnObject->ApplicationDesc.Initialize()) != DPN_OK)
{
DPFERR("Could not initialize ApplicationDesc");
DisplayDNError(0,hResultCode);
goto Failure;
}
fApplicationDesc = TRUE;
//
// Initialize HandleTable
//
if ((hResultCode = pdnObject->HandleTable.Initialize()) != DPN_OK)
{
DPFERR("Could not initialize HandleTable");
DisplayDNError(0,hResultCode);
goto Failure;
}
fHandleTable = TRUE;
//
// The threadpool interface always exists for the life of the object.
//
DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
#ifndef DPNBUILD_ONLYONETHREAD
//
// Have the thread pool object try to start at least one thread. Other
// components may request more, but we just need a single worker.
//
// We'll ignore failure, because we could still operate in DoWork mode even
// when starting the thread fails. It most likely failed because the user
// is in that mode already anyway (DPNERR_ALREADYINITIALIZED).
//
hResultCode = IDirectPlay8ThreadPoolWork_RequestTotalThreadCount(pdnObject->pIDPThreadPoolWork, 1, 0);
if (hResultCode != DPN_OK)
{
if (hResultCode != DPNERR_ALREADYINITIALIZED)
{
DPFX(DPFPREP, 0, "Requesting a single thread failed (err = 0x%lx)!", hResultCode);
}
//
// Continue...
//
}
#endif // ! DPNBUILD_ONLYONETHREAD
//
// Initialize protocol and create shut-down event
//
DNASSERT(pdnObject->lProtocolRefCount == 0);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
if ((hResultCode = DNPProtocolInitialize( pdnObject->pdnProtocolData, pdnObject, &g_ProtocolVTBL,
pdnObject->pIDPThreadPoolWork, (dwFlags
#ifdef DIRECTPLAYDIRECTX9
& DPNINITIALIZE_HINT_LANSESSION
#endif // DIRECTPLAYDIRECTX9
))) != DPN_OK)
{
hResultCode = DPNERR_OUTOFMEMORY;
DPFERR("DNPProtocolInitialize() failed");
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pdnObject->lProtocolRefCount = 1;
fProtocol = TRUE;
DNASSERT( pdnObject->hProtocolShutdownEvent == NULL );
if ((hResultCode = SyncEventNew(pdnObject,&pProtocolSyncEvent)) != DPN_OK)
{
DPFERR("Could not get protocol shutdown event");
DisplayDNError(0,hResultCode);
goto Failure;
}
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
if ((hResultCode = SyncEventNew(pdnObject,&pThreadPoolSyncEvent)) != DPN_OK)
{
DPFERR("Could not create threadpool shutdown event");
DisplayDNError(0,hResultCode);
goto Failure;
}
pdnObject->lThreadPoolRefCount = 1;
pdnObject->ThreadPoolShutDownEvent = pThreadPoolSyncEvent;
pThreadPoolSyncEvent = NULL;
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
pdnObject->hProtocolShutdownEvent = pProtocolSyncEvent;
pProtocolSyncEvent = NULL;
pdnObject->pfnDnUserMessageHandler = pfn;
pdnObject->pvUserContext = pvUserContext;
pdnObject->dwFlags |= DN_OBJECT_FLAG_INITIALIZED;
pdnObject->dwMaxFrameSize = 0;
hResultCode = DPN_OK;
Exit:
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (fApplicationDesc)
{
pdnObject->ApplicationDesc.Deinitialize();
}
if (fHandleTable)
{
pdnObject->HandleTable.Deinitialize();
}
if (pProtocolSyncEvent)
{
pProtocolSyncEvent->ReturnSelfToPool();
pProtocolSyncEvent = NULL;
}
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
if (pThreadPoolSyncEvent)
{
pThreadPoolSyncEvent->ReturnSelfToPool();
pThreadPoolSyncEvent = NULL;
}
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
if (fProtocol)
{
DNProtocolRelease(pdnObject);
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Close"
STDMETHODIMP DN_Close(PVOID pInterface,const DWORD dwFlags)
{
HRESULT hResultCode = DPN_OK;
DIRECTNETOBJECT *pdnObject;
CBilink *pBilink;
CAsyncOp *pAsyncOp;
CConnection *pConnection;
CPendingDeletion *pPending;
CServiceProvider *pSP;
BOOL fWaitForEvent;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dwFlags [0x%lx]",pInterface,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( !IsValidDirectPlay8Object( pInterface ) )
{
DPFERR("Invalid object specified " );
DPF_RETURN( DPNERR_INVALIDOBJECT );
}
#ifdef DIRECTPLAYDIRECTX9
if( dwFlags & ~(DPNCLOSE_IMMEDIATE) )
#else
if (dwFlags != 0)
#endif
{
DPFERR("Invalid flags");
DPF_RETURN( DPNERR_INVALIDFLAGS );
}
}
#endif // !DPNBUILD_NOPARAMVAL
pAsyncOp = NULL;
pConnection = NULL;
pSP = NULL;
//
// Ensure this isn't being called on a callback thread
//
DNEnterCriticalSection(&pdnObject->csCallbackThreads);
pBilink = pdnObject->m_bilinkCallbackThreads.GetNext();
while (pBilink != &pdnObject->m_bilinkCallbackThreads)
{
if ((CONTAINING_CALLBACKTHREAD(pBilink))->IsCurrentThread())
{
DNLeaveCriticalSection(&pdnObject->csCallbackThreads);
DPFERR("Cannot call Close on a callback thread");
hResultCode = DPNERR_NOTALLOWED;
goto Failure;
}
pBilink = pBilink->GetNext();
}
DNLeaveCriticalSection(&pdnObject->csCallbackThreads);
//
// Flag as closing. Make sure this hasn't already been called.
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
// Ensure already initialized
if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFX(DPFPREP, 1, "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFERR("Already closing" );
hResultCode = DPNERR_ALREADYCLOSING;
goto Failure;
}
pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING;
#ifdef DIRECTPLAYDIRECTX9
if (dwFlags & DPNCLOSE_IMMEDIATE)
{
//
// We will set DN_OBJECT_FLAG_CLOSING_IMMEDIATE so that any disconnects from now on will be immediate
//
pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING_IMMEDIATE;
}
#endif
if (pdnObject->dwLockCount == 0)
{
fWaitForEvent = FALSE;
}
else
{
fWaitForEvent = TRUE;
}
pdnObject->dwClosingThreadID = GetCurrentThreadId();
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifdef DBG
{
CNameTableEntry *pLocalPlayer;
if (pdnObject->NameTable.GetLocalPlayerRef(&pLocalPlayer) == DPN_OK)
{
DPFX(DPFPREP, 0,"Local player was [0x%lx]",pLocalPlayer->GetDPNID());
pLocalPlayer->Release();
}
}
#endif // DBG
//
// If there are operations underway, we will wait for them to complete and release the lock count
//
if (fWaitForEvent)
{
hResultCode = IDirectPlay8ThreadPoolWork_WaitWhileWorking(pdnObject->pIDPThreadPoolWork,
HANDLE_FROM_DNHANDLE(pdnObject->hLockEvent),
0);
DNASSERT(hResultCode == DPN_OK);
}
//
// Cancel connect
//
DPFX(DPFPREP, 3,"Checking CONNECT");
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pAsyncOp = pdnObject->pConnectParent;
pdnObject->pConnectParent = NULL;
pSP = pdnObject->pConnectSP;
pdnObject->pConnectSP = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp)
{
pAsyncOp->Lock();
pConnection = pAsyncOp->GetConnection();
pAsyncOp->SetConnection( NULL );
pAsyncOp->Unlock();
DPFX(DPFPREP, 3,"Canceling CONNECT");
hResultCode = DNCancelChildren(pdnObject,pAsyncOp);
DPFX(DPFPREP, 3,"Canceling CONNECT returned [0x%lx]",hResultCode);
pAsyncOp->Release();
pAsyncOp = NULL;
if (pConnection)
{
pConnection->Disconnect();
pConnection->Release();
pConnection = NULL;
}
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
//
// Remove outstanding ENUMs, SENDs, RECEIVE_BUFFERs
//
DPFX(DPFPREP, 3,"Canceling outstanding operations");
hResultCode = DNCancelActiveCommands(pdnObject,( DN_CANCEL_FLAG_ENUM_QUERY
| DN_CANCEL_FLAG_ENUM_RESPONSE
| DN_CANCEL_FLAG_USER_SEND
| DN_CANCEL_FLAG_INTERNAL_SEND
| DN_CANCEL_FLAG_RECEIVE_BUFFER
#ifndef DPNBUILD_NOMULTICAST
| DN_CANCEL_FLAG_JOIN
#endif // ! DPNBUILD_NOMULTICAST
),
NULL,
FALSE,
0);
DPFX(DPFPREP, 3,"Canceling outstanding operations returned [0x%lx]",hResultCode);
//
// Cancel any REQUESTs
//
DPFX(DPFPREP, 3,"Canceling requests");
hResultCode = DNCancelRequestCommands(pdnObject);
DPFX(DPFPREP, 3,"Canceling requests returned [0x%lx]",hResultCode);
#ifndef DPNBUILD_NOMULTICAST
//
// Disconnect from multicast group
//
DPFX(DPFPREP, 3,"Disconnecting from multicast group");
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pBilink = pdnObject->m_bilinkMulticast.GetNext();
while (pBilink != &pdnObject->m_bilinkMulticast)
{
pConnection = CONTAINING_OBJECT(pBilink,CConnection,m_bilinkMulticast);
pConnection->m_bilinkMulticast.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pConnection->Disconnect();
pConnection->Release();
pConnection = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pBilink = pdnObject->m_bilinkMulticast.GetNext();
}
if (pdnObject->pMulticastSend)
{
pConnection = pdnObject->pMulticastSend;
pdnObject->pMulticastSend = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnection)
{
pConnection->Disconnect();
pConnection->Release();
pConnection = NULL;
}
DNASSERT(pConnection == NULL);
#endif // DPNBUILD_NOMULTICAST
//
// Terminate session. This will remove all players from the NameTable
//
DPFX(DPFPREP, 3,"Terminate Session");
if ((hResultCode = DNTerminateSession(pdnObject,DPN_OK)) != DPN_OK)
{
DPFERR("Could not terminate session");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
}
//
// Disconnect any indicated connections
//
DNEnterCriticalSection(&pdnObject->csConnectionList);
while (pdnObject->m_bilinkIndicated.GetNext() != &pdnObject->m_bilinkIndicated)
{
pConnection = CONTAINING_OBJECT(pdnObject->m_bilinkIndicated.GetNext(),CConnection,m_bilinkIndicated);
pConnection->m_bilinkIndicated.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csConnectionList);
DNASSERT(pConnection->GetDPNID() == 0);
pConnection->Disconnect();
pConnection->Release();
pConnection = NULL;
DNEnterCriticalSection(&pdnObject->csConnectionList);
}
DNLeaveCriticalSection(&pdnObject->csConnectionList);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
//
// Release SP's
//
DPFX(DPFPREP, 3,"Releasing SPs");
DN_SPReleaseAll(pdnObject);
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
//
// Shut down protocol
//
DPFX(DPFPREP, 3,"Shutting down Protocol");
DNProtocolRelease(pdnObject);
pdnObject->hProtocolShutdownEvent->WaitForEvent();
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
if ((hResultCode = DNPProtocolShutdown(pdnObject->pdnProtocolData)) != DPN_OK)
{
DPFERR("Could not shut down Protocol Layer !");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
}
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pdnObject->hProtocolShutdownEvent->ReturnSelfToPool();
pdnObject->hProtocolShutdownEvent = NULL;
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// Wait for thread pool to be done
//
DNThreadPoolRelease(pdnObject);
pdnObject->ThreadPoolShutDownEvent->WaitForEvent();
pdnObject->ThreadPoolShutDownEvent->ReturnSelfToPool();
pdnObject->ThreadPoolShutDownEvent = NULL;
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// The threadpool interface always exists for the life of the object.
//
DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
//
// Deinitialize HandleTable
//
DPFX(DPFPREP, 3,"Deinitializing HandleTable");
pdnObject->HandleTable.Deinitialize();
//
// Reset NameTable
//
DPFX(DPFPREP, 3,"Resetting NameTable");
pdnObject->NameTable.ResetNameTable();
//
// Deinitialize ApplicationDescription
//
DPFX(DPFPREP, 3,"Deinitializing ApplicationDesc");
pdnObject->ApplicationDesc.Deinitialize();
//
// Any pending NameTable operations
//
pBilink = pdnObject->m_bilinkPendingDeletions.GetNext();
while (pBilink != &pdnObject->m_bilinkPendingDeletions)
{
pPending = CONTAINING_OBJECT(pBilink,CPendingDeletion,m_bilinkPendingDeletions);
pBilink = pBilink->GetNext();
pPending->m_bilinkPendingDeletions.RemoveFromList();
pPending->ReturnSelfToPool();
pPending = NULL;
}
//
// Misc Clean Up
//
if (pdnObject->pIDP8ADevice)
{
IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
pdnObject->pIDP8ADevice = NULL;
}
if (pdnObject->pvConnectData)
{
DNFree(pdnObject->pvConnectData);
pdnObject->pvConnectData = NULL;
pdnObject->dwConnectDataSize = 0;
}
if( pdnObject->pConnectAddress )
{
IDirectPlay8Address_Release( pdnObject->pConnectAddress );
pdnObject->pConnectAddress = NULL;
}
#ifndef DPNBUILD_NOVOICE
if( pdnObject->pTargetList )
{
delete [] pdnObject->pTargetList;
pdnObject->pTargetList = NULL;
}
if( pdnObject->pExpandedTargetList )
{
delete [] pdnObject->pExpandedTargetList;
pdnObject->pExpandedTargetList = NULL;
}
#endif // !DPNBUILD_NOVOICE
#ifndef DPNBUILD_NOLOBBY
pdnObject->dpnhLobbyConnection = NULL;
// Release our hold on the lobbiedapplication
if( pdnObject->pIDP8LobbiedApplication)
{
IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication);
pdnObject->pIDP8LobbiedApplication = NULL;
}
#endif // ! DPNBUILD_NOLOBBY
//
// Reset DirectNet object flag
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~( DN_OBJECT_FLAG_INITIALIZED
| DN_OBJECT_FLAG_CLOSING
// | DN_OBJECT_FLAG_DISCONNECTING
// | DN_OBJECT_FLAG_HOST_CONNECTED
| DN_OBJECT_FLAG_LOCALHOST ));
pdnObject->dwMaxFrameSize = 0;
pdnObject->dwClosingThreadID = 0;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
Exit:
DNASSERT( pAsyncOp == NULL );
DNASSERT( pConnection == NULL );
DNASSERT( pSP == NULL );
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
goto Exit;
}
//
// Enumerate SP's if no SPGUID supplied, or SP Adapters if an SPGUID is supplied
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumServiceProviders"
STDMETHODIMP DN_EnumServiceProviders( PVOID pInterface,
const GUID *const pguidServiceProvider,
const GUID *const pguidApplication,
DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer,
DWORD *const pcbEnumData,
DWORD *const pcReturned,
const DWORD dwFlags )
{
#if ((defined(DPNBUILD_ONLYONEADAPTER)) || (defined(DPNBUILD_ONLYONESP)))
DPFX(DPFPREP, 0, "Enumerating service providers or their adapters is not supported!");
return DPNERR_UNSUPPORTED;
#else // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
HRESULT hResultCode;
PDIRECTNETOBJECT pdnObject;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pguidServiceProvider [0x%p], pguidApplication [0x%p], pSPInfoBuffer [0x%p], pcbEnumData [0x%p], pcReturned [0x%p], dwFlags [0x%lx]",
pInterface,pguidServiceProvider,pguidApplication,pSPInfoBuffer,pcbEnumData,pcReturned,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateEnumServiceProviders( pInterface, pguidServiceProvider, pguidApplication,
pSPInfoBuffer, pcbEnumData, pcReturned, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN(hResultCode);
}
}
#endif // DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DPFERR( "Object is not initialized" );
DPF_RETURN( DPNERR_UNINITIALIZED );
}
if (pguidServiceProvider == NULL) // Enumerate all service providers
{
#ifdef DPNBUILD_ONLYONESP
DPFX(DPFPREP, 0, "Enumerating service providers not supported!");
hResultCode = DPNERR_UNSUPPORTED;
#else // ! DPNBUILD_ONLYONESP
hResultCode = DN_EnumSP( pdnObject,
dwFlags,
#ifndef DPNBUILD_LIBINTERFACE
pguidApplication,
#endif // ! DPNBUILD_LIBINTERFACE
pSPInfoBuffer,
pcbEnumData,
pcReturned);
#endif // ! DPNBUILD_ONLYONESP
}
else // Service provider specified - enumerate adaptors
{
#ifdef DPNBUILD_ONLYONEADAPTER
DPFX(DPFPREP, 0, "Enumerating devices not supported!");
hResultCode = DPNERR_UNSUPPORTED;
#else // ! DPNBUILD_ONLYONEADAPTER
hResultCode = DN_EnumAdapters( pdnObject,
dwFlags,
pguidServiceProvider,
#ifndef DPNBUILD_LIBINTERFACE
pguidApplication,
#endif // ! DPNBUILD_LIBINTERFACE
pSPInfoBuffer,
pcbEnumData,
pcReturned);
#endif // ! DPNBUILD_ONLYONEADAPTER
}
DPFX(DPFPREP, 3,"Set: *pcbEnumData [%ld], *pcReturned [%ld]",*pcbEnumData,*pcReturned);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
#endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
}
//
// Cancel an outstanding Async Operation. hAsyncHandle is the operation handle returned when
// the operation was initiated.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_CancelAsyncOperation"
STDMETHODIMP DN_CancelAsyncOperation(PVOID pvInterface,
const DPNHANDLE hAsyncOp,
const DWORD dwFlags)
{
HRESULT hResultCode;
CNameTableEntry *pNTEntry;
CConnection *pConnection;
CAsyncOp *pHandleParent;
CAsyncOp *pAsyncOp;
DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pvInterface [0x%p], hAsyncOp [0x%lx], dwFlags [0x%lx]",
pvInterface,hAsyncOp,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pvInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateCancelAsyncOperation( pvInterface, hAsyncOp, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DPFERR( "Object is not initialized" );
DPF_RETURN( DPNERR_UNINITIALIZED );
}
pNTEntry = NULL;
pConnection = NULL;
pAsyncOp = NULL;
pHandleParent = NULL;
//
// If hAsyncOp is specified and it's not supposed to be a player ID, we will cancel the
// operation it represents. Otherwise, we will rely on the flags to determine which operations
// to cancel.
//
if ((hAsyncOp) && (! (dwFlags & DPNCANCEL_PLAYER_SENDS)))
{
//
// Cancel single operation
//
pdnObject->HandleTable.Lock();
if ((hResultCode = pdnObject->HandleTable.Find(hAsyncOp,(PVOID*)&pHandleParent)) != DPN_OK)
{
pdnObject->HandleTable.Unlock();
DPFERR("Invalid USER Handle specified");
hResultCode = DPNERR_INVALIDHANDLE;
goto Failure;
}
else
{
pHandleParent->AddRef();
pdnObject->HandleTable.Unlock();
}
if ( pHandleParent->GetOpType() != ASYNC_OP_USER_HANDLE )
{
DPFERR("Invalid USER Handle specified");
hResultCode = DPNERR_INVALIDHANDLE;
goto Failure;
}
//
// Some operations may be marked as CANNOT_CANCEL. Return DPNERR_CANNOTCANCEL for these
//
if ( pHandleParent->IsCannotCancel() )
{
DPFERR("Operation not allowed to be cancelled");
hResultCode = DPNERR_CANNOTCANCEL;
goto Failure;
}
hResultCode = DNCancelChildren(pdnObject,pHandleParent);
pHandleParent->Release();
pHandleParent = NULL;
}
else
{
//
// Cancel many operations based on flags
//
DWORD dwInternalFlags;
HRESULT hr;
//
// Re-map flags
//
dwInternalFlags = 0;
if (dwFlags & DPNCANCEL_ALL_OPERATIONS)
{
#ifdef DPNBUILD_NOMULTICAST
dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND );
#else // ! DPNBUILD_NOMULTICAST
dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND | DN_CANCEL_FLAG_JOIN );
#endif // ! DPNBUILD_NOMULTICAST
}
else if (dwFlags & DPNCANCEL_CONNECT)
{
dwInternalFlags = DN_CANCEL_FLAG_CONNECT;
}
else if (dwFlags & DPNCANCEL_ENUM)
{
dwInternalFlags = DN_CANCEL_FLAG_ENUM_QUERY;
}
else if (dwFlags & DPNCANCEL_SEND)
{
dwInternalFlags = DN_CANCEL_FLAG_USER_SEND;
}
#ifndef DPNBUILD_NOMULTICAST
else if (dwFlags & DPNCANCEL_JOIN)
{
dwInternalFlags = DN_CANCEL_FLAG_JOIN;
}
#endif // ! DPNBUILD_NOMULTICAST
#ifdef DIRECTPLAYDIRECTX9
else if (dwFlags & DPNCANCEL_PLAYER_SENDS)
{
//
// If the DPNCANCEL_PLAYER_SENDS flag is specified, then hAsyncOp is actually
// a player ID (except Client, where it must be 0, and it means the host player).
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)
{
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef(&pNTEntry)) != DPN_OK)
{
DPFERR("Unable to find host player");
hResultCode = DPNERR_NOCONNECTION;
goto Failure;
}
}
else
{
if ((hResultCode = pdnObject->NameTable.FindEntry((DPNID) hAsyncOp,&pNTEntry)) != DPN_OK)
{
DPFERR("Unable to find specified player");
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if (pNTEntry->IsGroup())
{
DPFERR("Specified ID is not a player");
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
}
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
{
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
//
// Re-map flags.
//
dwInternalFlags = DN_CANCEL_FLAG_USER_SEND;
if (dwFlags & (DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH | DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL | DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW))
{
if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH))
{
dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI;
}
if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL))
{
dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI;
}
if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW))
{
dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI;
}
//
// We should have set at least one of the negation flags.
//
DNASSERT(dwInternalFlags & (DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI | DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI | DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI));
}
}
#endif
else
{
DNASSERT(FALSE); // Should never get here
}
DPFX(DPFPREP, 3,"Re-mapped internal flags [0x%lx]",dwInternalFlags);
//
// Pre-set error code
hResultCode = DPN_OK;
//
// To cancel a CONNECT, look at the DirectNetObject
//
if (dwInternalFlags & DN_CANCEL_FLAG_CONNECT)
{
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pConnectParent)
{
if (pdnObject->pConnectParent->IsChild())
{
DNASSERT(pdnObject->pConnectParent->GetParent() != NULL);
pdnObject->pConnectParent->GetParent()->AddRef();
pAsyncOp = pdnObject->pConnectParent->GetParent();
}
else
{
pdnObject->pConnectParent->AddRef();
pAsyncOp = pdnObject->pConnectParent;
}
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp)
{
DPFX(DPFPREP, 3,"Canceling CONNECT");
hr = DNCancelChildren(pdnObject,pAsyncOp);
if (hr != DPN_OK)
{
hResultCode = DPNERR_CANNOTCANCEL;
DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelChildren to: [0x%lx]",hr, hResultCode);
}
pAsyncOp->Release();
pAsyncOp = NULL;
}
}
//
// To cancel ENUMs and SENDs, cancel out of the active list
//
if (dwInternalFlags & (DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND))
{
DPFX(DPFPREP, 3,"Canceling ENUMs or SENDs");
hr = DNCancelActiveCommands(pdnObject,dwInternalFlags,pConnection,FALSE,0);
if (hr != DPN_OK)
{
hResultCode = DPNERR_CANNOTCANCEL;
DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelActiveCommands to: [0x%lx]",hr, hResultCode);
}
}
}
Exit:
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pHandleParent)
{
pHandleParent->Release();
pHandleParent = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Connect"
STDMETHODIMP DN_Connect( PVOID pInterface,
const DPN_APPLICATION_DESC *const pdnAppDesc,
IDirectPlay8Address *const pHostAddr,
IDirectPlay8Address *const pDeviceInfo,
const DPN_SECURITY_DESC *const pdnSecurity,
const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
const void *const pvUserConnectData,
const DWORD dwUserConnectDataSize,
void *const pvPlayerContext,
void *const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
CAsyncOp *pHandleParent;
CAsyncOp *pConnectParent;
CAsyncOp *pAsyncOp;
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
CSyncEvent *pSyncEvent;
HRESULT volatile hrOperation;
IDirectPlay8Address *pIHost;
IDirectPlay8Address *pIDevice;
IDirectPlay8Address *pIAdapter;
DWORD dwConnectFlags;
#ifndef DPNBUILD_ONLYONESP
GUID guidSP;
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter;
#endif // ! DPNBUILD_ONLYONEADAPTER
void *pvConnectData;
void *pvAdapterBuffer;
DPN_SP_CAPS dnSPCaps;
#ifndef DPNBUILD_ONLYONEADAPTER
BOOL fEnumAdapters;
#endif // ! DPNBUILD_ONLYONEADAPTER
CRefCountBuffer *pReply;
CServiceProvider *pSP;
DWORD dwMultiplexFlag;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnAppDesc [0x%p], pHostAddr [0x%p], pDeviceInfo [0x%p], pdnSecurity [0x%p], pdnCredentials [0x%p], pvUserConnectData [0x%p], dwUserConnectDataSize [%ld], pvPlayerContext [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,pdnAppDesc,pHostAddr,pDeviceInfo,pdnSecurity,pdnCredentials,pvUserConnectData,dwUserConnectDataSize,pvPlayerContext,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateConnect( pInterface, pdnAppDesc, pHostAddr, pDeviceInfo,
pdnSecurity, pdnCredentials, pvUserConnectData,
dwUserConnectDataSize,pvPlayerContext,
pvAsyncContext,phAsyncHandle,dwFlags ) ) )
{
DPFERR( "Error validating connect params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
// Check to ensure not already connected/connecting
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING)
{
DPFERR( "Object is already connecting" );
DPF_RETURN(DPNERR_CONNECTING);
}
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
{
DPFERR( "Object is already connected" );
DPF_RETURN(DPNERR_ALREADYCONNECTED);
}
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
{
DPFERR( "Object is closing or disconnecting" );
DPF_RETURN(DPNERR_ALREADYCLOSING);
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
// Preset these so that they are properly cleaned up
pIHost = NULL;
pIDevice = NULL;
pIAdapter = NULL;
pSyncEvent = NULL;
pHandleParent = NULL;
pConnectParent = NULL;
pAsyncOp = NULL;
pvConnectData = NULL;
pvAdapterBuffer = NULL;
hrOperation = DPNERR_GENERIC;
pReply = NULL;
pSP = NULL;
dwMultiplexFlag = 0;
if ((hResultCode = IDirectPlay8Address_Duplicate(pHostAddr,&pIHost)) != DPN_OK)
{
DPFERR("Could not duplicate host address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
//
// Duplicate specified Device Address, or create a blank one if NULL
//
if (pDeviceInfo != NULL)
{
if ((hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice)) != DPN_OK)
{
DPFERR("Could not duplicate device info");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
else
{
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIDevice));
#else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIDevice),
FALSE);
#endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK)
{
DPFERR("Could not create Device Address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
DNASSERT(pdnObject->pOnlySP != NULL);
pdnObject->pOnlySP->AddRef();
pSP = pdnObject->pOnlySP;
#else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONESP
//
// If there is no SP on the device address, then steal it from the Host address
//
if ((hResultCode = IDirectPlay8Address_GetSP(pIDevice,&guidSP)) != DPN_OK)
{
if ((hResultCode = IDirectPlay8Address_GetSP(pIHost,&guidSP)) != DPN_OK)
{
DPFERR("Could not retrieve SP from Host Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
if ((hResultCode = IDirectPlay8Address_SetSP(pIDevice,&guidSP)) != DPN_OK)
{
DPFERR("Could not set SP on Device Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP is loaded
//
hResultCode = DN_SPEnsureLoaded(pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL,
#endif // ! DPNBUILD_LIBINTERFACE
&pSP);
if (hResultCode != DPN_OK)
{
DPFERR("Could not find or load SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
//
// Get SP caps
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK)
{
DPFERR("Could not get SP caps");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Update DirectNet Application Description
//
pdnObject->ApplicationDesc.Lock();
hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS);
pdnObject->ApplicationDesc.Unlock();
// Connect flags to Protocol
dwConnectFlags = 0;
#ifndef DPNBUILD_NOSPUI
if (dwFlags & DPNCONNECT_OKTOQUERYFORADDRESSING)
{
dwConnectFlags |= DN_CONNECTFLAGS_OKTOQUERYFORADDRESSING;
}
#endif // ! DPNBUILD_NOSPUI
if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0)
{
dwConnectFlags |= DN_CONNECTFLAGS_SESSIONDATA;
}
//
// Create parent async op, which will be released when the ENTIRE connection is finished
// including nametable transfer and installation on the local machine
//
if ((hResultCode = AsyncOpNew(pdnObject,&pConnectParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnectParent->SetOpType( ASYNC_OP_CONNECT );
pConnectParent->MakeParent();
pConnectParent->SetContext( pvPlayerContext );
pConnectParent->SetResult( DPNERR_NOCONNECTION );
pConnectParent->SetCompletion( DNCompleteConnectOperation );
pConnectParent->SetReserved(1);
if (dwFlags & DPNCONNECT_SYNC)
{
DPFX(DPFPREP, 5,"Sync operation - create sync event");
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create synchronization event");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnectParent->SetSyncEvent( pSyncEvent );
pConnectParent->SetResultPointer( &hrOperation );
pConnectParent->SetOpData( &pReply );
}
else
{
DPFX(DPFPREP, 5,"Async operation - create handle parent");
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
{
DPFERR("Could not create handle parent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pHandleParent->SetContext( pvAsyncContext );
pHandleParent->Lock();
if (pHandleParent->IsCancelled())
{
pHandleParent->Unlock();
pConnectParent->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pConnectParent->MakeChild( pHandleParent );
pHandleParent->Unlock();
}
//
// We will need a parent op for the CONNECTs to help with clean up when the initial CONNECT stage is done
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create CONNECT parent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_CONNECT );
pAsyncOp->MakeParent();
pAsyncOp->SetResult( DPNERR_NOCONNECTION );
pAsyncOp->SetCompletion( DNCompleteConnectToHost );
pAsyncOp->SetOpFlags( dwConnectFlags );
pConnectParent->Lock();
if (pConnectParent->IsCancelled())
{
pConnectParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild( pConnectParent );
pConnectParent->Unlock();
//
// Save CONNECT data (if supplied)
//
if (pvUserConnectData && dwUserConnectDataSize)
{
if ((pvConnectData = DNMalloc(dwUserConnectDataSize)) == NULL)
{
DPFERR("Could not allocate CONNECT data buffer");
DNASSERT(FALSE);
hResultCode = DPNERR_OUTOFMEMORY;
goto Failure;
}
memcpy(pvConnectData,pvUserConnectData,dwUserConnectDataSize);
}
//
// Update DirectNet object with relevant data
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pConnectParent->AddRef();
pdnObject->pConnectParent = pConnectParent;
if (pvConnectData)
{
if (pdnObject->pvConnectData)
{
DNFree(pdnObject->pvConnectData);
pdnObject->pvConnectData = NULL;
}
pdnObject->pvConnectData = pvConnectData;
pdnObject->dwConnectDataSize = dwUserConnectDataSize;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_ONLYONEADAPTER
//
// If there is no adapter specified in the device address,
// we will attempt to CONNECT on each individual adapter if the SP supports it
//
fEnumAdapters = FALSE;
if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK)
{
DPFX(DPFPREP,1,"Could not determine adapter");
DisplayDNError(1,hResultCode);
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS)
{
DPFX(DPFPREP, 3,"SP supports CONNECTing on all adapters");
fEnumAdapters = TRUE;
}
}
else
{
DPFX(DPFPREP, 7, "Device address contained adapter GUID.");
}
if(fEnumAdapters)
{
DWORD dwNumAdapters;
GUID *pAdapterList = NULL;
DN_CONNECT_OP_DATA *pConnectOpData = NULL;
if ((hResultCode = DNEnumAdapterGuids( pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
0,
&pAdapterList,
&dwNumAdapters)) != DPN_OK)
{
DPFERR("Could not enum adapters for this SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (dwNumAdapters == 0)
{
DPFERR("No valid device adapters could be found");
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pConnectOpData = pAsyncOp->GetLocalConnectOpData();
pConnectOpData->dwNumAdapters = dwNumAdapters;
pConnectOpData->dwCurrentAdapter = 0;
if (dwNumAdapters > 1)
{
dwMultiplexFlag |= DN_CONNECTFLAGS_ADDITIONALMULTIPLEXADAPTERS;
}
//
// Choose first adapter for initial LISTEN call
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK)
{
DPFERR("Could not set device adapter");
DisplayDNError(0,hResultCode);
MemoryBlockFree(pdnObject,pAdapterList);
pAdapterList = NULL;
goto Failure;
}
pConnectOpData->dwCurrentAdapter++;
pAsyncOp->SetOpData( pAdapterList );
pAdapterList = NULL;
pConnectOpData = NULL;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
pAsyncOp->SetSP( pSP ); // Set this for DNPerformNextConnect()
//
// Save SP for future connects
//
pSP->AddRef();
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pConnectSP)
{
pdnObject->pConnectSP->Release();
pdnObject->pConnectSP = NULL;
}
pdnObject->pConnectSP = pSP;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->pConnectAddress = pIHost;
IDirectPlay8Address_AddRef(pdnObject->pConnectAddress);
//
// CONNECT !
//
hResultCode = DNPerformConnect( pdnObject,
NULL,
pIDevice,
pIHost,
pSP,
pAsyncOp->GetOpFlags() | dwMultiplexFlag,
pAsyncOp);
if (hResultCode != DPN_OK)
{
DPFERR("Could not connect");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->Release();
pAsyncOp = NULL;
pConnectParent->Release();
pConnectParent = NULL;
IDirectPlay8Address_Release(pIHost);
pIHost = NULL;
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
pSP->Release();
pSP = NULL;
if (dwFlags & DPNCONNECT_SYNC)
{
CNameTableEntry *pHostPlayer;
pHostPlayer = NULL;
if ((hResultCode = pSyncEvent->WaitForEvent()) != DPN_OK)
{
DPFERR("DNSyncEventWait() terminated bizarrely");
DNASSERT(FALSE);
}
else
{
hResultCode = hrOperation;
}
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
//
// No longer connecting
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Clients need to release all sends from the server that were
// queued once the CONNECT_COMPLETE gets indicated.
// We prepare to do that now.
//
if ((hrOperation == DPN_OK) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT))
{
if (pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer ) == DPN_OK)
{
pHostPlayer->Lock();
pHostPlayer->MakeAvailable();
pHostPlayer->NotifyAddRef();
pHostPlayer->SetInUse();
pHostPlayer->Unlock();
//
// We are now connected
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
else
{
//
// If we couldn't get a reference on the server (host player),
// then either the server has disconnected, or we are being shut down.
// In either case, we should return an error
//
DPFX(DPFPREP, 0, "Couldn't get host player reference, failing CONNECT!");
hrOperation = DPNERR_NOCONNECTION;
hResultCode = hrOperation;
if (pReply)
{
pReply->Release();
pReply = NULL;
}
}
}
else
{
//
// Connect failed, or this is a peer/server interface
//
}
//
// Generate connect completion
//
DNUserConnectComplete(pdnObject,0,NULL,hrOperation,pReply);
if (pReply)
{
pReply->Release();
pReply = NULL;
}
//
// Cancel ENUMs if the CONNECT succeeded and unload SP's
//
if (hrOperation == DPN_OK)
{
DNCancelActiveCommands(pdnObject,DN_CANCEL_FLAG_ENUM_QUERY,NULL,TRUE,DPNERR_CONNECTING);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
DN_SPReleaseAll(pdnObject);
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
//
// Actually release queued messages if necessary
//
if (pHostPlayer != NULL)
{
pHostPlayer->PerformQueuedOperations();
pHostPlayer->Release();
pHostPlayer = NULL;
}
}
DNASSERT( pHostPlayer == NULL );
}
else
{
pHandleParent->SetCompletion( DNCompleteUserConnect );
if (phAsyncHandle)
{
*phAsyncHandle = pHandleParent->GetHandle();
}
pHandleParent->Release();
pHandleParent = NULL;
hResultCode = DPNERR_PENDING;
}
Exit:
DNASSERT( pSP == NULL );
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pHandleParent)
{
pHandleParent->Release();
pHandleParent = NULL;
}
if (pConnectParent)
{
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pConnectParent->GetHandle(), NULL )))
{
// Release the HandleTable reference
pConnectParent->Release();
}
pConnectParent->Release();
pConnectParent = NULL;
}
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pIHost)
{
IDirectPlay8Address_Release(pIHost);
pIHost = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
if (pIAdapter)
{
IDirectPlay8Address_Release(pIAdapter);
pIAdapter = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
if (pvAdapterBuffer)
{
DNFree(pvAdapterBuffer);
pvAdapterBuffer = NULL;
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pIDP8ADevice)
{
IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
pdnObject->pIDP8ADevice = NULL;
}
if (pdnObject->pvConnectData)
{
DNFree(pdnObject->pvConnectData);
pdnObject->pvConnectData = NULL;
pdnObject->dwConnectDataSize = 0;
}
if( pdnObject->pConnectAddress )
{
IDirectPlay8Address_Release( pdnObject->pConnectAddress );
pdnObject->pConnectAddress = NULL;
}
if (pdnObject->pConnectSP)
{
pdnObject->pConnectSP->Release();
pdnObject->pConnectSP = NULL;
}
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Exit;
}
// DN_GetSendQueueInfo
//
// Get info about the user send queue.
// This will find the CConnection for a given player and extract the required queue infor from it.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetSendQueueInfo"
STDMETHODIMP DN_GetSendQueueInfo(PVOID pInterface,
const DPNID dpnid,
DWORD *const pdwNumMsgs,
DWORD *const pdwNumBytes,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
DWORD dwQueueFlags;
DWORD dwNumMsgs;
DWORD dwNumBytes;
CNameTableEntry *pNTEntry;
CConnection *pConnection;
HRESULT hResultCode;
DNASSERT(pInterface != NULL);
DPFX(DPFPREP, 2,"Parameters : pInterface [0x%p], dpnid [0x%lx], pdwNumMsgs [0x%p], pdwNumBytes [0x%p], dwFlags [0x%lx]",
pInterface,dpnid,pdwNumMsgs,pdwNumBytes,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
HRESULT hrResult;
if( FAILED( hrResult = DN_ValidateGetSendQueueInfo( pInterface, pdwNumMsgs, pdwNumBytes, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN( hrResult );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR( "Object is already connecting" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED ) )
{
DPFERR("Object is not connected" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
pConnection = NULL;
//
// Validate specified player ID and get CConnection
//
if((hResultCode = pdnObject->NameTable.FindEntry( dpnid, &pNTEntry )) != DPN_OK)
{
DPFX(DPFPREP, 0,"Could not find Player ID [0x%lx] in NameTable", dpnid );
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find entry in deleted list either");
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (pNTEntry->IsLocal() || pNTEntry->IsGroup())
{
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
{
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
//
// Determine required queues
//
dwQueueFlags = dwFlags & (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW);
if (dwQueueFlags == 0)
{
dwQueueFlags = (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW);
}
//
// Extract required info
//
dwNumMsgs = 0;
dwNumBytes = 0;
pConnection->Lock();
if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_HIGH)
{
dwNumMsgs += pConnection->GetHighQueueNum();
dwNumBytes += pConnection->GetHighQueueBytes();
}
if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_NORMAL)
{
dwNumMsgs += pConnection->GetNormalQueueNum();
dwNumBytes += pConnection->GetNormalQueueBytes();
}
if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_LOW)
{
dwNumMsgs += pConnection->GetLowQueueNum();
dwNumBytes += pConnection->GetLowQueueBytes();
}
pConnection->Unlock();
pConnection->Release();
pConnection = NULL;
if (pdwNumMsgs)
{
*pdwNumMsgs = dwNumMsgs;
DPFX(DPFPREP, 3,"Setting: *pdwNumMsgs [%ld]",dwNumMsgs);
}
if (pdwNumBytes)
{
*pdwNumBytes = dwNumBytes;
DPFX(DPFPREP, 3,"Setting: *pdwNumBytes [%ld]",dwNumBytes);
}
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetApplicationDesc"
STDMETHODIMP DN_GetApplicationDesc(PVOID pInterface,
DPN_APPLICATION_DESC *const pAppDescBuffer,
DWORD *const pcbDataSize,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
CPackedBuffer packedBuffer;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pAppDescBuffer [0x%p], pcbDataSize [0x%p], dwFlags [0x%lx]",
pInterface,pAppDescBuffer,pcbDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetApplicationDesc( pInterface, pAppDescBuffer, pcbDataSize, dwFlags ) ) )
{
DPFERR( "Failed validation getappdesc" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("Object is not connected or hosting" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
//
// Initialize PackedBuffer
//
packedBuffer.Initialize(static_cast<void*>(pAppDescBuffer),*pcbDataSize);
//
// Try to pack in the application description.
// If it won't fit, the required size will be in the PackedBuffer.
//
hResultCode = pdnObject->ApplicationDesc.Pack(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
//
// Ensure we know what's going on
//
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_BUFFERTOOSMALL))
{
DPFERR("Unknown error occurred packing application description");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_GENERIC;
goto Failure;
}
//
// Size of buffer
//
*pcbDataSize = packedBuffer.GetSizeRequired();
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SetApplicationDesc"
STDMETHODIMP DN_SetApplicationDesc(PVOID pInterface,
const DPN_APPLICATION_DESC *const pdnApplicationDesc,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode = DPN_OK;
CRefCountBuffer *pRefCountBuffer;
CPackedBuffer packedBuffer;
CWorkerJob *pWorkerJob;
DWORD dwAppDescInfoSize;
DWORD dwEnumFrameSize;
DWORD dwUpdateFlags;
CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnApplicationDesc [0x%p], dwFlags [0x%lx]",
pInterface,pdnApplicationDesc,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateSetApplicationDesc( pInterface, pdnApplicationDesc, dwFlags ) ) )
{
DPFERR( "Error validating setappdesc params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR( "Object has not yet completed connecting / hosting" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !DN_CHECK_LOCALHOST( pdnObject ) )
{
DPFERR("Object is not connected or hosting" );
DPF_RETURN(DPNERR_NOTHOST);
}
pNTEntry = NULL;
pRefCountBuffer = NULL;
pWorkerJob = NULL;
//
// This can only be called by the host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry )) != DPN_OK)
{
DPFERR("Could not get local player");
hResultCode = DPNERR_NOTHOST;
goto Failure;
}
if (!pNTEntry->IsHost())
{
DPFERR("Not Host player");
hResultCode = DPNERR_NOTHOST;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
//
// Use cached max enum frame size
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
dwEnumFrameSize = pdnObject->dwMaxFrameSize;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) );
if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnApplicationDesc->dwApplicationReservedDataSize))
{
DPFERR("Not enough room for the application reserved data");
hResultCode = DPNERR_DATATOOLARGE;
goto Failure;
}
//
// Update Host player's application desc first
//
pdnObject->ApplicationDesc.Lock();
if (pdnApplicationDesc->dwMaxPlayers > 0)
{
if (pdnApplicationDesc->dwMaxPlayers < pdnObject->ApplicationDesc.GetCurrentPlayers())
{
DPFERR("Cannot set max players to less than the current number of players");
pdnObject->ApplicationDesc.Unlock();
hResultCode = DPNERR_SESSIONFULL;
goto Failure;
}
}
hResultCode = pdnObject->ApplicationDesc.Update(pdnApplicationDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|
DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
pdnObject->ApplicationDesc.Unlock();
if (hResultCode != DPN_OK)
{
DPFERR("Could not update Application Desciption");
DisplayDNError(0,hResultCode);
goto Failure;
}
#ifdef DIRECTPLAYDIRECTX9
//
// Update Listen if enums allowed/disallowed
//
dwUpdateFlags = 0;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && !(pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS))
{
dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS;
pdnObject->dwFlags &= ~DN_OBJECT_FLAG_DISALLOW_ENUMS;
}
else if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && (pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS))
{
dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS;
pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (dwUpdateFlags)
{
DNUpdateListens(pdnObject,dwUpdateFlags);
}
#endif // DIRECTPLAYDIRECTX9
//
// Inform host application
//
hResultCode = DNUserUpdateAppDesc(pdnObject);
//
// Get Application Description Info size
//
packedBuffer.Initialize(NULL,0);
hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
DNASSERT(hResultCode == DPNERR_BUFFERTOOSMALL);
dwAppDescInfoSize = packedBuffer.GetSizeRequired();
//
// Create packed buffer to send to other players
//
if ((hResultCode = RefCountBufferNew(pdnObject,dwAppDescInfoSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not create CountBuffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if (hResultCode != DPN_OK)
{
DPFERR("Could not pack Application Description into buffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Notify other players
//
DPFX(DPFPREP, 5,"Adding UpdateApplicationDesc to Job Queue");
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) == DPN_OK)
{
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC );
pWorkerJob->SetSendNameTableOperationVersion( 0 );
pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
}
else
{
DPFERR("Could not create worker job - ignore and continue");
DisplayDNError(0,hResultCode);
}
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNTerminateSession"
HRESULT DNTerminateSession(DIRECTNETOBJECT *const pdnObject,
const HRESULT hrReason)
{
HRESULT hResultCode;
#ifndef DPNBUILD_NOLOBBY
BOOL fWasConnected;
#endif // ! DPNBUILD_NOLOBBY
#ifndef DPNBUILD_SINGLEPROCESS
BOOL fWasRegistered;
#endif // ! DPNBUILD_SINGLEPROCESS
CAsyncOp *pAsyncOp;
DPFX(DPFPREP, 4,"Parameters: hrReason [0x%lx]",hrReason);
DNASSERT(pdnObject != NULL);
DNASSERT( (hrReason == DPN_OK) || (hrReason == DPNERR_HOSTTERMINATEDSESSION) || (hrReason == DPNERR_CONNECTIONLOST));
pAsyncOp = NULL;
//
// Shut down listen(s)
//
DPFX(DPFPREP, 3,"Checking LISTENs");
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pAsyncOp = pdnObject->pListenParent;
pdnObject->pListenParent = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp)
{
DPFX(DPFPREP, 3,"Canceling LISTENs");
hResultCode = DNCancelChildren(pdnObject,pAsyncOp);
DPFX(DPFPREP, 3,"Canceling LISTENs returned [0x%lx]",hResultCode);
pAsyncOp->Release();
pAsyncOp = NULL;
}
#ifndef DPNBUILD_SINGLEPROCESS
//
// Unregister from DPNSVR (if required)
//
fWasRegistered = FALSE;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & DN_OBJECT_FLAG_DPNSVR_REGISTERED)
{
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_DPNSVR_REGISTERED);
fWasRegistered = TRUE;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (fWasRegistered)
{
pdnObject->ApplicationDesc.UnregisterWithDPNSVR();
}
#endif // ! DPNBUILD_SINGLEPROCESS
//
// Flag DirectNetObject as disconnecting. This flag will be cleared when Close() finishes.
//
#ifndef DPNBUILD_NOLOBBY
fWasConnected = FALSE;
#endif // ! DPNBUILD_NOLOBBY
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
{
#ifndef DPNBUILD_NOLOBBY
fWasConnected = TRUE;
#endif // ! DPNBUILD_NOLOBBY
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTED);
}
#pragma BUGBUG( minara,"How usefull is this DN_OBJECT_FLAG_DISCONNECTING flag ?" )
pdnObject->dwFlags |= DN_OBJECT_FLAG_DISCONNECTING;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_NOLOBBY
//
// Update Lobby status
//
if (fWasConnected)
{
DNUpdateLobbyStatus(pdnObject,DPLSESSION_DISCONNECTED);
}
#endif // ! DPNBUILD_NOLOBBY
#ifndef DPNBUILD_NOVOICE
//
// Notify Voice
//
Voice_Notify( pdnObject, DVEVENT_STOPSESSION, 0, 0 );
#endif // DPNBUILD_NOVOICE
//
// Remove host migration target
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pNewHost)
{
pdnObject->pNewHost->Release();
pdnObject->pNewHost = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Delete all players from NameTable. This will involve
// emptying the table and removing short-cut player pointers
//
DPFX(DPFPREP, 5,"Removing players from NameTable");
pdnObject->NameTable.EmptyTable(hrReason);
//
// Clean up NameTable operation list
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
{
DPFX(DPFPREP, 5,"Cleaning up NameTable operation list");
DNNTRemoveOperations(pdnObject,0,TRUE);
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
//
// Clean up CONNECT parent
//
if (pdnObject->pConnectParent)
{
pAsyncOp = pdnObject->pConnectParent;
pdnObject->pConnectParent = NULL;
}
//
// Clean up CONNECT info and address
//
if (pdnObject->pvConnectData)
{
DNFree(pdnObject->pvConnectData);
pdnObject->pvConnectData = NULL;
pdnObject->dwConnectDataSize = 0;
}
if (pdnObject->pConnectAddress)
{
IDirectPlay8Address_Release(pdnObject->pConnectAddress);
pdnObject->pConnectAddress = NULL;
}
if (pdnObject->pIDP8ADevice)
{
IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
pdnObject->pIDP8ADevice = NULL;
}
//
// Clear the DISCONNECTING and HOST_CONNECTED flag
// and clear connection info
//
pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_DISCONNECTING
| DN_OBJECT_FLAG_HOST_CONNECTED));
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
hResultCode = DPN_OK;
DNASSERT(pAsyncOp == NULL);
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SendTo"
STDMETHODIMP DN_SendTo( PVOID pv,
const DPNID dpnid,
const DPN_BUFFER_DESC *const prgBufferDesc,
const DWORD cBufferDesc,
const DWORD dwTimeOut,
void *const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
HRESULT hResultCode;
HRESULT hrSend;
CNameTableEntry *pNTEntry;
CNameTableEntry *pLocalPlayer;
DIRECTNETOBJECT *pdnObject;
DWORD dwSendFlags;
CSyncEvent *pSyncEvent;
const DPN_BUFFER_DESC *pActualBufferDesc;
DWORD dwActualBufferDesc;
CRefCountBuffer *pRefCountBuffer;
DPNHANDLE handle;
CAsyncOp *pAsyncOp;
CAsyncOp *pParent;
CAsyncOp *pHandleParent;
CConnection *pConnection;
DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], prgBufferDesc [0x%p], dwTimeOut [%ld], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
dpnid,prgBufferDesc,dwTimeOut,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateSendParams( pv , prgBufferDesc, cBufferDesc, dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags ) ) )
{
DPFX(DPFPREP, 0, "Error validating common send params hr=[0x%lx]", hResultCode );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR( "Object has not yet completed connecting / hosting" );
DPF_RETURN(DPNERR_CONNECTING);
}
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("Object is not connected or hosting" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pRefCountBuffer = NULL;
pSyncEvent = NULL;
pNTEntry = NULL;
pLocalPlayer = NULL;
pAsyncOp = NULL;
pParent = NULL;
pHandleParent = NULL;
pConnection = NULL;
handle = 0;
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)
{
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pNTEntry )) != DPN_OK)
{
DPFERR("Could not find Host player");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
{
DPFERR("Could not get Connection reference");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_CONNECTIONLOST; // re-map this
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
}
#ifndef DPNBUILD_NOMULTICAST
else if (pdnObject->dwFlags & DN_OBJECT_FLAG_MULTICAST)
{
if (pdnObject->pMulticastSend == NULL)
{
DPFERR("Could not get multicast send connection");
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pdnObject->pMulticastSend->AddRef();
pConnection = pdnObject->pMulticastSend;
}
#endif // ! DPNBUILD_NOMULTICAST
else
{
if (dpnid == DPNID_ALL_PLAYERS_GROUP)
{
if ((hResultCode = pdnObject->NameTable.GetAllPlayersGroupRef( &pNTEntry )) != DPN_OK)
{
DPFERR("Unable to get all players group");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
}
else
{
if (dwFlags & DPNSEND_NOLOOPBACK)
{
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_GENERIC;
goto Failure;
}
if (dpnid == pLocalPlayer->GetDPNID())
{
hResultCode = DPNERR_INVALIDPARAM;
goto Failure;
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Unable to find target player or group");
DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find target in deleted list either");
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
//
// Target was found, but is not reachable
//
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (! pNTEntry->IsGroup())
{
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
{
DPFERR("Could not get Connection reference");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_CONNECTIONLOST; // re-map this
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
}
}
}
//
// Create copy of data in scatter-gather buffers
//
if (!(dwFlags & (DPNSEND_NOCOPY | DPNSEND_COMPLETEONPROCESS)))
{
DWORD dw;
DWORD dwSize;
dwSize = 0;
for ( dw = 0 ; dw < cBufferDesc ; dw++ )
{
dwSize += prgBufferDesc[dw].dwBufferSize;
}
if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not allocate buffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
pActualBufferDesc = pRefCountBuffer->BufferDescAddress();
dwActualBufferDesc = 1;
dwSize = 0;
for ( dw = 0 ; dw < cBufferDesc ; dw++ )
{
memcpy(pActualBufferDesc->pBufferData + dwSize,prgBufferDesc[dw].pBufferData,prgBufferDesc[dw].dwBufferSize);
dwSize += prgBufferDesc[dw].dwBufferSize;
}
}
else
{
pRefCountBuffer = NULL;
pActualBufferDesc = prgBufferDesc;
dwActualBufferDesc = cBufferDesc;
}
dwSendFlags = 0;
if (dwFlags & DPNSEND_GUARANTEED)
{
dwSendFlags |= DN_SENDFLAGS_RELIABLE;
}
if (dwFlags & DPNSEND_NONSEQUENTIAL)
{
dwSendFlags |= DN_SENDFLAGS_NON_SEQUENTIAL;
}
if (dwFlags & DPNSEND_PRIORITY_HIGH)
{
dwSendFlags |= DN_SENDFLAGS_HIGH_PRIORITY;
}
if (dwFlags & DPNSEND_PRIORITY_LOW)
{
dwSendFlags |= DN_SENDFLAGS_LOW_PRIORITY;
}
#ifdef DIRECTPLAYDIRECTX9
if (dwFlags & DPNSEND_COALESCE)
{
dwSendFlags |= DN_SENDFLAGS_COALESCE;
}
#endif // DIRECTPLAYDIRECTX9
if (dwFlags & DPNSEND_SYNC)
{
//
// Create SyncEvent for SYNC operation
//
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create sync event for group sends");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
else
{
//
// Create Handle for ASYNC operation
//
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pHandleParent->SetContext( pvAsyncContext );
pHandleParent->SetStartTime( GETTIMESTAMP() );
handle = pHandleParent->GetHandle();
}
//
// pNTEntry will be NULL if this is not a group send
// pConnection will not be NULL if this is not a group send
//
if (pNTEntry != NULL)
{
BOOL fRequest;
BOOL fNoLoopBack;
DNASSERT(pConnection == NULL);
//
// Perform group sends and get parent AsyncOp
//
if (dwFlags & DPNSEND_COMPLETEONPROCESS)
{
fRequest = TRUE;
}
else
{
fRequest = FALSE;
}
if (dwFlags & DPNSEND_NOLOOPBACK)
{
fNoLoopBack = TRUE;
}
else
{
fNoLoopBack = FALSE;
}
hResultCode = DNSendGroupMessage( pdnObject,
pNTEntry,
DN_MSG_USER_SEND,
pActualBufferDesc,
dwActualBufferDesc,
pRefCountBuffer,
dwTimeOut,
dwSendFlags,
fNoLoopBack,
fRequest,
pHandleParent,
&pParent);
if (hResultCode != DPN_OK)
{
DPFERR("SEND failed");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Synchronous ?
//
if (dwFlags & DPNSEND_SYNC)
{
pParent->SetSyncEvent( pSyncEvent );
pParent->SetResultPointer( &hrSend );
hrSend = DPNERR_GENERIC;
}
else
{
//
// Set async completion (if required). We will only need this if the SEND succeeded.
//
if (!(dwFlags & DPNSEND_NOCOMPLETE))
{
pHandleParent->SetCompletion( DNCompleteSendHandle );
}
pHandleParent->Release();
pHandleParent = NULL;
}
pParent->Release();
pParent = NULL;
pNTEntry->Release();
pNTEntry = NULL;
}
else
{
DNASSERT(pConnection != NULL);
if (dwFlags & DPNSEND_COMPLETEONPROCESS)
{
hResultCode = DNPerformRequest( pdnObject,
DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION,
pActualBufferDesc,
pConnection,
pHandleParent,
&pAsyncOp);
}
else
{
hResultCode = DNSendMessage(pdnObject,
pConnection,
DN_MSG_USER_SEND,
dpnid,
pActualBufferDesc,
dwActualBufferDesc,
pRefCountBuffer,
dwTimeOut,
dwSendFlags,
pHandleParent,
&pAsyncOp);
}
pConnection->Release();
pConnection = NULL;
if (hResultCode == DPN_OK)
{
//
// If the caller wants asynchronous, we want to guarantee that we'll always
// return DPNSUCCESS_PENDING, but since the send is already complete,
// manually generate the completion now.
// If the caller wanted synchronous, trigger the event so we drop out of
// the wait below.
//
if (dwFlags & DPNSEND_SYNC)
{
pSyncEvent->Set();
hrSend = DPN_OK;
}
else
{
//
// Immediate completion should only happen for non-guaranteed sends
// where we wouldn't be told of the RTT and retry count anyway.
//
DNASSERT(! (dwFlags & DPNSEND_GUARANTEED));
DNUserSendComplete( pdnObject,
handle,
pvAsyncContext,
pHandleParent->GetStartTime(),
DPN_OK,
-1,
0);
pHandleParent->Release();
pHandleParent = NULL;
}
}
else
{
if (hResultCode != DPNERR_PENDING)
{
DPFERR("SEND failed");
DisplayDNError(0,hResultCode);
if (hResultCode == DPNERR_INVALIDENDPOINT)
{
hResultCode = DPNERR_CONNECTIONLOST;
}
goto Failure;
}
//
// Synchronous ?
//
if (dwFlags & DPNSEND_SYNC)
{
pAsyncOp->SetSyncEvent( pSyncEvent );
pAsyncOp->SetResultPointer( &hrSend );
hrSend = DPNERR_GENERIC;
#pragma TODO( minara, "We can be smarter about passing back errors - at least better than this !" )
}
else
{
//
// Set async completion (if required). We will only need this if the SEND succeeded.
//
if (!(dwFlags & DPNSEND_NOCOMPLETE))
{
pHandleParent->SetCompletion( DNCompleteSendHandle );
}
pHandleParent->Release();
pHandleParent = NULL;
}
pAsyncOp->Release();
pAsyncOp = NULL;
}
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (dwFlags & DPNSEND_SYNC)
{
pSyncEvent->WaitForEvent();
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
hResultCode = hrSend;
}
else
{
if (phAsyncHandle != NULL)
{
*phAsyncHandle = handle;
}
hResultCode = DPNERR_PENDING;
}
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pHandleParent)
{
pHandleParent->Release();
pHandleParent = NULL;
}
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pParent)
{
pParent->Release();
pParent = NULL;
}
if (handle != 0)
{
if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
handle = 0;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
goto Exit;
}
// DN_Host
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Host"
STDMETHODIMP DN_Host( PVOID pInterface,
const DPN_APPLICATION_DESC *const pdnAppDesc,
IDirectPlay8Address **const prgpDeviceInfo,
const DWORD cDeviceInfo,
const DPN_SECURITY_DESC *const pdnSecurity,
const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
void *const pvPlayerContext,
const DWORD dwFlags)
{
CNameTableEntry *pHostPlayer;
CNameTableEntry *pAllPlayersGroup;
DWORD dwCurrentDevice;
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
IDirectPlay8Address *rgIDevice[MAX_HOST_ADDRESSES];
DWORD dwNumDeviceAddresses;
DWORD dwListensRunning;
CConnection *pConnection;
CAsyncOp *pListenParent;
DWORD dwEnumFrameSize;
DWORD dwListenFlags;
DWORD dwUpdateFlags;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnAppDesc [0x%p], prgpDeviceInfo [0x%p], cDeviceInfo [%ld], pdnSecurity [0x%p], pdnCredentials [0x%p], dwFlags [0x%lx]",
pInterface,pdnAppDesc,prgpDeviceInfo,cDeviceInfo,pdnSecurity,pdnCredentials,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateHost( pInterface, pdnAppDesc, prgpDeviceInfo, cDeviceInfo,
pdnSecurity, pdnCredentials, pvPlayerContext,
dwFlags ) ) )
{
DPFERR( "Error validating host params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
// Check to ensure not already connected
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
{
if( DN_CHECK_LOCALHOST( pdnObject ) )
{
DPFERR("Object is already hosting" );
DPF_RETURN(DPNERR_HOSTING);
}
else
{
DPFERR("Object is already connected" );
DPF_RETURN(DPNERR_ALREADYCONNECTED);
}
}
#ifndef DPNBUILD_NOPARAMVAL
if((pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) &&
(pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) )
{
DPFERR( "You cannot specify the clientserver flag in peer mode" );
DPF_RETURN(DPNERR_INVALIDPARAM);
}
#ifndef DPNBUILD_NOSERVER
if((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) &&
!(pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) )
{
DPFERR( "You MUST specify the client/server flag for client/server mode" );
DPF_RETURN(DPNERR_INVALIDPARAM);
}
#endif // !DPNBUILD_NOSERVER
#endif // !DPNBUILD_NOPARAMVAL
#ifdef DIRECTPLAYDIRECTX9
//ensure that both types of signing aren't specified
if ((pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED) && (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED))
{
DPFERR( "You cannot specify both fast and full signing" );
DPF_RETURN(DPNERR_INVALIDPARAM);
}
#endif // DIRECTPLAYDIRECTX9
dwNumDeviceAddresses = 0;
pListenParent = NULL;
pConnection = NULL;
pHostPlayer = NULL;
pAllPlayersGroup = NULL;
//
// Flag as CONNECTING to prevent other operations here
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_CONNECTED))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
hResultCode = DPNERR_ALREADYCONNECTED;
goto Failure;
}
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
// Adding local host flag
pdnObject->dwFlags |= DN_OBJECT_FLAG_LOCALHOST;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Copy application description to DirectNet object
//
pdnObject->ApplicationDesc.Lock();
hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS);
pdnObject->ApplicationDesc.Unlock();
if (hResultCode != DPN_OK)
{
DPFERR("Could not update application description");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Create Instance GUID
//
if ((hResultCode = pdnObject->ApplicationDesc.CreateNewInstanceGuid()) != DPN_OK)
{
DPFERR("Could not create instance GUID - ignore and continue");
DisplayDNError(0,hResultCode);
}
//
// Set NameTable DPNID mask
//
DPFX(DPFPREP, 5,"DPNID Mask [0x%lx]",pdnObject->ApplicationDesc.GetDPNIDMask());
pdnObject->NameTable.SetDPNIDMask( pdnObject->ApplicationDesc.GetDPNIDMask() );
//
// Create group "ALL PLAYERS"
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pAllPlayersGroup)) != DPN_OK)
{
DPFERR("Could not create NameTableEntry");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAllPlayersGroup->MakeGroup();
// This function takes the lock internally
pdnObject->NameTable.MakeAllPlayersGroup(pAllPlayersGroup);
//
// Create local player
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pHostPlayer)) != DPN_OK)
{
DPFERR("Could not create NameTableEntry");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
// This function takes the lock internally
pHostPlayer->UpdateEntryInfo( pdnObject->NameTable.GetDefaultPlayer()->GetName(),
pdnObject->NameTable.GetDefaultPlayer()->GetNameSize(),
pdnObject->NameTable.GetDefaultPlayer()->GetData(),
pdnObject->NameTable.GetDefaultPlayer()->GetDataSize(),
DPNINFO_NAME|DPNINFO_DATA,
FALSE);
pHostPlayer->SetDNETVersion( DN_VERSION_CURRENT );
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER)
{
pHostPlayer->MakeServer();
}
else
#endif // !DPNBUILD_NOSERVER
{
DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_PEER);
pHostPlayer->MakePeer();
}
pHostPlayer->SetContext(pvPlayerContext);
pHostPlayer->StartConnecting();
if ((hResultCode = pdnObject->NameTable.AddEntry(pHostPlayer)) != DPN_OK)
{
DPFERR("Could not add NameTableEntry to NameTable");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
// Create Host's connection (NULL end point)
if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK)
{
DPFERR("Could not create new connection");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnection->SetStatus( CONNECTED );
pConnection->MakeLocal();
pConnection->SetEndPt(NULL);
pConnection->SetDPNID(pHostPlayer->GetDPNID());
pdnObject->NameTable.MakeLocalPlayer(pHostPlayer);
pdnObject->NameTable.MakeHostPlayer(pHostPlayer);
//
// Make ALL_PLAYERS group available (does not indicate anything to user).
//
pAllPlayersGroup->Lock();
pAllPlayersGroup->MakeAvailable();
pAllPlayersGroup->Unlock();
pAllPlayersGroup->Release();
pAllPlayersGroup = NULL;
//
// Don't notify user of CREATE_PLAYER yet in case starting listens fails.
// This prevents them from having to handle CREATE_PLAYERs even in
// the failure case.
//
//
// Start listens
//
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
if (cDeviceInfo == 0)
{
//
// Create a placeholder device address
//
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
reinterpret_cast<void**>(&rgIDevice[0]));
#else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>(&rgIDevice[0]),
FALSE);
#endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK)
{
DPFERR("Could not create device address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
dwNumDeviceAddresses = 1;
}
else
#endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
{
#ifdef DBG
for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++)
{
DPFX(DPFPREP, 5,"Original Device: prgpDeviceInfo[%ld] [0x%p]",dwCurrentDevice,prgpDeviceInfo[dwCurrentDevice]);
}
#endif // DBG
// Duplicate address interfaces
for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++)
{
if ((hResultCode = IDirectPlay8Address_Duplicate(prgpDeviceInfo[dwCurrentDevice],&rgIDevice[dwNumDeviceAddresses])) != DPN_OK)
{
DPFERR("Could not duplicate Host address info - skipping it");
continue;
}
DPFX(DPFPREP, 5,"Duplicate Device: rgIDevice[%ld] [0x%p]",dwNumDeviceAddresses,rgIDevice[dwNumDeviceAddresses]);
dwNumDeviceAddresses++;
}
}
// Parent Async Op
if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pListenParent->SetOpType( ASYNC_OP_LISTEN );
pListenParent->MakeParent();
pListenParent->SetCompletion( DNCompleteListen );
dwListenFlags = 0;
#ifndef DPNBUILD_NOSPUI
// Save query for addressing flag (if necessary)
if (dwFlags & DPNHOST_OKTOQUERYFORADDRESSING)
{
dwListenFlags |= DN_LISTENFLAGS_OKTOQUERYFORADDRESSING;
}
#endif // ! DPNBUILD_NOSPUI
if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0)
{
dwListenFlags |= DN_LISTENFLAGS_SESSIONDATA;
}
#ifdef DIRECTPLAYDIRECTX9
// Disallow enums if required
if (pdnAppDesc->dwFlags & DPNSESSION_NOENUMS)
{
dwListenFlags |= DN_LISTENFLAGS_DISALLOWENUMS;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
// turning signing on if required. N.B. We've already ensured that only one of these options is selected
if (pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED)
{
dwListenFlags|=DN_LISTENFLAGS_FASTSIGNED;
}
else if (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED)
{
dwListenFlags|=DN_LISTENFLAGS_FULLSIGNED;
}
#endif // DIRECTPLAYDIRECTX9
pListenParent->SetOpFlags(dwListenFlags);
// Children op's
dwListensRunning = 0;
for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++)
{
if (rgIDevice[dwCurrentDevice] != NULL)
{
hResultCode = DNPerformSPListen(pdnObject,
rgIDevice[dwCurrentDevice],
pListenParent,
NULL);
if (hResultCode == DPN_OK)
{
dwListensRunning++;
}
}
}
// Make sure at least 1 listen started
if (dwListensRunning == 0)
{
DPFERR("Could not start any LISTENs");
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
// Store parent LISTEN on DirectNet object
pListenParent->AddRef();
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->pListenParent = pListenParent;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pListenParent->Release();
pListenParent = NULL;
//
// Use cached max enum frame size
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
dwEnumFrameSize = pdnObject->dwMaxFrameSize;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) );
if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnAppDesc->dwApplicationReservedDataSize))
{
DPFERR("Not enough room for the application reserved data");
hResultCode = DPNERR_DATATOOLARGE;
goto Failure;
}
//
// Register with DPNSVR
//
dwUpdateFlags = 0;
#ifndef DPNBUILD_SINGLEPROCESS
if(pdnObject->ApplicationDesc.UseDPNSVR())
{
dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DPNSVR;
}
#endif // ! DPNBUILD_SINGLEPROCESS
if (pdnObject->ApplicationDesc.DisallowEnums())
{
dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS;
}
if (dwUpdateFlags)
{
if ((hResultCode = DNUpdateListens(pdnObject,dwUpdateFlags)) != DPN_OK)
{
DPFERR("Could not update listens or register with DPNSVR");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
//
// Update DirectNet object to be connected
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING);
pdnObject->dwFlags &= ~DN_OBJECT_FLAG_CONNECTING;
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_NOLOBBY
//
// Update Lobby status
//
DNUpdateLobbyStatus(pdnObject,DPLSESSION_CONNECTED);
#endif // ! DPNBUILD_NOLOBBY
//
// Now that Listens have been successfully started, indicate the local CREATE_PLAYER.
//
//
// One player in game (Local/Host player)
//
pdnObject->ApplicationDesc.IncPlayerCount(TRUE);
//
// Populate local player's connection
//
pConnection->SetDPNID(pHostPlayer->GetDPNID());
pdnObject->NameTable.PopulateConnection(pConnection);
pConnection->Release();
pConnection = NULL;
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
//
// Unload SP's
//
DN_SPReleaseAll(pdnObject);
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pHostPlayer->Release();
pHostPlayer = NULL;
hResultCode = DPN_OK;
Exit:
//
// Clean up copies of device address
//
for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++)
{
IDirectPlay8Address_Release(rgIDevice[dwCurrentDevice]);
rgIDevice[dwCurrentDevice] = NULL;
}
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
if (pListenParent)
{
pListenParent->Release();
pListenParent = NULL;
}
if (pHostPlayer)
{
pHostPlayer->Release();
pHostPlayer = NULL;
}
if (pAllPlayersGroup)
{
pAllPlayersGroup->Release();
pAllPlayersGroup = NULL;
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pListenParent = pdnObject->pListenParent;
pdnObject->pListenParent = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pListenParent)
{
DNCancelChildren(pdnObject,pListenParent);
pListenParent->Release();
pListenParent = NULL;
}
pdnObject->NameTable.EmptyTable(DPNERR_HOSTTERMINATEDSESSION);
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_CONNECTING|DN_OBJECT_FLAG_CONNECTED|DN_OBJECT_FLAG_LOCALHOST);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_CreateGroup"
STDMETHODIMP DN_CreateGroup(PVOID pInterface,
const DPN_GROUP_INFO *const pdpnGroupInfo,
void *const pvGroupContext,
void *const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
PWSTR pwszName;
DWORD dwNameSize;
PVOID pvData;
DWORD dwDataSize;
CNameTableEntry *pLocalPlayer;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdpnGroupInfo [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateCreateGroup( pInterface, pdpnGroupInfo, pvGroupContext,
pvAsyncContext,phAsyncHandle, dwFlags ) ) )
{
DPFERR( "Error validating create group params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to create a group" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pLocalPlayer = NULL;
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName))
{
pwszName = pdpnGroupInfo->pwszName;
dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR);
}
else
{
pwszName = NULL;
dwNameSize = 0;
}
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize))
{
pvData = pdpnGroupInfo->pvData;
dwDataSize = pdpnGroupInfo->dwDataSize;
}
else
{
pvData = NULL;
dwDataSize = 0;
}
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pLocalPlayer->IsHost())
{
DPFX(DPFPREP, 3,"Host is creating group");
hResultCode = DNHostCreateGroup(pdnObject,
pwszName,
dwNameSize,
pvData,
dwDataSize,
pdpnGroupInfo->dwInfoFlags,
pdpnGroupInfo->dwGroupFlags,
pvGroupContext,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to create group");
}
else
{
if (!(dwFlags & DPNCREATEGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
hAsyncOp = 0;
}
}
}
else
{
DPFX(DPFPREP, 3,"Request host to create group");
hResultCode = DNRequestCreateGroup( pdnObject,
pwszName,
dwNameSize,
pvData,
dwDataSize,
pdpnGroupInfo->dwGroupFlags,
pvGroupContext,
pvAsyncContext,
&hAsyncOp,
dwFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to create group");
hResultCode = DPNERR_GENERIC;
#pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
}
else
{
if (!(dwFlags & DPNCREATEGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
}
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_DestroyGroup"
STDMETHODIMP DN_DestroyGroup(PVOID pInterface,
const DPNID dpnidGroup,
PVOID const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
CNameTableEntry *pLocalPlayer;
CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,dpnidGroup,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateDestroyGroup( pInterface, dpnidGroup, pvAsyncContext,
phAsyncHandle, dwFlags ) ) )
{
DPFERR( "Error validating destroy group params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to destroy a group" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pLocalPlayer = NULL;
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
{
DPFERR( "Could not find specified group" );
DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
{
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pLocalPlayer->IsHost())
{
DPFX(DPFPREP, 3,"Host is destroying group");
hResultCode = DNHostDestroyGroup( pdnObject,
dpnidGroup,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to destroy group");
}
else
{
if (!(dwFlags & DPNDESTROYGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
hAsyncOp = 0;
}
}
}
else
{
DPFX(DPFPREP, 3,"Request host to destroy group");
hResultCode = DNRequestDestroyGroup(pdnObject,
dpnidGroup,
pvAsyncContext,
&hAsyncOp,
dwFlags);
if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
{
DPFERR("Could not request host to destroy group");
hResultCode = DPNERR_GENERIC;
#pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
}
else
{
if (!(dwFlags & DPNDESTROYGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
}
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_AddClientToGroup"
STDMETHODIMP DN_AddClientToGroup(PVOID pInterface,
const DPNID dpnidGroup,
const DPNID dpnidClient,
PVOID const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
CNameTableEntry *pLocalPlayer;
CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateAddClientToGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext,
phAsyncHandle, dwFlags ) ))
{
DPFERR( "Error validating add client to group params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to add a player to a group" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pLocalPlayer = NULL;
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
{
DPFERR( "Unable to find specified group" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
DPFERR( "Unable to specify client or all players group for group ID" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK)
{
DPFERR( "Unable to find specified player" );
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if (pNTEntry->IsGroup())
{
DPFERR( "Specified client is a group ID" );
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pLocalPlayer->IsHost())
{
DPFX(DPFPREP, 3,"Host is adding player to group");
hResultCode = DNHostAddPlayerToGroup( pdnObject,
dpnidGroup,
dpnidClient,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to add player to group");
}
else
{
if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
hAsyncOp = 0;
}
}
}
else
{
DPFX(DPFPREP, 3,"Request host to add player to group");
hResultCode = DNRequestAddPlayerToGroup(pdnObject,
dpnidGroup,
dpnidClient,
pvAsyncContext,
&hAsyncOp,
dwFlags);
if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
{
DPFERR("Could not request host to add player to group");
hResultCode = DPNERR_GENERIC;
#pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
}
else
{
if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
}
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_RemoveClientFromGroup"
STDMETHODIMP DN_RemoveClientFromGroup(PVOID pInterface,
const DPNID dpnidGroup,
const DPNID dpnidClient,
PVOID const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
CNameTableEntry *pLocalPlayer;
CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateRemoveClientFromGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext, phAsyncHandle, dwFlags ) ))
{
DPFERR( "Error validating remove client from group params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to remove a player from a group" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pLocalPlayer = NULL;
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
{
DPFERR( "Could not find specified group in nametable" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
DPFERR( "Specified ID is not a valid group!" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK)
{
DPFERR( "Specified client ID is not a valid client!" );
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if (pNTEntry->IsGroup())
{
DPFERR( "Specified client ID is a group!" );
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pLocalPlayer->IsHost())
{
DPFX(DPFPREP, 3,"Host is deleting player from group");
hResultCode = DNHostDeletePlayerFromGroup( pdnObject,
dpnidGroup,
dpnidClient,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to delete player from group");
}
else
{
if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
hAsyncOp = 0;
}
}
}
else
{
DPFX(DPFPREP, 3,"Request host to delete player from group");
hResultCode = DNRequestDeletePlayerFromGroup(pdnObject,
dpnidGroup,
dpnidClient,
pvAsyncContext,
&hAsyncOp,
dwFlags);
if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
{
DPFERR("Could not request host to delete player from group");
hResultCode = DPNERR_GENERIC;
#pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
}
else
{
if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
}
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
// DN_SetGroupInfo
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SetGroupInfo"
STDMETHODIMP DN_SetGroupInfo( PVOID pv,
const DPNID dpnid,
DPN_GROUP_INFO *const pdpnGroupInfo,
PVOID const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
DPNHANDLE hAsyncOp;
PWSTR pwszName;
DWORD dwNameSize;
PVOID pvData;
DWORD dwDataSize;
CNameTableEntry *pLocalPlayer;
CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pv,dpnid,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateSetGroupInfo( pv, dpnid, pdpnGroupInfo, pvAsyncContext, phAsyncHandle, dwFlags ) ) )
{
DPFERR( "Error validating set group info params" );
DPF_RETURN( hResultCode );
}
}
#endif // DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to set group info" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pLocalPlayer = NULL;
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR( "Specified ID is not a group" );
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
DPFERR( "Specified ID is not a valid group" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName))
{
pwszName = pdpnGroupInfo->pwszName;
dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR);
}
else
{
pwszName = NULL;
dwNameSize = 0;
}
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize))
{
pvData = pdpnGroupInfo->pvData;
dwDataSize = pdpnGroupInfo->dwDataSize;
}
else
{
pvData = NULL;
dwDataSize = 0;
}
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pLocalPlayer->IsHost())
{
DPFX(DPFPREP, 3,"Host is updating group info");
hResultCode = DNHostUpdateInfo( pdnObject,
dpnid,
pwszName,
dwNameSize,
pvData,
dwDataSize,
pdpnGroupInfo->dwInfoFlags,
pvAsyncContext,
pLocalPlayer->GetDPNID(),
0,
&hAsyncOp,
dwFlags );
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not request host to update info");
}
else
{
if (!(dwFlags & DPNSETGROUPINFO_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
// TODO: MASONB: Why does DNHostUpdateInfo do this? This same code is duplicated
// everywhere.
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
hAsyncOp = 0;
}
}
}
else
{
DPFX(DPFPREP, 3,"Request host to update group info");
hResultCode = DNRequestUpdateInfo( pdnObject,
dpnid,
pwszName,
dwNameSize,
pvData,
dwDataSize,
pdpnGroupInfo->dwInfoFlags,
pvAsyncContext,
&hAsyncOp,
dwFlags);
if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
{
DPFERR("Could not request host to update info");
}
else
{
if (!(dwFlags & DPNSETGROUPINFO_SYNC))
{
DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
*phAsyncHandle = hAsyncOp;
}
}
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
// DN_GetGroupInfo
//
// Retrieve group name and/or data from the local nametable.
//
// lpwszGroupName may be NULL to avoid retrieving group name
// pdwGroupFlags may be NULL to avoid retrieving group flags
// pvGroupData may not by NULL if *pdwDataSize is non zero
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetGroupInfo"
STDMETHODIMP DN_GetGroupInfo(PVOID pv,
const DPNID dpnid,
DPN_GROUP_INFO *const pdpnGroupInfo,
DWORD *const pdwSize,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
CNameTableEntry *pNTEntry;
CPackedBuffer packedBuffer;
HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], pdpnGroupInfo [0x%p], dwFlags [0x%lx]",
dpnid,pdpnGroupInfo,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetGroupInfo( pv, dpnid, pdpnGroupInfo, pdwSize, dwFlags ) ) )
{
DPFERR( "Error validating get group info params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING)) )
{
DPFERR("You must be connected / hosting to get group info" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR( "Specified group is not valid" );
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
}
packedBuffer.Initialize(pdpnGroupInfo,*pdwSize);
pNTEntry->Lock();
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
DPFERR( "Specified ID is not a group" );
pNTEntry->Unlock();
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
hResultCode = pNTEntry->PackInfo(&packedBuffer);
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
if ((hResultCode == DPN_OK) || (hResultCode == DPNERR_BUFFERTOOSMALL))
{
*pdwSize = packedBuffer.GetSizeRequired();
}
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumClientsAndGroups"
STDMETHODIMP DN_EnumClientsAndGroups(PVOID pInterface,
DPNID *const prgdpnid,
DWORD *const pcdpnid,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
CBilink *pBilink;
CNameTableEntry *pNTEntry;
DWORD dwCount;
DPNID *pDPNID;
BOOL bEnum = TRUE;
HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]",
pInterface,prgdpnid,pcdpnid,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateEnumClientsAndGroups( pInterface, prgdpnid, pcdpnid, dwFlags ) ) )
{
DPFERR( "Error validating enum clients and groups params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to enumerate players and groups" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
if (prgdpnid == NULL || *pcdpnid == 0) // Don't enum if not asked to
{
bEnum = FALSE;
}
pdnObject->NameTable.ReadLock();
dwCount = 0;
pDPNID = prgdpnid;
//
// Enum players
//
if (dwFlags & DPNENUM_PLAYERS)
{
pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
{
pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
pNTEntry->Lock();
if (pNTEntry->IsAvailable())
{
dwCount++;
if (bEnum && (dwCount <= *pcdpnid))
{
*pDPNID++ = pNTEntry->GetDPNID();
}
else
{
bEnum = FALSE;
}
}
pNTEntry->Unlock();
pBilink = pBilink->GetNext();
}
}
//
// Enum groups
//
if (dwFlags & DPNENUM_GROUPS)
{
pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkGroups)
{
pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
pNTEntry->Lock();
if (pNTEntry->IsAvailable() && !pNTEntry->IsAllPlayersGroup())
{
dwCount++;
if (bEnum && (dwCount <= *pcdpnid))
{
*pDPNID++ = pNTEntry->GetDPNID();
}
else
{
bEnum = FALSE;
}
}
pNTEntry->Unlock();
pBilink = pBilink->GetNext();
}
}
pdnObject->NameTable.Unlock();
//
// This will NOT include players/groups in the deleted list.
// i.e. removed from the NameTable but for whom DESTROY_PLAYER/GROUP notifications have yet to be posted
//
*pcdpnid = dwCount;
if (!bEnum && dwCount)
{
hResultCode = DPNERR_BUFFERTOOSMALL;
}
else
{
hResultCode = DPN_OK;
}
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumGroupMembers"
STDMETHODIMP DN_EnumGroupMembers(PVOID pInterface,
const DPNID dpnid,
DPNID *const prgdpnid,
DWORD *const pcdpnid,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
CNameTableEntry *pNTEntry;
CGroupMember *pGroupMember;
CBilink *pBilink;
DWORD dwCount;
DPNID *pDPNID;
BOOL bOutputBufferTooSmall = FALSE;
HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnid [0x%lx], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]",
pInterface,dpnid,prgdpnid,pcdpnid,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateEnumGroupMembers( pInterface, dpnid, prgdpnid, pcdpnid, dwFlags ) ) )
{
DPFERR( "Error validating enum group params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to enumerate group members" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
//
// if the user didn't supply a buffer, assume that the
// output buffer is too small
//
if ( ( prgdpnid == NULL ) || ( ( *pcdpnid ) == 0 ) )
{
bOutputBufferTooSmall = TRUE;
}
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find NameTableEntry");
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
{
DPFERR("Not a group dpnid!");
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
pNTEntry->Lock();
dwCount = 0;
pDPNID = prgdpnid;
pBilink = pNTEntry->m_bilinkMembership.GetNext();
while (pBilink != &pNTEntry->m_bilinkMembership)
{
pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers);
dwCount++;
if ( ( bOutputBufferTooSmall == FALSE ) && (dwCount <= *pcdpnid))
{
*pDPNID++ = pGroupMember->GetPlayer()->GetDPNID();
}
else
{
bOutputBufferTooSmall = TRUE;
}
pBilink = pBilink->GetNext();
}
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
*pcdpnid = dwCount;
//
// if the user's output buffer appears to be incapable receiving
// output, double-check to make sure that the output size requirement
// isn't zero (which is really OK), before telling them that the
// output buffer is too small
//
if ( ( bOutputBufferTooSmall ) && ( dwCount != 0 ) )
{
hResultCode = DPNERR_BUFFERTOOSMALL;
}
else
{
hResultCode = DPN_OK;
}
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumHosts"
STDMETHODIMP DN_EnumHosts( PVOID pv,
DPN_APPLICATION_DESC *const pApplicationDesc,
IDirectPlay8Address *const pAddrHost,
IDirectPlay8Address *const pDeviceInfo,
PVOID const pUserEnumData,
const DWORD dwUserEnumDataSize,
const DWORD dwRetryCount,
const DWORD dwRetryInterval,
const DWORD dwTimeOut,
PVOID const pvAsyncContext,
DPNHANDLE *const pAsyncHandle,
const DWORD dwFlags )
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
HRESULT hrEnum;
#ifndef DPNBUILD_ONLYONESP
GUID guidSP;
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter;
#endif // ! DPNBUILD_ONLYONEADAPTER
CAsyncOp *pParent;
CAsyncOp *pHandleParent;
CSyncEvent *pSyncEvent;
CServiceProvider *pSP;
CRefCountBuffer *pRCBuffer;
DN_ENUM_QUERY_OP_DATA *pEnumQueryOpData;
IDirectPlay8Address *pIHost;
IDirectPlay8Address *pIDevice;
DPNHANDLE handle;
DPN_SP_CAPS dnSPCaps;
#ifndef DPNBUILD_ONLYONEADAPTER
BOOL fEnumAdapters;
#endif // ! DPNBUILD_ONLYONEADAPTER
BOOL fHosting;
DWORD dwBufferCount;
DWORD dwEnumQueryFlags;
DWORD dwMultiplexFlag;
GUID guidnull;
#ifdef DBG
TCHAR DP8ABuffer[512] = {0};
DWORD DP8ASize;
#endif // DBG
DPFX(DPFPREP, 2,"Parameters: pApplicationDesc [0x%p], pAddrHost [0x%p], pDeviceInfo [0x%p], pUserEnumData [0x%p], dwUserEnumDataSize [%ld], dwRetryCount [%ld], dwRetryInterval [%ld], dwTimeOut [%ld], pvAsyncContext [0x%p], pAsyncHandle [0x%p], dwFlags [0x%lx]",
pApplicationDesc,pAddrHost,pDeviceInfo,pUserEnumData,dwUserEnumDataSize,dwRetryCount,dwRetryInterval,dwTimeOut,pvAsyncContext,pAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateEnumHosts( pv, pApplicationDesc, pAddrHost,
pDeviceInfo, pUserEnumData, dwUserEnumDataSize,
dwRetryCount, dwRetryInterval, dwTimeOut,
pvAsyncContext, pAsyncHandle, dwFlags ) ) )
{
DPFERR( "Error validating enum hosts params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
//
// initialize
//
hResultCode = DPN_OK;
pParent = NULL;
pHandleParent = NULL;
pSyncEvent = NULL;
pRCBuffer = NULL;
pSP = NULL;
pIHost = NULL;
pIDevice = NULL;
handle = 0;
dwMultiplexFlag = 0;
#ifdef DBG
if (pAddrHost)
{
DP8ASize = 512;
IDirectPlay8Address_GetURL(pAddrHost,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer);
}
if (pDeviceInfo)
{
DP8ASize = 512;
IDirectPlay8Address_GetURL(pDeviceInfo,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer);
}
#endif // DBG
//
// Cannot ENUM if Hosting - I have no idea why, but VanceO insisted on it
//
fHosting = FALSE;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CONNECTING))
{
CNameTableEntry *pLocalPlayer;
pLocalPlayer = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) == DPN_OK)
{
if (pLocalPlayer->IsHost())
{
fHosting = TRUE;
}
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
}
else
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
if (fHosting)
{
hResultCode = DPNERR_HOSTING;
goto Failure;
}
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
DNASSERT(pdnObject->pOnlySP != NULL);
pdnObject->pOnlySP->AddRef();
pSP = pdnObject->pOnlySP;
#else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONESP
//
// Extract SP guid as we will probably need it
//
hResultCode = IDirectPlay8Address_GetSP(pDeviceInfo,&guidSP);
if ( hResultCode != DPN_OK)
{
DPFERR("SP not specified in Device address");
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP specified in Device address is loaded
//
hResultCode = DN_SPEnsureLoaded(pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL,
#endif // ! DPNBUILD_LIBINTERFACE
&pSP);
if (hResultCode != DPN_OK)
{
DPFERR("Could not ensure SP is loaded!");
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
//
// Get SP caps to ensure payload will fit
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK)
{
DPFERR("Could not get SP caps");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Ensure payload will fit
//
if (dwUserEnumDataSize > dnSPCaps.dwMaxEnumPayloadSize)
{
DPFERR("User enum data is too large");
hResultCode = DPNERR_ENUMQUERYTOOLARGE;
goto Failure;
}
//
// Duplicate addresses for local usage (so we can modify them if neccessary
//
if (pAddrHost)
{
// Use supplied Host address
if ((hResultCode = IDirectPlay8Address_Duplicate(pAddrHost,&pIHost)) != DPN_OK)
{
DPFERR("Could not duplicate Host address");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDHOSTADDRESS;
goto Failure;
}
}
else
{
//
// Create new Host address and use Device SP guid
//
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIHost));
#else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIHost),
FALSE);
#endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK)
{
DPFERR("Could not create Host address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
#ifndef DPNBUILD_ONLYONESP
if ((hResultCode = IDirectPlay8Address_SetSP(pIHost,&guidSP)) != DPN_OK)
{
DPFERR("Could not set Host address SP");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP
}
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
if (pDeviceInfo == NULL)
{
hResultCode = IDirectPlay8Address_Duplicate(pIHost,&pIDevice);
}
else
#endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
{
hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice);
}
if (hResultCode != DPN_OK)
{
DPFERR("Could not duplicate Device address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
#ifdef DBG
DP8ASize = 512;
IDirectPlay8Address_GetURL(pIHost,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer);
DP8ASize = 512;
IDirectPlay8Address_GetURL(pIDevice,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer);
#endif // DBG
// Enum flags to Protocol
dwEnumQueryFlags = 0;
#ifndef DPNBUILD_NOSPUI
if (dwFlags & DPNENUMHOSTS_OKTOQUERYFORADDRESSING)
{
dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING;
}
#endif // ! DPNBUILD_NOSPUI
if (dwFlags & DPNENUMHOSTS_NOBROADCASTFALLBACK)
{
dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK;
}
if (pApplicationDesc->dwReservedDataSize > 0)
{
dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_SESSIONDATA;
}
//
// Parent for ENUMs
//
if ((hResultCode = AsyncOpNew(pdnObject,&pParent)) != DPN_OK)
{
DPFERR("Could not create ENUM parent AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pParent->MakeParent();
pParent->SetOpType( ASYNC_OP_ENUM_QUERY );
pParent->SetContext( pvAsyncContext );
pParent->SetCompletion( DNCompleteEnumQuery );
pParent->SetOpFlags( dwEnumQueryFlags );
//
// Synchronous ?
//
if (dwFlags & DPNENUMHOSTS_SYNC)
{
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create SyncEvent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pParent->SetSyncEvent( pSyncEvent );
pParent->SetResultPointer( &hrEnum );
hrEnum = DPNERR_GENERIC;
}
else
{
//
// Create Handle parent AsyncOp (if required)
//
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pHandleParent->SetContext( pvAsyncContext );
pHandleParent->Lock();
if (pHandleParent->IsCancelled())
{
pHandleParent->Unlock();
pParent->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pParent->MakeChild( pHandleParent );
handle = pHandleParent->GetHandle();
pHandleParent->Unlock();
}
//
// Keep SP on ENUM parent
//
pParent->SetSP( pSP );
pSP->Release();
pSP = NULL;
pEnumQueryOpData = pParent->GetLocalEnumQueryOpData();
#ifndef DPNBUILD_ONLYONEADAPTER
//
// If there is no adapter specified in the device address,
// we will attempt to enum on each individual adapter if the SP supports it
//
fEnumAdapters = FALSE;
if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK)
{
DPFX(DPFPREP,1,"Could not determine adapter");
DisplayDNError(1,hResultCode);
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS)
{
DPFX(DPFPREP, 3,"SP supports ENUMing on all adapters");
fEnumAdapters = TRUE;
}
}
if(fEnumAdapters)
{
DWORD dwNumAdapters;
GUID *pAdapterList = NULL;
if ((hResultCode = DNEnumAdapterGuids( pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
0,
&pAdapterList,
&dwNumAdapters)) != DPN_OK)
{
DPFERR("Could not enum adapters for this SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (dwNumAdapters == 0)
{
DPFERR("No adapters were found for this SP");
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pEnumQueryOpData->dwNumAdapters = dwNumAdapters;
pEnumQueryOpData->dwCurrentAdapter = 0;
if (dwNumAdapters > 1)
{
dwMultiplexFlag |= DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS;
}
//
// Choose first adapter for initial ENUM call
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK)
{
DPFERR("Could not set device adapter");
DisplayDNError(0,hResultCode);
MemoryBlockFree(pdnObject,pAdapterList);
goto Failure;
}
pEnumQueryOpData->dwCurrentAdapter++;
pParent->SetOpData( pAdapterList );
pAdapterList = NULL;
}
else
#endif // ! DPNBUILD_ONLYONEADAPTER
{
#ifndef DPNBUILD_ONLYONEADAPTER
pEnumQueryOpData->dwNumAdapters = 0;
pEnumQueryOpData->dwCurrentAdapter = 0;
#endif // ! DPNBUILD_ONLYONEADAPTER
}
//
// Set up EnumQuery BufferDescriptions
//
//
// When filling out the enum structure the SP requires an extra BUFFERDESC
// to exist immediately before the one were passing with the user data. The
// SP will be using that extra buffer to prepend an optional header
//
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(&pEnumQueryOpData->EnumQueryPayload);
memset(&guidnull, 0, sizeof(guidnull));
if (pApplicationDesc->guidApplication != guidnull)
{
DPFX(DPFPREP, 7, "Object 0x%p enumerating with application GUID {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.",
pdnObject,
pApplicationDesc->guidApplication.Data1,
pApplicationDesc->guidApplication.Data2,
pApplicationDesc->guidApplication.Data3,
pApplicationDesc->guidApplication.Data4[0],
pApplicationDesc->guidApplication.Data4[1],
pApplicationDesc->guidApplication.Data4[2],
pApplicationDesc->guidApplication.Data4[3],
pApplicationDesc->guidApplication.Data4[4],
pApplicationDesc->guidApplication.Data4[5],
pApplicationDesc->guidApplication.Data4[6],
pApplicationDesc->guidApplication.Data4[7]);
pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITH_APPLICATION_GUID;
memcpy(&pEnumQueryOpData->EnumQueryPayload.guidApplication,&pApplicationDesc->guidApplication,sizeof(GUID));
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD);
}
else
{
pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITHOUT_APPLICATION_GUID;
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD) - sizeof(GUID);
}
//
// Copy user data (if any)
//
if (pUserEnumData && dwUserEnumDataSize)
{
DPFX(DPFPREP,3,"User enum data specified");
if ((hResultCode = RefCountBufferNew(pdnObject,dwUserEnumDataSize,MemoryBlockAlloc,MemoryBlockFree,&pRCBuffer)) != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
memcpy(pRCBuffer->GetBufferAddress(),pUserEnumData,dwUserEnumDataSize);
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(pRCBuffer->GetBufferAddress());
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = dwUserEnumDataSize;
pParent->SetRefCountBuffer( pRCBuffer );
dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT;
pRCBuffer->Release();
pRCBuffer = NULL;
}
else
{
DPFX(DPFPREP,3,"User enum data not specified");
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = NULL;
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = 0;
dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT - 1;
}
//
// Set up EnumQuery misc fields
//
pEnumQueryOpData->dwRetryCount = dwRetryCount;
pEnumQueryOpData->dwRetryInterval = dwRetryInterval;
pEnumQueryOpData->dwTimeOut = dwTimeOut;
pEnumQueryOpData->dwBufferCount = dwBufferCount;
//
// For reserved data we understand, we don't actually need all of the data we had the
// user track.
//
if ((pApplicationDesc->dwReservedDataSize == DPN_MAX_APPDESC_RESERVEDDATA_SIZE) &&
(*((DWORD*) pApplicationDesc->pvReservedData) == SPSESSIONDATAINFO_XNET))
{
pEnumQueryOpData->dwAppDescReservedDataSize = sizeof(SPSESSIONDATA_XNET);
memcpy(pEnumQueryOpData->AppDescReservedData, &pApplicationDesc->pvReservedData, pEnumQueryOpData->dwAppDescReservedDataSize);
}
else
{
pEnumQueryOpData->dwAppDescReservedDataSize = 0;
}
DPFX(DPFPREP,3,"Number of buffers actually used [%ld]",dwBufferCount);
hResultCode = DNPerformEnumQuery( pdnObject,
pIHost,
pIDevice,
pParent->GetSP()->GetHandle(),
pParent->GetOpFlags() | dwMultiplexFlag,
pParent->GetContext(),
pParent );
if (hResultCode != DPN_OK)
{
DPFERR("Could not start ENUM");
DisplayDNError(0,hResultCode);
goto Failure;
}
pParent->Release();
pParent = NULL;
//
// Wait for SyncEvent or return Async Handle
//
if (dwFlags & DPNENUMHOSTS_SYNC)
{
pSyncEvent->WaitForEvent();
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
hResultCode = hrEnum;
}
else
{
//
// Blame vanceo if this EVER returns anything other than DPN_OK at this stage
//
pHandleParent->SetCompletion( DNCompleteAsyncHandle );
pHandleParent->Release();
pHandleParent = NULL;
*pAsyncHandle = handle;
hResultCode = DPNERR_PENDING;
}
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
IDirectPlay8Address_Release(pIHost);
pIHost = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (handle != 0)
{
CAsyncOp* pAsyncOp;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp )))
{
// Release the HandleTable reference
pAsyncOp->Release();
pAsyncOp = NULL;
}
handle = 0;
}
if (pParent)
{
pParent->Release();
pParent = NULL;
}
if (pHandleParent)
{
pHandleParent->Release();
pHandleParent = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
if (pRCBuffer)
{
pRCBuffer->Release();
pRCBuffer = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pIHost)
{
IDirectPlay8Address_Release(pIHost);
pIHost = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
goto Exit;
}
//**********************************************************************
// DN_DestroyPlayer
//
// Remove a player from this DirectNet session
// This will send a termination message to the player.
// Both the host and the player will terminate.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_DestroyPlayer"
STDMETHODIMP DN_DestroyPlayer(PVOID pInterface,
const DPNID dpnid,
const void *const pvDestroyData,
const DWORD dwDestroyDataSize,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
CRefCountBuffer *pRefCountBuffer;
CNameTableEntry *pNTEntry;
CConnection *pConnection;
DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], dpnid [0x%lx], pvDestroyData [0x%p], dwDestroyDataSize [%ld], dwFlags [0x%lx]",
pInterface,dpnid,pvDestroyData,dwDestroyDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateDestroyPlayer( pInterface, dpnid, pvDestroyData, dwDestroyDataSize, dwFlags ) ) )
{
DPFERR( "Error validating destroy player params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to destroy a player" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
pRefCountBuffer = NULL;
pConnection = NULL;
if (!DN_CHECK_LOCALHOST(pdnObject))
{
DPFERR( "Object is not session host, cannot destroy players" );
DPF_RETURN(DPNERR_NOTHOST);
}
// Ensure DNID specified is valid
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find player entry");
DisplayDNError(0,hResultCode);
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
if (pNTEntry->IsLocal() )
{
DPFERR( "Cannot destroy local player" );
hResultCode = DPNERR_INVALIDPLAYER;
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pNTEntry->IsGroup())
{
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
{
DPFERR("Could not get connection ref");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_CONNECTIONLOST;
goto Failure;
}
pNTEntry->Release();
pNTEntry = NULL;
//
// Build terminate message
//
hResultCode = RefCountBufferNew(pdnObject,
sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwDestroyDataSize,
MemoryBlockAlloc,
MemoryBlockFree,
&pRefCountBuffer);
if (hResultCode != DPN_OK)
{
DPFERR("Could not allocate RefCountBuffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress());
if (dwDestroyDataSize)
{
memcpy(pMsg+1,pvDestroyData,dwDestroyDataSize);
pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION);
}
else
{
pMsg->dwTerminateDataOffset = 0;
}
pMsg->dwTerminateDataSize = dwDestroyDataSize;
//
// Send message to player to exit
//
hResultCode = DNSendMessage(pdnObject,
pConnection,
DN_MSG_INTERNAL_TERMINATE_SESSION,
dpnid,
pRefCountBuffer->BufferDescAddress(),
1,
pRefCountBuffer,
0,
DN_SENDFLAGS_RELIABLE,
NULL,
NULL);
if (hResultCode != DPNERR_PENDING)
{
DPFERR("Could not send DESTROY_CLIENT message to player");
DisplayDNError(0,hResultCode);
DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
if (hResultCode == DPNERR_INVALIDENDPOINT)
{
hResultCode = DPNERR_INVALIDPLAYER;
}
goto Failure;
}
pConnection->Release();
pConnection = NULL;
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
//
// Remove from NameTable and inform other players of disconnect
//
hResultCode = DNHostDisconnect(pdnObject,dpnid,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
goto Exit;
}
// DN_ReturnBuffer
//
// Return a receive buffer which is no longer in use
#undef DPF_MODNAME
#define DPF_MODNAME "DN_ReturnBuffer"
STDMETHODIMP DN_ReturnBuffer(PVOID pv,
const DPNHANDLE hBufferHandle,
const DWORD dwFlags)
{
DIRECTNETOBJECT *pdnObject;
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
DPFX(DPFPREP, 2,"Parameters: hBufferHandle [0x%lx], dwFlags [0x%lx]",hBufferHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateReturnBuffer( pv, hBufferHandle, dwFlags ) ) )
{
DPFERR( "Error validating return buffer params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to return a buffer" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
DNASSERT( pdnObject != NULL );
pAsyncOp = NULL;
//
// Find async op
//
pdnObject->HandleTable.Lock();
if ((hResultCode = pdnObject->HandleTable.Find( hBufferHandle,(PVOID*)&pAsyncOp )) != DPN_OK)
{
pdnObject->HandleTable.Unlock();
DPFERR("Could not find handle");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDHANDLE;
goto Failure;
}
else
{
pAsyncOp->AddRef();
pdnObject->HandleTable.Unlock();
}
//
// Ensure it's not already cancelled
//
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() || pAsyncOp->IsComplete())
{
pAsyncOp->Unlock();
hResultCode = DPNERR_INVALIDHANDLE;
goto Failure;
}
pAsyncOp->SetComplete();
pAsyncOp->Unlock();
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hBufferHandle, NULL )))
{
//
// Remove from active list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
// Release the HandleTable reference
pAsyncOp->Release();
}
pAsyncOp->Release();
pAsyncOp = NULL;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
// DN_GetPlayerContext
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetPlayerContext"
STDMETHODIMP DN_GetPlayerContext(PVOID pv,
const DPNID dpnid,
PVOID *const ppvPlayerContext,
const DWORD dwFlags)
{
HRESULT hResultCode;
CNameTableEntry *pNTEntry;
DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvPlayerContext [0x%p], dwFlags [0x%lx]",
pv, dpnid,ppvPlayerContext,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetPlayerContext( pv, dpnid, ppvPlayerContext, dwFlags ) ) )
{
DPFERR( "Error validating getplayercontext params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
{
DPFERR("You must be connected / hosting to get player context" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not retrieve player entry");
DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find player in deleted list either");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
}
//
// Ensure this is not a group and that the player has been created
// There may be a period during which the player is "available" but the CREATE_PLAYER notification
// has not returned. Return DPNERR_NOTREADY in this case.
//
pNTEntry->Lock();
if (pNTEntry->IsGroup())
{
pNTEntry->Unlock();
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
if (!pNTEntry->IsCreated())
{
if (pNTEntry->IsAvailable())
{
hResultCode = DPNERR_NOTREADY;
}
else
{
hResultCode = DPNERR_INVALIDPLAYER;
}
pNTEntry->Unlock();
goto Failure;
}
*ppvPlayerContext = pNTEntry->GetContext();
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
// DN_GetGroupContext
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetGroupContext"
STDMETHODIMP DN_GetGroupContext(PVOID pv,
const DPNID dpnid,
PVOID *const ppvGroupContext,
const DWORD dwFlags)
{
HRESULT hResultCode;
CNameTableEntry *pNTEntry;
DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvGroupContext [0x%p], dwFlags [0x%lx]",
pv, dpnid,ppvGroupContext,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetGroupContext( pv, dpnid, ppvGroupContext,dwFlags ) ) )
{
DPFERR( "Error validating getgroupcontext params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
{
DPFERR("You must be connected / hosting to get group context" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not retrieve group entry");
DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find player in deleted list either");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
}
//
// Ensure this is not a player and that the group has been created
// There may be a period during which the group is "available" but the CREATE_GROUP notification
// has not returned. Return DPNERR_NOTREADY in this case.
//
pNTEntry->Lock();
if (!pNTEntry->IsGroup())
{
pNTEntry->Unlock();
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
if (!pNTEntry->IsCreated())
{
if (pNTEntry->IsAvailable())
{
hResultCode = DPNERR_NOTREADY;
}
else
{
hResultCode = DPNERR_INVALIDGROUP;
}
pNTEntry->Unlock();
goto Failure;
}
if( pNTEntry->IsAllPlayersGroup() )
{
pNTEntry->Unlock();
DPFERR("Cannot getcontext for the all players group" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
*ppvGroupContext = pNTEntry->GetContext();
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_RegisterLobby"
STDMETHODIMP DN_RegisterLobby(PVOID pInterface,
const DPNHANDLE dpnhLobbyConnection,
IDirectPlay8LobbiedApplication *const pIDP8LobbiedApplication,
const DWORD dwFlags)
{
#ifdef DPNBUILD_NOLOBBY
DPFX(DPFPREP, 0, "RegisterLobby is not supported!");
return DPNERR_UNSUPPORTED;
#else // ! DPNBUILD_NOLOBBY
DIRECTNETOBJECT *pdnObject;
#ifndef DPNBUILD_NOPARAMVAL
HRESULT hResultCode;
#endif // DPNBUILD_NOPARAMVAL
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pIDP8LobbiedApplication [0x%p], dwFlags [0x%lx]",
pInterface,pIDP8LobbiedApplication,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateRegisterLobby( pInterface, dpnhLobbyConnection, pIDP8LobbiedApplication, dwFlags ) ) )
{
DPFERR( "Error validating register lobby params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
if (dwFlags == DPNLOBBY_REGISTER)
{
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE)
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
return(DPNERR_ALREADYREGISTERED);
}
IDirectPlay8LobbiedApplication_AddRef(pIDP8LobbiedApplication);
pdnObject->pIDP8LobbiedApplication = pIDP8LobbiedApplication;
pdnObject->dpnhLobbyConnection = dpnhLobbyConnection;
pdnObject->dwFlags |= DN_OBJECT_FLAG_LOBBY_AWARE;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
else
{
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
return(DPNERR_NOTREGISTERED);
}
IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication);
pdnObject->dpnhLobbyConnection = NULL;
pdnObject->pIDP8LobbiedApplication = NULL;
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_LOBBY_AWARE);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
return(DPN_OK);
#endif // ! DPNBUILD_NOLOBBY
}
#ifndef DPNBUILD_NOLOBBY
#undef DPF_MODNAME
#define DPF_MODNAME "DNNotifyLobbyClientOfSettings"
//
// DNNotifyLobbyClientOfSettings
//
// This function sends a connection settings update to the lobby client informing it that the lobby
// client settings have changed.
//
HRESULT DNNotifyLobbyClientOfSettings(
DIRECTNETOBJECT * const pdnObject,
IDirectPlay8LobbiedApplication *pdpLobbiedApp,
DPNHANDLE dpnConnection,
IDirectPlay8Address *pHostAddress,
IDirectPlay8Address *pConnectFromAddress )
{
HRESULT hResultCode = DPN_OK;
DPL_CONNECTION_SETTINGS dplConnectionSettings;
BOOL fIsHost = FALSE;
CPackedBuffer packBuffer;
PBYTE pBuffer = NULL;
BOOL fINCriticalSection = FALSE;
CNameTableEntry *pNTEntry = NULL;
DWORD dwIndex;
fIsHost = DN_CHECK_LOCALHOST( pdnObject );
ZeroMemory( &dplConnectionSettings, sizeof( DPL_CONNECTION_SETTINGS ) );
dplConnectionSettings.dwSize = sizeof( DPL_CONNECTION_SETTINGS );
dplConnectionSettings.dwFlags = (fIsHost) ? DPLCONNECTSETTINGS_HOST : 0;
// Lock the object while we make a copy of the app desc.
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
fINCriticalSection = TRUE;
// Determine the size of buffer
packBuffer.Initialize(NULL, 0 );
hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if( hResultCode != DPNERR_BUFFERTOOSMALL )
{
DPFX(DPFPREP, 0, "Error getting app desc size hr=0x%x", hResultCode );
goto NOTIFY_EXIT;
}
pBuffer = (BYTE*) DNMalloc(packBuffer.GetSizeRequired());
if( !pBuffer )
{
DPFX(DPFPREP, 0, "Error allocating memory for buffer" );
hResultCode = DPNERR_OUTOFMEMORY;
goto NOTIFY_EXIT;
}
packBuffer.Initialize(pBuffer,packBuffer.GetSizeRequired());
hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if( FAILED( hResultCode ) )
{
DPFX(DPFPREP, 0, "Error packing app desc hr=0x%x", hResultCode );
goto NOTIFY_EXIT;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
fINCriticalSection = FALSE;
memcpy( &dplConnectionSettings.dpnAppDesc, pBuffer, sizeof( DPN_APPLICATION_DESC ) );
hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry );
if( FAILED( hResultCode ) )
{
DPFX(DPFPREP, 0, "Error getting local player hr=0x%x", hResultCode );
goto NOTIFY_EXIT;
}
// Make sure player name isn't changed while we are working with the entry
pNTEntry->Lock();
if( pNTEntry->GetName() )
{
dplConnectionSettings.pwszPlayerName = (WCHAR*) DNMalloc((wcslen(pNTEntry->GetName())+1)*sizeof(WCHAR));
if( !dplConnectionSettings.pwszPlayerName )
{
pNTEntry->Unlock();
DPFX(DPFPREP, 0, "Error allocating memory" );
goto NOTIFY_EXIT;
}
wcscpy( dplConnectionSettings.pwszPlayerName, pNTEntry->GetName() );
}
else
{
dplConnectionSettings.pwszPlayerName = NULL;
}
pNTEntry->Unlock();
// Release our reference
pNTEntry->Release();
// Host address field
if( fIsHost )
{
dplConnectionSettings.pdp8HostAddress = NULL;
hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
if( hResultCode != DPNERR_BUFFERTOOSMALL )
{
dplConnectionSettings.cNumDeviceAddresses = 0;
DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode );
goto NOTIFY_EXIT;
}
dplConnectionSettings.ppdp8DeviceAddresses = (IDirectPlay8Address**) DNMalloc(dplConnectionSettings.cNumDeviceAddresses*sizeof(IDirectPlay8Address*));
if( !dplConnectionSettings.ppdp8DeviceAddresses )
{
DPFX(DPFPREP, 0, "Error allocating memory" );
dplConnectionSettings.cNumDeviceAddresses = 0;
hResultCode = DPNERR_OUTOFMEMORY;
goto NOTIFY_EXIT;
}
hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
if( FAILED( hResultCode ) )
{
dplConnectionSettings.cNumDeviceAddresses = 0;
DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode );
goto NOTIFY_EXIT;
}
}
else
{
dplConnectionSettings.pdp8HostAddress = pHostAddress;
dplConnectionSettings.ppdp8DeviceAddresses = &pConnectFromAddress;
dplConnectionSettings.cNumDeviceAddresses = 1;
}
// Update the settings
hResultCode = IDirectPlay8LobbiedApplication_SetConnectionSettings( pdpLobbiedApp, dpnConnection, &dplConnectionSettings, 0 );
NOTIFY_EXIT:
if( dplConnectionSettings.ppdp8DeviceAddresses && fIsHost )
{
for( dwIndex = 0; dwIndex < dplConnectionSettings.cNumDeviceAddresses; dwIndex++ )
{
IDirectPlay8Address_Release( dplConnectionSettings.ppdp8DeviceAddresses[dwIndex] );
}
DNFree(dplConnectionSettings.ppdp8DeviceAddresses);
}
if( dplConnectionSettings.pwszPlayerName )
DNFree(dplConnectionSettings.pwszPlayerName);
if( fINCriticalSection )
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if( pBuffer )
DNFree(pBuffer);
return hResultCode;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNUpdateLobbyStatus"
HRESULT DNUpdateLobbyStatus(DIRECTNETOBJECT *const pdnObject,
const DWORD dwStatus)
{
HRESULT hResultCode;
IDirectPlay8LobbiedApplication *pIDP8LobbiedApplication;
DPNHANDLE dpnhLobbyConnection = NULL;
IDirectPlay8Address *pHostAddress = NULL;
IDirectPlay8Address *pConnectFromAddress = NULL;
DPFX(DPFPREP, 4,"Parameters: dwStatus [0x%lx]",dwStatus);
DNASSERT(pdnObject != NULL);
pIDP8LobbiedApplication = NULL;
//
// Get lobbied application interface, if it exists and other settings we need
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE) && (pdnObject->pIDP8LobbiedApplication))
{
IDirectPlay8LobbiedApplication_AddRef(pdnObject->pIDP8LobbiedApplication);
pIDP8LobbiedApplication = pdnObject->pIDP8LobbiedApplication;
dpnhLobbyConnection = pdnObject->dpnhLobbyConnection;
pConnectFromAddress = pdnObject->pIDP8ADevice;
pHostAddress = pdnObject->pConnectAddress;
if( pConnectFromAddress )
{
IDirectPlay8Address_AddRef( pConnectFromAddress );
}
if( pHostAddress )
{
IDirectPlay8Address_AddRef( pHostAddress );
}
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Update status and release object
//
if (pIDP8LobbiedApplication)
{
// If we are about to do a connection notification
// we send the updated connection settings.
//
// This gives lobby client full picture.
//
if( dwStatus == DPLSESSION_CONNECTED )
{
DNNotifyLobbyClientOfSettings(pdnObject, pIDP8LobbiedApplication, dpnhLobbyConnection, pHostAddress, pConnectFromAddress );
}
IDirectPlay8LobbiedApplication_UpdateStatus(pIDP8LobbiedApplication,dpnhLobbyConnection,dwStatus,0);
IDirectPlay8LobbiedApplication_Release(pIDP8LobbiedApplication);
pIDP8LobbiedApplication = NULL;
if( pHostAddress )
{
IDirectPlay8Address_Release( pHostAddress );
}
if( pConnectFromAddress )
{
IDirectPlay8Address_Release( pConnectFromAddress );
}
}
hResultCode = DPN_OK;
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#endif // ! DPNBUILD_NOLOBBY
#undef DPF_MODNAME
#define DPF_MODNAME "DN_TerminateSession"
STDMETHODIMP DN_TerminateSession(PVOID pInterface,
void *const pvTerminateData,
const DWORD dwTerminateDataSize,
const DWORD dwFlags)
{
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
CRefCountBuffer *pRefCountBuffer;
CWorkerJob *pWorkerJob;
DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvTerminateData [0x%p], dwTerminateDataSize [%ld], dwFlags [0x%lx]",
pInterface,pvTerminateData,dwTerminateDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateTerminateSession( pInterface, pvTerminateData, dwTerminateDataSize, dwFlags ) ) )
{
DPFERR( "Error validating terminatesession params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to terminate a session" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pRefCountBuffer = NULL;
pWorkerJob = NULL;
if (!DN_CHECK_LOCALHOST(pdnObject))
{
DPFERR( "Object is not session host, cannot destroy players" );
hResultCode = DPNERR_NOTHOST;
goto Failure;
}
//
// Build terminate message
//
hResultCode = RefCountBufferNew(pdnObject,
sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwTerminateDataSize,
MemoryBlockAlloc,
MemoryBlockFree,
&pRefCountBuffer);
if (hResultCode != DPN_OK)
{
DPFERR("Could not allocate RefCountBuffer");
DisplayDNError(0,hResultCode);
goto Failure;
}
pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress());
if (dwTerminateDataSize)
{
memcpy(pMsg+1,pvTerminateData,dwTerminateDataSize);
pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION);
}
else
{
pMsg->dwTerminateDataOffset = 0;
}
pMsg->dwTerminateDataSize = dwTerminateDataSize;
//
// Worker job to send message to all players
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not allocate new WorkerJob");
DisplayDNError(0,hResultCode);
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_TERMINATE_SESSION );
pWorkerJob->SetSendNameTableOperationVersion( 0 );
pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
//
// Terminate local session
//
hResultCode = DNUserTerminateSession(pdnObject,
DPNERR_HOSTTERMINATEDSESSION,
pvTerminateData,
dwTerminateDataSize);
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not create WorkerJob");
DisplayDNError(0,hResultCode);
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_TERMINATE_SESSION );
pWorkerJob->SetTerminateSessionReason( DPNERR_HOSTTERMINATEDSESSION );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
goto Exit;
}
//
// FUnction that performs work for DN_GetHostAddress and for Lobby informs
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetHostAddressHelper"
HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject,
IDirectPlay8Address **const prgpAddress,
DWORD *const pcAddress)
{
CAsyncOp *pListenParent;
CAsyncOp *pListenSP;
CAsyncOp *pListen;
CBilink *pBilinkSP;
CBilink *pBilink;
DWORD dwListenCount;
CNameTableEntry *pLocalPlayer;
IDirectPlay8Address **ppAddress;
HRESULT hResultCode;
pListenParent = NULL;
pListenSP = NULL;
pListen = NULL;
pLocalPlayer = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_LISTENING)
|| !pLocalPlayer->IsHost()
|| (pdnObject->pListenParent == NULL))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFERR("Not listening or Host player");
hResultCode = DPNERR_NOTHOST;
goto Failure;
}
pdnObject->pListenParent->AddRef();
pListenParent = pdnObject->pListenParent;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pLocalPlayer->Release();
pLocalPlayer = NULL;
//
// Ensure that the address pointer buffer is large enough
//
dwListenCount = 0;
pListenParent->Lock(); // Prevent changes while we run through
pBilinkSP = pListenParent->m_bilinkParent.GetNext();
while (pBilinkSP != &pListenParent->m_bilinkParent)
{
pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext();
while (pBilink != &pListenSP->m_bilinkParent)
{
dwListenCount++;
pBilink = pBilink->GetNext();
}
pListenSP->Unlock();
pListenSP = NULL;
pBilinkSP = pBilinkSP->GetNext();
}
if (dwListenCount > *pcAddress)
{
pListenParent->Unlock();
*pcAddress = dwListenCount;
hResultCode = DPNERR_BUFFERTOOSMALL;
goto Failure;
}
//
// Get addresses of LISTENs
//
ppAddress = prgpAddress;
dwListenCount = 0;
pBilinkSP = pListenParent->m_bilinkParent.GetNext();
while (pBilinkSP != &pListenParent->m_bilinkParent)
{
pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext();
while (pBilink != &pListenSP->m_bilinkParent)
{
pListen = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
if (pListen->GetProtocolHandle() != NULL)
{
SPGETADDRESSINFODATA spInfoData;
memset(&spInfoData,0x00,sizeof(SPGETADDRESSINFODATA));
spInfoData.Flags = SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES;
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData,pListen->GetProtocolHandle(),&spInfoData)) != DPN_OK)
{
DPFERR("Could not get LISTEN address!");
DisplayDNError(0,hResultCode);
//
// Release all the addresses we have so far.
//
while (dwListenCount > 0)
{
dwListenCount--;
ppAddress--;
IDirectPlay8Address_Release(*ppAddress);
*ppAddress = NULL;
}
goto Failure;
}
*ppAddress++ = spInfoData.pAddress;
dwListenCount++;
}
pBilink = pBilink->GetNext();
}
pListenSP->Unlock();
pListenSP = NULL;
pBilinkSP = pBilinkSP->GetNext();
}
pListenParent->Unlock();
*pcAddress = dwListenCount;
hResultCode = DPN_OK;
pListenParent->Release();
pListenParent = NULL;
Exit:
DPF_RETURN(hResultCode);
Failure:
if (pListenParent)
{
pListenParent->Release();
pListenParent = NULL;
}
if (pLocalPlayer)
{
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
goto Exit;
}
//
// DN_GetHostAddress
//
// We will determine the host addresses by examining the LISTENs which are running.
// We do this because after Host migration, we may not be running the same LISTEN
// we started with.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetHostAddress"
STDMETHODIMP DN_GetHostAddress(PVOID pInterface,
IDirectPlay8Address **const prgpAddress,
DWORD *const pcAddress,
const DWORD dwFlags)
{
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], prgpAddress [0x%p], pcAddress [0x%p], dwFlags [0x%lx]",
pInterface,prgpAddress,pcAddress,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetHostAddress( pInterface, prgpAddress, pcAddress, dwFlags ) ) )
{
DPFERR( "Error validating gethostaddress params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
{
DPFERR("You must be connected / hosting to get host address" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
DNASSERT(pdnObject != NULL);
// Actually do the work and get the addresses
hResultCode = DNGetHostAddressHelper( pdnObject, prgpAddress, pcAddress );
DPF_RETURN(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNUpdateListens"
HRESULT DNUpdateListens(DIRECTNETOBJECT *const pdnObject,
const DWORD dwFlags)
{
HRESULT hResultCode;
CAsyncOp *pListenParent;
DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%u]", dwFlags);
DNASSERT( pdnObject != NULL );
DNASSERT( dwFlags != 0 );
DNASSERT( ! ((dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS)) );
hResultCode = DPNERR_GENERIC;
pListenParent = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pListenParent)
{
pdnObject->pListenParent->AddRef();
pListenParent = pdnObject->pListenParent;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pListenParent)
{
CBilink *pBilinkSP;
CBilink *pBilink;
CAsyncOp *pListenSP;
CAsyncOp *pAsyncOp;
CAsyncOp **ListenList;
DWORD dwCount;
DWORD dwActual;
dwCount = 0;
dwActual = 0;
ListenList = NULL;
pListenParent->Lock();
pBilinkSP = pListenParent->m_bilinkParent.GetNext();
while (pBilinkSP != &pListenParent->m_bilinkParent)
{
pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext();
while (pBilink != &pListenSP->m_bilinkParent)
{
dwCount++;
pBilink = pBilink->GetNext();
}
pListenSP->Unlock();
pBilinkSP = pBilinkSP->GetNext();
}
if (dwCount > 0)
{
if ((ListenList = static_cast<CAsyncOp**>(DNMalloc(dwCount*sizeof(CAsyncOp*)))) != NULL)
{
pBilinkSP = pListenParent->m_bilinkParent.GetNext();
while (pBilinkSP != &pListenParent->m_bilinkParent)
{
pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext();
while (pBilink != &pListenSP->m_bilinkParent)
{
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
pAsyncOp->AddRef();
ListenList[dwActual] = pAsyncOp;
dwActual++;
if (dwActual > dwCount)
{
DNASSERT(FALSE);
break;
}
pBilink = pBilink->GetNext();
}
pListenSP->Unlock();
pBilinkSP = pBilinkSP->GetNext();
}
}
}
pListenParent->Unlock();
if ((ListenList != NULL) && (dwActual > 0))
{
DWORD dw;
DWORD dwUpdateFlags;
HRESULT hrRegister;
dwUpdateFlags = 0;
hrRegister = DPNERR_DPNSVRNOTAVAILABLE;
if (dwFlags & DN_UPDATE_LISTEN_FLAG_HOST_MIGRATE)
{
dwUpdateFlags |= DN_UPDATELISTEN_HOSTMIGRATE;
}
if (dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS)
{
dwUpdateFlags |= DN_UPDATELISTEN_ALLOWENUMS;
}
if (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS)
{
dwUpdateFlags |= DN_UPDATELISTEN_DISALLOWENUMS;
}
for (dw = 0 ; dw < dwActual ; dw++)
{
if ((ListenList[dw]->GetResult() == DPN_OK) && (ListenList[dw]->GetProtocolHandle() != 0))
{
if (dwUpdateFlags)
{
if (DNPUpdateListen(pdnObject->pdnProtocolData,
ListenList[dw]->GetProtocolHandle(),
dwUpdateFlags) == DPN_OK)
{
hResultCode = DPN_OK;
}
}
#ifndef DPNBUILD_SINGLEPROCESS
if (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR)
{
if (DNRegisterListenWithDPNSVR(pdnObject,ListenList[dw]) == DPN_OK)
{
hrRegister = DPN_OK;
}
}
#endif // ! DPNBUILD_SINGLEPROCESS
}
ListenList[dw]->Release();
ListenList[dw] = NULL;
}
if ((dwActual != 0) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR))
{
hResultCode = hrRegister;
}
DNFree(ListenList);
ListenList = NULL;
}
pListenParent->Release();
pListenParent = NULL;
}
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#ifndef DPNBUILD_SINGLEPROCESS
#undef DPF_MODNAME
#define DPF_MODNAME "DNRegisterListenWithDPNSVR"
HRESULT DNRegisterListenWithDPNSVR(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pListen)
{
HRESULT hResultCode;
SPGETADDRESSINFODATA spInfo;
CAsyncOp *pListenSP;
CServiceProvider *pSP;
DPFX(DPFPREP, 6,"Parameters: pListen [0x%p]",pListen);
pListenSP = NULL;
pSP = NULL;
pListen->Lock();
if (pListen->GetParent() == NULL)
{
pListen->Unlock();
DPFX(DPFPREP, 7,"No SP parent for listen async op");
hResultCode = DPNERR_DOESNOTEXIST;
goto Failure;
}
pListen->GetParent()->AddRef();
pListenSP = pListen->GetParent();
pListen->Unlock();
pListenSP->Lock();
if (pListenSP->GetSP() == NULL)
{
pListenSP->Unlock();
DPFX(DPFPREP, 7,"No SP for listen SP async op");
hResultCode = DPNERR_DOESNOTEXIST;
goto Failure;
}
pListenSP->GetSP()->AddRef();
pSP = pListenSP->GetSP();
pListenSP->Unlock();
pListenSP->Release();
pListenSP = NULL;
//
// Determine the address we're actually listening on
//
memset(&spInfo,0x00,sizeof(SPGETADDRESSINFODATA));
spInfo.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, pListen->GetProtocolHandle(),&spInfo)) == DPN_OK)
{
DPN_SP_CAPS dnSPCaps;
#ifdef DBG
TCHAR DP8ABuffer[512] = {0};
DWORD DP8ASize;
#endif // DBG
DNASSERT(spInfo.pAddress != NULL);
#ifdef DBG
DP8ASize = 512;
IDirectPlay8Address_GetURL(spInfo.pAddress,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 7,"Listen address [%s]",DP8ABuffer);
#endif // DBG
//
// Determine if the listen's SP supports DPNSVR
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) == DPN_OK)
{
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSDPNSRV)
{
DWORD dwRetry;
//
// We re-try the registration to catch the case where DPNSVR is shutting
// down while we are trying to register. Unlikely but has to be handled.
//
for( dwRetry = 0; dwRetry < DPNSVR_REGISTER_ATTEMPTS ; dwRetry ++ )
{
hResultCode = pdnObject->ApplicationDesc.RegisterWithDPNSVR( spInfo.pAddress );
if (hResultCode == DPN_OK || hResultCode == DPNERR_ALREADYREGISTERED)
{
//
// Flag registering with DPNSVR for cleanup
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_DPNSVR_REGISTERED;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
hResultCode = DPN_OK;
break;
}
else
{
if( dwRetry < DPNSVR_REGISTER_ATTEMPTS )
{
DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x, retrying", hResultCode );
Sleep( DPNSVR_REGISTER_SLEEP );
}
else
{
DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x", hResultCode );
}
}
}
}
}
IDirectPlay8Address_Release(spInfo.pAddress);
spInfo.pAddress = NULL;
}
pSP->Release();
pSP = NULL;
Exit:
DNASSERT( pListenSP == NULL );
DNASSERT( pSP == NULL );
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pListenSP)
{
pListenSP->Release();
pListenSP = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
goto Exit;
}
#endif // ! DPNBUILD_SINGLEPROCESS
#undef DPF_MODNAME
#define DPF_MODNAME "DNAddRefLock"
HRESULT DNAddRefLock(DIRECTNETOBJECT *const pdnObject)
{
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ((pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) ||
!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
return(DPNERR_ALREADYCLOSING);
}
pdnObject->dwLockCount++;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
return(DPN_OK);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNDecRefLock"
void DNDecRefLock(DIRECTNETOBJECT *const pdnObject)
{
BOOL fSetEvent;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwLockCount--;
if ((pdnObject->dwLockCount == 0) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING))
{
fSetEvent = TRUE;
}
else
{
fSetEvent = FALSE;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (fSetEvent)
{
DNSetEvent(pdnObject->hLockEvent);
}
}
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
#undef DPF_MODNAME
#define DPF_MODNAME "DNThreadPoolAddRef"
void DNThreadPoolAddRef(DIRECTNETOBJECT *const pdnObject)
{
LONG lRefCount;
DNASSERT(pdnObject->lThreadPoolRefCount >= 0);
lRefCount = DNInterlockedIncrement( (LONG*)&pdnObject->lThreadPoolRefCount );
DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNThreadPoolRelease"
void DNThreadPoolRelease(DIRECTNETOBJECT *const pdnObject)
{
LONG lRefCount;
DNASSERT(pdnObject->lThreadPoolRefCount > 0);
lRefCount = DNInterlockedDecrement( (LONG*)&pdnObject->lThreadPoolRefCount );
if (lRefCount == 0)
{
DPFX(DPFPREP, 9, "Thread pool refcount = 0, setting shut down event");
DNASSERT( pdnObject->ThreadPoolShutDownEvent );
pdnObject->ThreadPoolShutDownEvent->Set();
}
else
{
DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount);
}
}
#endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE