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.
571 lines
15 KiB
571 lines
15 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dplunk.c
|
|
* Content: IUnknown implementation for dplobby
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======= ======= ======
|
|
* 4/13/96 myronth Created it
|
|
* 10/23/96 myronth Added client/server methods
|
|
* 11/08/96 myronth Added PRV_GetDPLobbySPInterface
|
|
* 11/20/96 myronth Added LogoffServer call to Release code
|
|
* 2/12/97 myronth Mass DX5 changes
|
|
* 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
|
|
* 3/12/97 myronth New release code for DPlay3 (order different)
|
|
* 3/13/97 myronth Added FreeLibrary code for LP's
|
|
* 3/17/97 myronth Cleanup map table
|
|
* 3/24/97 kipo Added support for IDirectPlayLobby2 interface
|
|
* 4/3/97 myronth Changed CALLSP macro to CALL_LP
|
|
* 5/8/97 myronth Drop the lobby lock when calling the LP, Purged
|
|
* dead code
|
|
* 7/30/97 myronth Added request node cleanup for standard lobby messaging
|
|
* 8/19/97 myronth Added PRV_GetLobbyObjectFromInterface
|
|
* 8/19/97 myronth Removed PRV_GetLobbyObjectFromInterface (not needed)
|
|
* 12/2/97 myronth Added IDirectPlayLobby3 interface
|
|
* 2/2/99 aarono Added lobbies to refcount on DPLAY dll to avoid
|
|
* accidental unload.
|
|
***************************************************************************/
|
|
#include "dplobpr.h"
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Definitions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Functions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_GetDPLobbySPInterface"
|
|
LPDPLOBBYSP PRV_GetDPLobbySPInterface(LPDPLOBBYI_DPLOBJECT this)
|
|
{
|
|
LPDPLOBBYI_INTERFACE lpInt;
|
|
|
|
|
|
ASSERT(this);
|
|
|
|
// Get an IDPLobbySP interface
|
|
if(FAILED(PRV_GetInterface(this, &lpInt, &dplCallbacksSP)))
|
|
{
|
|
DPF_ERR("Unable to get non-reference counted DPLobbySP Interface pointer");
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
// Decrement the ref cnt on the interface
|
|
lpInt->dwIntRefCnt--;
|
|
|
|
// Return the interface pointer
|
|
return (LPDPLOBBYSP)lpInt;
|
|
|
|
} // PRV_GetDPLobbySPInterface
|
|
|
|
// Find an interface with the pCallbacks vtbl on this object.
|
|
// If one doesn't exist, create it, increment the ref count,
|
|
// and return the interface
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_GetInterface"
|
|
HRESULT PRV_GetInterface(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLOBBYI_INTERFACE * ppInt,
|
|
LPVOID lpCallbacks)
|
|
{
|
|
LPDPLOBBYI_INTERFACE lpCurrentInts = this->lpInterfaces;
|
|
BOOL bFound = FALSE;
|
|
|
|
|
|
DPF(7, "Entering PRV_GetInterface");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, ppInt, lpCallbacks);
|
|
|
|
ASSERT(ppInt);
|
|
|
|
// See if there is already an interface
|
|
while (lpCurrentInts && !bFound)
|
|
{
|
|
if (lpCurrentInts->lpVtbl == lpCallbacks)
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
else
|
|
lpCurrentInts = lpCurrentInts->lpNextInterface;
|
|
}
|
|
|
|
// If there is one, return it
|
|
if(bFound)
|
|
{
|
|
*ppInt = lpCurrentInts;
|
|
(*ppInt)->dwIntRefCnt++;
|
|
// we don't increment this->dwRefCnt, since it's one / interface object
|
|
return DP_OK;
|
|
}
|
|
|
|
// Otherwise create one
|
|
*ppInt = DPMEM_ALLOC(sizeof(DPLOBBYI_INTERFACE));
|
|
if (!(*ppInt))
|
|
{
|
|
DPF_ERR("Could not alloc interface - out of memory");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
(*ppInt)->dwIntRefCnt = 1;
|
|
(*ppInt)->lpDPLobby = this;
|
|
(*ppInt)->lpNextInterface = this->lpInterfaces;
|
|
(*ppInt)->lpVtbl = lpCallbacks;
|
|
|
|
this->lpInterfaces = *ppInt;
|
|
this->dwRefCnt++; // One time only for each interface object
|
|
return DP_OK;
|
|
|
|
} // PRV_GetInterface
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_QueryInterface"
|
|
HRESULT DPLAPI DPL_QueryInterface(LPDIRECTPLAYLOBBY lpDPL, REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering DPL_QueryInterface");
|
|
DPF(9, "Parameters: 0x%08x, refiid, 0x%08x", lpDPL, ppvObj);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDINTERFACE;
|
|
}
|
|
|
|
this = DPLOBJECT_FROM_INTERFACE(lpDPL);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
if ( !VALID_READ_UUID_PTR(riid) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if ((!VALID_UUID_PTR(ppvObj)) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Object pointer is invalid!");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*ppvObj=NULL;
|
|
|
|
if( IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IDirectPlayLobby) )
|
|
{
|
|
// Get an IDirectPlayLobby Interface (Unicode)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacks);
|
|
}
|
|
else if( IsEqualIID(riid, &IID_IDirectPlayLobbyA) )
|
|
{
|
|
// Get an IDirectPlayLobbyA Interface (ANSI)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacksA);
|
|
}
|
|
else if( IsEqualIID(riid, &IID_IDirectPlayLobby2) )
|
|
{
|
|
// Get an IDirectPlayLobby2 Interface (Unicode)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacks2);
|
|
}
|
|
else if( IsEqualIID(riid, &IID_IDirectPlayLobby2A) )
|
|
{
|
|
// Get an IDirectPlayLobby2A Interface (ANSI)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacks2A);
|
|
}
|
|
else if( IsEqualIID(riid, &IID_IDirectPlayLobby3) )
|
|
{
|
|
// Get an IDirectPlayLobby3 Interface (Unicode)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacks3);
|
|
}
|
|
else if( IsEqualIID(riid, &IID_IDirectPlayLobby3A) )
|
|
{
|
|
// Get an IDirectPlayLobby3A Interface (ANSI)
|
|
hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
|
|
&dplCallbacks3A);
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} //DPL_QueryInterface
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_AddRef"
|
|
ULONG DPLAPI DPL_AddRef(LPDIRECTPLAYLOBBY lpDPL)
|
|
{
|
|
LPDPLOBBYI_INTERFACE lpInt = (LPDPLOBBYI_INTERFACE)lpDPL;
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
|
|
|
|
DPF(7, "Entering DPL_AddRef");
|
|
DPF(9, "Parameters: 0x%08x", lpDPL);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return 0;
|
|
}
|
|
|
|
this = DPLOBJECT_FROM_INTERFACE(lpDPL);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return 0;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DPLOBBY();
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Make sure someone isn't calling AddRef on our IDPLobbySP interface
|
|
if(lpInt->lpVtbl == &dplCallbacksSP)
|
|
{
|
|
DPF_ERR("You cannot call AddRef on an IDPLobbySP interface");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return 0;
|
|
}
|
|
|
|
// Increment the interface's reference count
|
|
lpInt->dwIntRefCnt++;
|
|
|
|
LEAVE_DPLOBBY();
|
|
return (lpInt->dwIntRefCnt);
|
|
|
|
} //DPL_AddRef
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyDPLobby"
|
|
HRESULT PRV_DestroyDPLobby(LPDPLOBBYI_DPLOBJECT this)
|
|
{
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyDPLobby");
|
|
DPF(9, "Parameters: 0x%08x", this);
|
|
|
|
// Since we can now be called from the DPlay3 object's Release code,
|
|
// make sure we don't have any interface objects when we go to
|
|
// free our lobby object. Assert here if any interfaces exist.
|
|
ASSERT(!this->lpInterfaces);
|
|
|
|
// Walk the list of GameNodes, freeing them as you go
|
|
while(this->lpgnHead)
|
|
PRV_RemoveGameNodeFromList(this->lpgnHead);
|
|
|
|
// Walk the list of pending lobby server requests and free them
|
|
while(this->lprnHead)
|
|
PRV_RemoveRequestNode(this, this->lprnHead);
|
|
|
|
// Free our callback table if one exists
|
|
if(this->pcbSPCallbacks)
|
|
DPMEM_FREE(this->pcbSPCallbacks);
|
|
|
|
// Free our ID Map Table if it exists
|
|
if(this->lpMap)
|
|
DPMEM_FREE(this->lpMap);
|
|
|
|
// Free the dplobby object
|
|
DPMEM_FREE(this);
|
|
|
|
gnObjects--;
|
|
|
|
ASSERT(((int)gnObjects) >= 0);
|
|
|
|
return DP_OK;
|
|
|
|
} // PRV_DestroyDPlayLobby
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyDPLobbyInterface"
|
|
HRESULT PRV_DestroyDPLobbyInterface(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLOBBYI_INTERFACE lpInterface)
|
|
{
|
|
LPDPLOBBYI_INTERFACE lpIntPrev; // The interface preceeding pInt in the list
|
|
BOOL bFound = FALSE;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyDPLobbyInterface");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpInterface);
|
|
|
|
// Remove pInt from the list of interfaces
|
|
if (this->lpInterfaces == lpInterface)
|
|
{
|
|
// It's the 1st one, just remove it
|
|
this->lpInterfaces = lpInterface->lpNextInterface;
|
|
}
|
|
else
|
|
{
|
|
lpIntPrev = this->lpInterfaces;
|
|
while (lpIntPrev && !bFound)
|
|
{
|
|
if (lpIntPrev->lpNextInterface == lpInterface)
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
else lpIntPrev = lpIntPrev->lpNextInterface;
|
|
}
|
|
if (!bFound)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_UNEXPECTED;
|
|
}
|
|
// take pint out of the list
|
|
lpIntPrev->lpNextInterface = lpInterface->lpNextInterface;
|
|
|
|
}
|
|
|
|
DPMEM_FREE(lpInterface);
|
|
return DP_OK;
|
|
|
|
} // PRV_DestroyDPLobbyInterface
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_Release"
|
|
ULONG PRV_Release(LPDPLOBBYI_DPLOBJECT this, LPDPLOBBYI_INTERFACE lpInterface)
|
|
{
|
|
HRESULT hr = DP_OK;
|
|
SPDATA_SHUTDOWN sdd;
|
|
DWORD dwError;
|
|
|
|
|
|
DPF(7, "==> PRV_Release");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpInterface);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Decrement the interface ref count
|
|
if (0 == --(lpInterface->dwIntRefCnt))
|
|
{
|
|
LPDPLOBBYI_GAMENODE lpgn;
|
|
// Notifying apps we launched that we are releasing
|
|
// our lobby interface.
|
|
lpgn=this->lpgnHead;
|
|
while(lpgn){
|
|
if(lpgn->dwFlags & GN_LOBBY_CLIENT) {
|
|
hr=PRV_SendStandardSystemMessage((LPDIRECTPLAYLOBBY)lpInterface, DPLSYS_LOBBYCLIENTRELEASE, lpgn->dwGameProcessID);
|
|
if(DP_OK != hr){
|
|
DPF(0,"Couldn't send system message to game pid %x, hr=%x",lpgn->dwGameProcessID,hr);
|
|
} else {
|
|
DPF(9,"Told Process %x we are releasing the lobby interface",lpgn->dwGameProcessID);
|
|
}
|
|
}
|
|
lpgn=lpgn->lpgnNext;
|
|
}
|
|
|
|
DPF(7,"Lobby interface Refcount hit 0, freeing\n");
|
|
// Since we're destroying an interface, dec the object count
|
|
this->dwRefCnt--;
|
|
|
|
// If our object ref cnt just went to zero, we need to call
|
|
// shutdown in the LP if one is loaded
|
|
if(this->dwFlags & DPLOBBYPR_SPINTERFACE)
|
|
{
|
|
// Clear our stack-based structure
|
|
memset(&sdd, 0, sizeof(SPDATA_SHUTDOWN));
|
|
|
|
// Call the Shutdown method in the SP
|
|
if(CALLBACK_EXISTS(Shutdown))
|
|
{
|
|
sdd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, Shutdown, &sdd);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// All LP's should support Shutdown
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("Could not invoke Shutdown method in the Service Provider");
|
|
}
|
|
}
|
|
|
|
// REVIEW!!!! -- Are we going to have the same problem dplay has
|
|
// with SP's hanging around and crashing after we go away? We
|
|
// need to make sure the LP goes away first.
|
|
if(this->hInstanceLP)
|
|
{
|
|
DPF(7,"About to free lobby provider library, hInstance %x\n",this->hInstanceLP);
|
|
if (!FreeLibrary(this->hInstanceLP))
|
|
{
|
|
dwError = GetLastError();
|
|
DPF_ERRVAL("Unable to free Lobby Provider DLL, dwError = %lu", dwError);
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
// Just to be safe
|
|
this->hInstanceLP = NULL;
|
|
}
|
|
|
|
// If the interface is the IDPLobbySP interface, we had to have been
|
|
// called from the DPlay3 release code, so clear the SP flag since
|
|
// we are going to remove the IDPLobbySP interface just below here.
|
|
this->dwFlags &= ~DPLOBBYPR_SPINTERFACE;
|
|
|
|
// Take the interface out of the table
|
|
hr = PRV_DestroyDPLobbyInterface(this, lpInterface);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF(0,"Could not destroy DPLobby interface! hr = 0x%08lx\n", hr);
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
// Now destroy the interface if the ref cnt is 0
|
|
if(0 == this->dwRefCnt)
|
|
{
|
|
// Destroy the DPLobby object
|
|
DPF(0,"Destroying DirectPlayLobby object - ref cnt = 0!");
|
|
hr = PRV_DestroyDPLobby(this);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF(0,"Could not destroy DPLobby! hr = 0x%08lx\n",hr);
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
} // 0 == this->dwRefCnt
|
|
|
|
LEAVE_DPLOBBY();
|
|
return 0;
|
|
|
|
} //0 == pInt->dwIntRefCnt
|
|
|
|
DPF(7, "<==PRV_Release, rc=%d\n",lpInterface->dwIntRefCnt);
|
|
|
|
LEAVE_DPLOBBY();
|
|
return (lpInterface->dwIntRefCnt);
|
|
} // PRV_Release
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_Release"
|
|
ULONG DPLAPI DPL_Release(LPDIRECTPLAYLOBBY lpDPL)
|
|
{
|
|
LPDPLOBBYI_INTERFACE lpInterface;
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_Release");
|
|
DPF(9, "Parameters: 0x%08x", lpDPL);
|
|
|
|
TRY
|
|
{
|
|
lpInterface = (LPDPLOBBYI_INTERFACE)lpDPL;
|
|
if( !VALID_DPLOBBY_INTERFACE( lpInterface ))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
this = DPLOBJECT_FROM_INTERFACE(lpDPL);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Make sure someone isn't calling Release on our IDPLobbySP interface
|
|
if(lpInterface->lpVtbl == &dplCallbacksSP)
|
|
{
|
|
DPF_ERR("You cannot call Release on an IDPLobbySP interface");
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
// Call our internal release function
|
|
return PRV_Release(this, lpInterface);
|
|
|
|
} //DPL_Release
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_FreeAllLobbyObjects"
|
|
void PRV_FreeAllLobbyObjects(LPDPLOBBYI_DPLOBJECT this)
|
|
{
|
|
|
|
DPF(7, "Entering PRV_FreeAllLobbyObjects");
|
|
DPF(9, "Parameters: 0x%08x", this);
|
|
|
|
ASSERT(this);
|
|
|
|
// If we have an SP interface, just call release on it
|
|
if(this->dwFlags & DPLOBBYPR_SPINTERFACE)
|
|
{
|
|
// Assert if an interface doesn't exist, because it should
|
|
ASSERT(this->lpInterfaces);
|
|
PRV_Release(this, this->lpInterfaces);
|
|
return;
|
|
}
|
|
|
|
// Otherwise, we should only have an uninitialized object,
|
|
// which we should just be able to destroy
|
|
PRV_DestroyDPLobby(this);
|
|
|
|
}
|
|
|
|
|