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.
 
 
 
 
 
 

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);
}