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.
 
 
 
 
 
 

2269 lines
63 KiB

/*==========================================================================
*
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
*
* File: group.c
* Content: Methods for managing groups
*
* History:
* Date By Reason
* ======= ======= ======
* 2/27/97 myronth Created it
* 3/17/97 myronth Create/DestroyGroup, Removed unnecessary Enum functions
* 3/20/97 myronth AddPlayerToGroup, DeletePlayerFromGroup
* 3/21/97 myronth SetGroupName, Get/SetGroupData
* 3/31/97 myronth Removed dead code, Added CreateAndMapNewGroup function
* 4/3/97 myronth Changed CALLSP macro to CALL_LP
* 5/6/97 kipo GetGroup() now takes a parent ID
* 5/8/97 myronth Subgroup support, GroupConnSettings, StartSession,
* and drop the lobby lock when calling the LP
* 5/12/97 myronth Handle remote groups properly
* 5/17/97 myronth Added parent ID to CreateAndMapNewGroup calls,
* Added send message code for DestroyGroup and
* DeletePlayerFromGroup on the local machine
* 5/20/97 myronth Send Delete & DestroyPlayer messages for remote
* players when a local player leaves a group (#8586)
* Made AddPlayerToGroup & DeletePlayerFromGroup return
* DPERR_ACCESSDENIED on remote players (#8679),
* Fixed a bunch of other lock bugs, Changed debug levels
* 5/21/97 myronth Pass CreateGroup flags through the lobby (#8813)
* 5/22/97 myronth Added functions to destroy remote subgroups when
* a local player leaves a group (#8810)
* 5/23/97 myronth Send messages locally for CreateGroup and
* CreateGroupInGroup (#8870)
* 6/3/97 myronth Added PRV_DestroySubgroups function (#9134) and
* rearranged some of the DestroyGroup code
* 6/5/97 myronth Added shortcut checking to PRV_DestroySubgroups by
* adding the PRV_AreSubgroupsShortcuts function
* 6/6/97 myronth Added PRV_DestroyGroupAndParents and PRV_Destroy-
* ShortcutsForExitingPlayer, cleaned up PRV_Delete-
* PlayerFromGroup, Fixed StartSession bugs (#9573,#9574)
* 6/9/97 myronth Only delete shortcuts (don't destroy the subgoup)
* in the PRV_DestroySubgroups function
* 6/16/97 myronth Fixed bad deletion of uncle groups & some subgroups
* during DeletePlayerFromGroup (#9655)
* 6/20/97 myronth Send AddGroupToGroup message locally to avoid
* sending duplicate messages. Also added code to
* send local DeleteGroupFromGroup messages (#10139)
* 6/24/97 myronth Send AddPlayerToGroup message locally to avoid
* sending duplicate messages (#10287)
* 8/22/97 myronth Force guidInstance to NULL in SetGroupConnectionSettings
* 9/29/97 myronth Send local SetGroupName/Data msgs after call to
* lobby server succeeds (#12554)
* 10/23/97 myronth Added hidden group support (#12688), fixed crashing
* bug on DeletePlayerFromGroup (#12885)
* 10/29/97 myronth Added support for group owners, including
* DPL_SetGroupOwner and DPL_GetGroupOwner
* 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
***************************************************************************/
#include "dplobpr.h"
//--------------------------------------------------------------------------
//
// Functions
//
//--------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_AddGroupToGroup"
HRESULT DPLAPI PRV_AddGroupToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
DWORD dwGroupID)
{
SPDATA_ADDGROUPTOGROUP ad;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_GROUP lpGroupTo = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_AddGroupToGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
this, dwParentID, dwGroupID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLAY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLAY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&ad, 0, sizeof(SPDATA_ADDGROUPTOGROUP));
ad.dwSize = sizeof(SPDATA_ADDGROUPTOGROUP);
ad.dwParentID = dwParentID;
ad.dwGroupID = dwGroupID;
// Call the AddGroupToGroup method in the SP
if(CALLBACK_EXISTS(AddGroupToGroup))
{
ad.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, AddGroupToGroup, &ad);
ENTER_DPLOBBY();
}
else
{
// AddGroupToGroup is required
DPF_ERR("The Lobby Provider callback for AddGroupToGroup doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_ADDGROUPTOGROUP;
}
// If it succeeded, send the AddGroupToGroup message to our local players
if(SUCCEEDED(hr))
{
// Take the dplay lock
ENTER_DPLAY();
// Find dplay's internal group struct for the To group
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
if(!lpGroupTo)
{
LEAVE_DPLAY();
DPF_ERR("Unable to find group in nametable");
hr = DPERR_INVALIDGROUP;
goto EXIT_ADDGROUPTOGROUP;
}
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDSHORTCUTTOGROUP);
msg.dwPlayerID = dwGroupID;
msg.dwGroupID = dwParentID;
// Call dplay's DistributeGroupMessage function to put the message
// in the queues of all the appropriate players
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF(8, "Failed adding AddGroupToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
}
// Drop the dplay lock
LEAVE_DPLAY();
}
else
{
DPF_ERRVAL("Failed calling AddGroupToGroup in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_ADDGROUPTOGROUP:
LEAVE_DPLOBBY();
return hr;
} // PRV_AddGroupToGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_AddPlayerToGroup"
HRESULT DPLAPI PRV_AddPlayerToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
DWORD dwPlayerID)
{
SPDATA_ADDPLAYERTOGROUP ad;
LPDPLAYI_PLAYER lpPlayer = NULL;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_GROUP lpGroupTo = NULL;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_AddPlayerToGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
this, dwGroupID, dwPlayerID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLAY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLAY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Take the dplay lock since we'll be looking at a dplay internal struct
ENTER_DPLAY();
// Make sure the player is a local player, otherwise return AccessDenied
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
if(!lpPlayer)
{
LEAVE_DPLAY();
DPF_ERR("Unable to find player in nametable");
hr = DPERR_INVALIDPLAYER;
goto EXIT_ADDPLAYERTOGROUP;
}
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
LEAVE_DPLAY();
DPF_ERR("Cannot add a remote player to a group");
hr = DPERR_ACCESSDENIED;
goto EXIT_ADDPLAYERTOGROUP;
}
// Drop the dplay lock since we're done
LEAVE_DPLAY();
// Setup our SPDATA struct
memset(&ad, 0, sizeof(SPDATA_ADDPLAYERTOGROUP));
ad.dwSize = sizeof(SPDATA_ADDPLAYERTOGROUP);
ad.dwGroupID = dwGroupID;
ad.dwPlayerID = dwPlayerID;
// Call the AddPlayerToGroup method in the SP
if(CALLBACK_EXISTS(AddPlayerToGroup))
{
ad.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, AddPlayerToGroup, &ad);
ENTER_DPLOBBY();
}
else
{
// AddPlayerToGroup is required
DPF_ERR("The Lobby Provider callback for AddPlayerToGroup doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_ADDPLAYERTOGROUP;
}
// If it succeeded, send the AddPlayerToGroup message to our local players
if(SUCCEEDED(hr))
{
// Take the dplay lock
ENTER_DPLAY();
// Find dplay's internal group struct for the To group
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
if(!lpGroupTo)
{
LEAVE_DPLAY();
DPF_ERR("Unable to find group in nametable");
hr = DPERR_INVALIDGROUP;
goto EXIT_ADDPLAYERTOGROUP;
}
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDPLAYERTOGROUP);
msg.dwPlayerID = dwPlayerID;
msg.dwGroupID = dwGroupID;
// Call dplay's DistributeGroupMessage function to put the message
// in the queues of all the appropriate players
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF(8, "Failed adding AddPlayerToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
}
else
{
// We need to see if this player is the group owner. If it is,
// we need to send a SetGroupOwner message as well.
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
if(lpGroup && (dwPlayerID == lpGroup->dwOwnerID))
{
// Now send the message
PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwPlayerID, 0);
}
}
// Drop the dplay lock
LEAVE_DPLAY();
}
else
{
DPF_ERRVAL("Failed calling AddPlayerToGroup in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_ADDPLAYERTOGROUP:
LEAVE_DPLOBBY();
return hr;
} // PRV_AddPlayerToGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CreateGroup"
HRESULT DPLAPI PRV_CreateGroup(LPDPLOBBYI_DPLOBJECT this, LPDPID lpidGroup,
LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags,
DWORD dwOwnerID)
{
SPDATA_CREATEGROUP cg;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_GROUP lpGroupTo = NULL;
DWORD dwInternalFlags;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_CreateGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
this, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&cg, 0, sizeof(SPDATA_CREATEGROUP));
cg.dwSize = sizeof(SPDATA_CREATEGROUP);
cg.lpName = lpName;
cg.lpData = lpData;
cg.dwDataSize = dwDataSize;
cg.dwFlags = dwFlags;
cg.dwGroupOwnerID = dwOwnerID;
// Call the CreateGroup method in the SP
if(CALLBACK_EXISTS(CreateGroup))
{
cg.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, CreateGroup, &cg);
ENTER_DPLOBBY();
}
else
{
// CreateGroup is required
DPF_ERR("The Lobby Provider callback for CreateGroup doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling CreateGroup in the Lobby Provider, hr = 0x%08x", hr);
goto EXIT_CREATEGROUP;
}
// Setup the flags to pass to GetGroup
dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
if(dwFlags & DPGROUP_STAGINGAREA)
dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
if(dwFlags & DPGROUP_HIDDEN)
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
// Add the player to dplay's nametable and put it in our map table
hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
dwDataSize, dwInternalFlags, cg.dwGroupID, 0, dwOwnerID);
if(FAILED(hr))
{
DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
// REVIEW!!!! -- We need to send a message back to the server saying
// we couldn't complete the deal on our end.
goto EXIT_CREATEGROUP;
}
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
msg.dwPlayerID = *lpidGroup;
// Take the lock
ENTER_DPLAY();
// Find dplay's internal group struct for the To group
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
if(!lpGroupTo)
{
LEAVE_DPLAY();
DPF_ERRVAL("Unable to find system group in nametable, hr = 0x%08x", hr);
goto EXIT_CREATEGROUP;
}
// Call dplay's DistributeGroupMessage function to put the message in
// the queues of all the appropriate players
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo, (LPBYTE)&msg,
sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF(2, "Failed adding CreateGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
}
LEAVE_DPLAY();
EXIT_CREATEGROUP:
LEAVE_DPLOBBY();
return hr;
} // PRV_CreateGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CreateGroupInGroup"
HRESULT DPLAPI PRV_CreateGroupInGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
LPDPID lpidGroup, LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize,
DWORD dwFlags, DWORD dwOwnerID)
{
SPDATA_CREATEGROUPINGROUP cgig;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
LPDPLAYI_GROUP lpGroupTo = NULL;
HRESULT hr = DP_OK;
DWORD dwInternalFlags;
DPF(7, "Entering PRV_CreateGroupInGroup");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
this, dwParentID, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&cgig, 0, sizeof(SPDATA_CREATEGROUPINGROUP));
cgig.dwSize = sizeof(SPDATA_CREATEGROUPINGROUP);
cgig.dwParentID = dwParentID;
cgig.lpName = lpName;
cgig.lpData = lpData;
cgig.dwDataSize = dwDataSize;
cgig.dwFlags = dwFlags;
cgig.dwGroupOwnerID = dwOwnerID;
// Call the CreateGroupInGroup method in the SP
if(CALLBACK_EXISTS(CreateGroupInGroup))
{
cgig.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, CreateGroupInGroup, &cgig);
ENTER_DPLOBBY();
}
else
{
// CreateGroupInGroup is required
DPF_ERR("The Lobby Provider callback for CreateGroupInGroup doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling CreateGroupInGroup in the Lobby Provider, hr = 0x%08x", hr);
LEAVE_DPLOBBY();
return hr;
}
// Setup the flags to pass to GetGroup
dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
if(dwFlags & DPGROUP_STAGINGAREA)
dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
if(dwFlags & DPGROUP_HIDDEN)
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
// Add the group to dplay's nametable and put it in our map table
hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
dwDataSize, dwInternalFlags, cgig.dwGroupID, dwParentID, dwOwnerID);
if(FAILED(hr))
{
DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
// REVIEW!!!! -- We need to send a message back to the server saying
// we couldn't complete the deal on our end.
goto EXIT_CREATEGROUPINGROUP;
}
// Take the dplay lock
ENTER_DPLAY();
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
msg.dwPlayerID = *lpidGroup;
// Find dplay's internal group struct for the To group
// Since this is local, send it to all players
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
if(!lpGroupTo)
{
LEAVE_DPLAY();
DPF_ERRVAL("Unable to find parent group in nametable, hr = 0x%08x", hr);
goto EXIT_CREATEGROUPINGROUP;
}
// Call dplay's DistributeGroupMessage function to put the message
// in the queues of all the appropriate players
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF(2, "Failed adding CreateGroupInGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
}
// Drop the dplay lock
LEAVE_DPLAY();
EXIT_CREATEGROUPINGROUP:
LEAVE_DPLOBBY();
return hr;
} // PRV_CreateGroupInGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DeleteGroupFromGroup"
HRESULT DPLAPI PRV_DeleteGroupFromGroup(LPDPLOBBYI_DPLOBJECT this,
DWORD dwParentID, DWORD dwGroupID)
{
SPDATA_DELETEGROUPFROMGROUP dgd;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_GROUP lpGroupTo = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_DeleteGroupFromGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
this, dwParentID, dwGroupID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&dgd, 0, sizeof(SPDATA_DELETEGROUPFROMGROUP));
dgd.dwSize = sizeof(SPDATA_DELETEGROUPFROMGROUP);
dgd.dwParentID = dwParentID;
dgd.dwGroupID = dwGroupID;
// Call the DeleteGroupFromGroup method in the SP
if(CALLBACK_EXISTS(DeleteGroupFromGroup))
{
dgd.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, DeleteGroupFromGroup, &dgd);
ENTER_DPLOBBY();
}
else
{
// DeleteGroupFromGroup is required
DPF_ERR("The Lobby Provider callback for DeleteGroupFromGroup doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
// If it succeeded, send the DeleteGroupFromGroup message to all local players
if(SUCCEEDED(hr))
{
// Take the dplay lock
ENTER_DPLAY();
// Get a pointer to dplay's system group
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
if(!lpGroupTo)
{
LEAVE_LOBBY_ALL();
DPF_ERR("Unable to find system group in nametable, not sending DeleteGroupFromGroup message");
return DPERR_INVALIDGROUP;
}
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
msg.dwPlayerID = dwGroupID;
msg.dwGroupID = dwParentID;
// Call dplay's DistributeGroupMessage function to put the message
// in the queues of all the appropriate players
DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF(8, "Failed adding DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
}
// Drop the dplay lock
LEAVE_DPLAY();
}
else
{
DPF_ERRVAL("Failed calling DeleteGroupFromGroup in the Lobby Provider, hr = 0x%08x", hr);
}
// The dplay InternalDeletePlayerFromGroup code will take care of the rest of
// the internal cleanup (nametable, players, etc.), so we can just return
// from here.
LEAVE_DPLOBBY();
return hr;
} // PRV_DeleteGroupFromGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DoSubgroupsContainLocalPlayers"
BOOL PRV_DoSubgroupsContainLocalPlayers(LPDPLAYI_GROUP lpGroup,
BOOL bIncludeGroup)
{
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
DPF(7, "Entering PRV_DoSubgroupsContainLocalPlayers");
DPF(9, "Parameters: 0x%08x, %lu", lpGroup, bIncludeGroup);
ASSERT(lpGroup);
// Figure out how many local players are in this group. If it's
// nonzero, just return true from this function. If the bIncludeGroup
// parameter is set to FALSE, then don't look at the group passed in
lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
lpGroup->lpDP->pSysPlayer->dwID);
if(lpGroupnode && (lpGroupnode->nPlayers > 0) && bIncludeGroup)
return TRUE;
// Walk the list of subgroups
lpSubgroup = lpGroup->pSubgroups;
while(lpSubgroup)
{
// We're going recursive here to do the entire heirarchy
// Check out any of it's subgroups
if((!(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
(PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)))
return TRUE;
else
lpSubgroup = lpSubgroup->pNextSubgroup;
} // while subgroups
return FALSE;
} // PRV_DoSubgroupsContainLocalPlayers
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_AreSubgroupsShortcuts"
BOOL PRV_AreSubgroupsShortcuts(LPDPLAYI_GROUP lpGroup)
{
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
DPF(7, "Entering PRV_AreSubgroupsShortcuts");
DPF(9, "Parameters: 0x%08x", lpGroup);
ASSERT(lpGroup);
// If the group is one of the following, then we want to return TRUE so
// it doesn't get nuked:
// 1) Root group, nGroups > 0
// 2) Root group, hidden, nGroups = 0
// 2) Non-root group, nGroups > 1
// Otherwise, we can check it's subgroups and return FALSE as appropriate
if(((lpGroup->dwIDParent == 0) && ((lpGroup->nGroups > 0) ||
(!(lpGroup->dwFlags & DPLAYI_GROUP_HIDDEN)) && (lpGroup->nGroups == 0))) ||
((lpGroup->dwIDParent != 0) && (lpGroup->nGroups > 1)))
return TRUE;
// Walk the list of subgroups
lpSubgroup = lpGroup->pSubgroups;
while(lpSubgroup)
{
// We're going recursive here to do the entire heirarchy
// Check out any of it's subgroups
if(PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))
return TRUE;
else
lpSubgroup = lpSubgroup->pNextSubgroup;
} // while subgroups
return FALSE;
} // PRV_AreSubgroupsShortcuts
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroyGroupAndParents"
void PRV_DestroyGroupAndParents(LPDPLOBBYI_DPLOBJECT this,
LPDPLAYI_GROUP lpGroup, LPDPLAYI_GROUP lpStopParent)
{
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
LPDPLAYI_GROUP lpParentGroup = NULL;
SPDATA_DESTROYREMOTEGROUP dg;
DPID dpidParent;
HRESULT hr;
DPF(7, "Entering PRV_DestroyGroupAndParents");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
this, lpGroup, lpStopParent);
ASSERT(lpGroup);
// Now we need to decide if this is the last group this group was in. If
// it is, then we need to destroy the group as well, and remove them from
// our map table. Of course, only destroy the group if it is a remote group.
// ALSO, we need to walk the heirarchy backward (up the tree) to the root
// node and delete all groups that were only created to get to our shortcut.
if(!(lpGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
// Walk our parental heirarchy until we reach a a root group.
dpidParent = lpGroup->dwIDParent;
while(dpidParent)
{
// Get dplay's internal group structures
lpParentGroup = GroupFromID(this->lpDPlayObject, dpidParent);
if(!lpParentGroup)
{
ASSERT(FALSE);
DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dpidParent);
return;
}
// If there are any local players in the parent group, we don't want to
// destroy it or any of it's subgroups (since players in the group will
// be able to see subgroups)
lpGroupnode = FindPlayerInGroupList(lpParentGroup->pSysPlayerGroupnodes,
this->lpDPlayObject->pSysPlayer->dwID);
if((lpGroupnode) && (lpGroupnode->nPlayers > 0))
return;
// Make sure we haven't reached our stop parent group if the caller
// passed one in. This will keep us from recursively destroying
// a subgroup's parent, which we might be spinning on, deleting all
// of it's subgroups.
if(lpStopParent && (lpStopParent == lpParentGroup))
return;
// Destroy the subgroups
PRV_DestroySubgroups(this, lpParentGroup, TRUE);
// Get the next parent
dpidParent = lpParentGroup->dwIDParent;
}
// See if we processed any parents, or if we already have a root
// group. If lpParentGroup is NULL, we have a root group, so just
// stuff our group pointer in the parent group pointer
if(!lpParentGroup)
lpParentGroup = lpGroup;
// Now see if our root group is hidden, and if it doesn't contain any
// references, then we want to destroy it as well.
if((!PRV_DoSubgroupsContainLocalPlayers(lpParentGroup, TRUE)) &&
(!PRV_AreSubgroupsShortcuts(lpParentGroup)) &&
(lpParentGroup->dwFlags & DPLAYI_GROUP_HIDDEN))
{
// Setup the SPDATA struct for DestroyRemoteGroup
memset(&dg, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
dg.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
dg.dwGroupID = lpParentGroup->dwID;
// Call our internal remote create
hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dg);
if(FAILED(hr))
{
DPF_ERRVAL("Failed destroying remote root group, hr = 0x%08x", hr);
}
}
}
} // PRV_DestroyGroupAndParents
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroyRemoteShortcutsForExitingPlayer"
void PRV_DestroyRemoteShortcutsForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
{
SPDATA_DELETEREMOTEGROUPFROMGROUP drgd;
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
HRESULT hr;
DPF(7, "Entering PRV_DestroyRemoteShortcutsForExitingPlayer");
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, dwGroupID);
ASSERT(lpGroup);
// Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
memset(&drgd, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
drgd.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
drgd.dwParentID = dwGroupID;
// Walk the list of subgroups, destroying all remote shortcuts
lpSubgroup = lpGroup->pSubgroups;
while(lpSubgroup)
{
// Save the next subgroup
lpNextSubgroup = lpSubgroup->pNextSubgroup;
// Make sure the group is remote and that this is really
// a shortcut and not a child
if(((lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
(!(lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)))
{
// Get the subgroup's lobby ID
drgd.dwGroupID = lpSubgroup->pGroup->dwID;
// Call our internal DeleteGroupFromGroup routine to delete
// the shortcut and send the appropriate messages
// NOTE: It is imperative that we pass in a pointer to the
// group who's shortcuts we are removing as the stop parent.
// If we do not, we run the risk of deleting it or one of
// it's children that we haven't yet looped through, which
// will result in a crash as we continue to walk the
// subgroup list.
hr = PRV_DeleteRemoteGroupFromGroup(this, &drgd, TRUE, lpGroup);
if(FAILED(hr))
{
DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
}
}
// Go to the next one
lpSubgroup = lpNextSubgroup;
}
} // PRV_DestroyRemoteShortcutsForExitingPlayer
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroyRemotePlayersForExitingPlayer"
void PRV_DestroyRemotePlayersForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
{
SPDATA_DELETEREMOTEPLAYERFROMGROUP drpd;
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
LPDPLAYI_GROUPNODE lpNextGroupnode = NULL;
HRESULT hr;
DPF(7, "Entering PRV_DestroyRemotePlayersForExitingPlayer");
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
ASSERT(lpGroup);
// Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
memset(&drpd, 0, sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP));
drpd.dwSize = sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP);
drpd.dwGroupID = dwGroupID;
// Walk the list of groupnodes, deleting remote players that are not in
// any other groups
lpGroupnode = lpGroup->pGroupnodes;
while(lpGroupnode)
{
// Save our next groupnode pointer since our current groupnode
// will be gone when we come back from the delete
lpNextGroupnode = lpGroupnode->pNextGroupnode;
// Delete the player from the group if it's remote and then
// destroy the player if he is in no other groups
if (!(lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
// Get the remote player's ID
drpd.dwPlayerID = lpGroupnode->pPlayer->dwID;
// Delete the player from the group
hr = PRV_DeleteRemotePlayerFromGroup(this, &drpd, TRUE);
if(FAILED(hr))
{
DPF_ERRVAL("Failed deleting remote player from group, hr = 0x%08x", hr);
}
}
lpGroupnode = lpNextGroupnode;
} // while
} // PRV_DestroyRemotePlayersForExitingPlayer
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroySubgroups"
void PRV_DestroySubgroups(LPDPLOBBYI_DPLOBJECT this, LPDPLAYI_GROUP lpGroup,
BOOL bRemoteOnly)
{
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
SPDATA_DESTROYREMOTEGROUP dgd;
SPDATA_DELETEREMOTEGROUPFROMGROUP drg;
HRESULT hr;
DPF(7, "Entering PRV_DestroySubgroups");
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, bRemoteOnly);
ASSERT(lpGroup);
// Setup the static part of the SPDATA structures
memset(&dgd, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
dgd.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
memset(&drg, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
drg.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
drg.dwParentID = lpGroup->dwID;
// Walk the list of subgroups
lpSubgroup = lpGroup->pSubgroups;
while(lpSubgroup)
{
// Save the next subgroup
lpNextSubgroup = lpSubgroup->pNextSubgroup;
// Make sure it's a remote group if the flag is set
if((bRemoteOnly) &&
(lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
lpSubgroup = lpNextSubgroup;
continue;
}
// If the subgroup doesn't contain any local players,
// nor do any of it's subgroups, then destroy it
if((!bRemoteOnly) ||
((!PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)) &&
(!PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))))
{
// If the group is a shortcut, just delete the link. If it's a child,
// destroy the subgroup.
if(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)
{
// Finish setting up the SPDATA structure
drg.dwGroupID = lpSubgroup->pGroup->dwID;
// Destroy the subgroup
hr = DPLP_DeleteGroupFromGroup((LPDPLOBBYSP)this->lpInterfaces, &drg);
if(FAILED(hr))
{
DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
}
}
else
{
// Finish setting up the SPDATA structure
dgd.dwGroupID = lpSubgroup->pGroup->dwID;
// Destroy the subgroup
hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dgd);
if(FAILED(hr))
{
DPF_ERRVAL("Failed destroying remote group, hr = 0x%08x", hr);
}
}
}
lpSubgroup = lpNextSubgroup;
} // while lpSubgroups
} // PRV_DestroySubgroups
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DeletePlayerFromGroup"
HRESULT DPLAPI PRV_DeletePlayerFromGroup(LPDPLOBBYI_DPLOBJECT this,
DWORD dwGroupID, DWORD dwPlayerID)
{
SPDATA_DELETEPLAYERFROMGROUP dpd;
MSG_PLAYERMGMTMESSAGE msg;
LPDPLAYI_PLAYER lpPlayer = NULL;
LPDPLAYI_GROUP lpGroup =NULL;
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_DeletePlayerFromGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
this, dwGroupID, dwPlayerID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Take the dplay lock since we'll be looking at a dplay internal struct
ENTER_DPLAY();
// Make sure the player is a local player, otherwise return AccessDenied
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
if(!lpPlayer)
{
DPF_ERR("Unable to find player in nametable");
hr = DPERR_INVALIDGROUP;
goto EXIT_DELETEPLAYERFROMGROUP;
}
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
DPF_ERR("Cannot delete a remote player from a group");
hr = DPERR_INVALIDPLAYER;
goto EXIT_DELETEPLAYERFROMGROUP;
}
// Drop the dplay lock since we're done
LEAVE_DPLAY();
// Setup our SPDATA struct
memset(&dpd, 0, sizeof(SPDATA_DELETEPLAYERFROMGROUP));
dpd.dwSize = sizeof(SPDATA_DELETEPLAYERFROMGROUP);
dpd.dwGroupID = dwGroupID;
dpd.dwPlayerID = dwPlayerID;
// Call the DeletePlayerFromGroup method in the SP
if(CALLBACK_EXISTS(DeletePlayerFromGroup))
{
dpd.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, DeletePlayerFromGroup, &dpd);
ENTER_DPLOBBY();
}
else
{
// DeletePlayerFromGroup is required
DPF_ERR("The Lobby Provider callback for DeletePlayerFromGroup doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling DeletePlayerFromGroup in the Lobby Provider, hr = 0x%08x", hr);
LEAVE_DPLOBBY();
return hr;
}
// Take the dplay lock
ENTER_DPLAY();
// We need to remove all other players in the group and send the appropriate
// message to the player we are about to delete because he won't see the
// system messages for them once he leaves the group. However, if any other
// local players are in the group, we don't want to remove the remote players
// from the nametable because the other local players need to see them.
// Get a pointer to dplay's internal group structure
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
if(!lpGroup)
{
DPF_ERRVAL("Unable to find group in nametable, idGroup = %lu", dwGroupID);
hr = DPERR_INVALIDGROUP;
goto EXIT_DELETEPLAYERFROMGROUP;
}
// Get a pointer to dplay's internal player structure
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
if(!lpPlayer)
{
DPF_ERRVAL("Unable to find player in nametable, hr = 0x%08x", hr);
hr = DPERR_INVALIDPLAYER;
goto EXIT_DELETEPLAYERFROMGROUP;
}
// We need to send a DeletePlayerFromGroup message to the player who
// was deleted since he won't get the group message once he's gone
// Now build the system message (at least the parts we need)
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
SET_MESSAGE_HDR(&msg);
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEPLAYERFROMGROUP);
msg.dwPlayerID = dwPlayerID;
msg.dwGroupID = dwGroupID;
// Call dplay's handleplayermessage function to put the message in the queue
hr = HandlePlayerMessage(lpPlayer, (LPBYTE)&msg,
sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
if(FAILED(hr))
{
DPF_ERRVAL("Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
// Set the hresult back to DP_OK since only the message failed
hr = DP_OK;
}
// Figure out how many local players are in this group. If it's only 1,
// then delete all the remote players.
lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
this->lpDPlayObject->pSysPlayer->dwID);
if((!lpGroupnode) || (lpGroupnode->nPlayers == 0))
{
// Destroy all remote players that are only in this group
PRV_DestroyRemotePlayersForExitingPlayer(this, lpGroup, dwGroupID);
// Destroy all the remote shortcut groups, making sure we are
// not in them, and removing their entire parental heirarchy
PRV_DestroyRemoteShortcutsForExitingPlayer(this, lpGroup, dwGroupID);
// Destroy all remote subgroups of this group, making sure we're
// not in them for some reason
PRV_DestroySubgroups(this, lpGroup, TRUE);
// Destroy the group we're leaving if it is remote as well as it's
// parental chain.
PRV_DestroyGroupAndParents(this, lpGroup, NULL);
}
EXIT_DELETEPLAYERFROMGROUP:
// The dplay InternalDeletePlayerFromGroup code will take care of the rest of
// the internal cleanup (nametable, players, etc.), so we can just return
// from here.
LEAVE_LOBBY_ALL();
return hr;
} // PRV_DeletePlayerFromGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroyGroup"
HRESULT DPLAPI PRV_DestroyGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
{
SPDATA_DESTROYGROUP dg;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_DestroyGroup");
DPF(9, "Parameters: 0x%08x, 0x%08x", this, dwLobbyID);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&dg, 0, sizeof(SPDATA_DESTROYGROUP));
dg.dwSize = sizeof(SPDATA_DESTROYGROUP);
dg.dwGroupID = dwLobbyID;
// Call the DestroyGroup method in the SP
if(CALLBACK_EXISTS(DestroyGroup))
{
dg.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, DestroyGroup, &dg);
ENTER_DPLOBBY();
}
else
{
// DestroyGroup is required
DPF_ERR("The Lobby Provider callback for DestroyGroup doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling DestroyGroup in the Lobby Provider, hr = 0x%08x", hr);
LEAVE_DPLOBBY();
return hr;
}
// Take the lock
ENTER_DPLAY();
// So, get dplay's internal group structure
lpGroup = GroupFromID(this->lpDPlayObject, dwLobbyID);
if(!lpGroup)
{
// This shouldn't ever happen. If the groups isn't in the nametable,
// we should never get this far.
ASSERT(FALSE);
LEAVE_LOBBY_ALL();
DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dwLobbyID);
return DPERR_INVALIDGROUP;
}
// Send messages to remove shortcuts to this group (since dplay won't
// do it for us)
PRV_SendDeleteShortcutMessageForExitingGroup(this, lpGroup);
// Destroy all the subgroups and remote players
PRV_RemoveSubgroupsAndPlayersFromGroup(this, lpGroup, dwLobbyID, FALSE);
// Drop the dplay lock since we're done mucking around with it's structures
LEAVE_DPLAY();
// Broadcast the DestroyGroup message
hr = PRV_BroadcastDestroyGroupMessage(this, dwLobbyID);
if(FAILED(hr))
{
DPF_ERRVAL("Failed to send DestroyGroup message to local players, hr = 0x%08x", hr);
}
// The dplay InternalDestroyGroup code will take care of the rest of
// the internal cleanup (nametable, players, etc.), so we can just return
// from here.
LEAVE_DPLOBBY();
return hr;
} // PRV_DestroyGroup
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetGroupConnectionSettings"
HRESULT PRV_GetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
DWORD dwGroupID, LPVOID lpData, LPDWORD lpdwSize)
{
SPDATA_GETGROUPCONNECTIONSETTINGS gcs;
LPDPLOBBYI_DPLOBJECT this = NULL;
LPDPLAYI_DPLAY lpDPObject = NULL;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_GetGroupConnectionSettings");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
lpDP, dwFlags, dwGroupID, lpData, lpdwSize);
TRY
{
lpDPObject = DPLAY_FROM_INT(lpDP);
hr = VALID_DPLAY_PTR( lpDPObject );
if (FAILED(hr))
{
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
return hr;
}
if(!IS_LOBBY_OWNED(lpDPObject))
{
DPF_ERR("GetGroupConnectionSettings is only supported for lobby connections");
return DPERR_UNSUPPORTED;
}
this = lpDPObject->lpLobbyObject;
if(!VALID_DPLOBBY_PTR(this))
{
DPF_ERR("Bad DPLobby object");
return DPERR_INVALIDOBJECT;
}
lpGroup = GroupFromID(lpDPObject, dwGroupID);
if (!VALID_DPLAY_GROUP(lpGroup))
{
DPF_ERR("Invalid group id");
return DPERR_INVALIDGROUP;
}
if( !VALID_DWORD_PTR( lpdwSize ) )
{
DPF_ERR("lpdwSize was not a valid dword pointer!");
return DPERR_INVALIDPARAMS;
}
if(lpData)
{
if( !VALID_WRITE_PTR(lpData, *lpdwSize) )
{
DPF_ERR("lpData is not a valid output buffer of the size specified in *lpdwSize");
return DPERR_INVALIDPARAMS;
}
}
// We haven't defined any flags for this release
if( (dwFlags) )
{
return DPERR_INVALIDFLAGS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&gcs, 0, sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS));
gcs.dwSize = sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS);
gcs.dwFlags = dwFlags;
gcs.dwGroupID = dwGroupID;
gcs.lpdwBufferSize = lpdwSize;
gcs.lpBuffer = lpData;
// Call the GetGroupConnectionSettings method in the SP
if(CALLBACK_EXISTS(GetGroupConnectionSettings))
{
gcs.lpISP = PRV_GetDPLobbySPInterface(this);
// Drop the dplay lock since we are going to send a guaranteed message
LEAVE_LOBBY_ALL();
hr = CALL_LP(this, GetGroupConnectionSettings, &gcs);
// Take the lock back
ENTER_LOBBY_ALL();
}
else
{
// GetGroupConnectionSettings is required
DPF_ERR("The Lobby Provider callback for GetGroupConnectionSettings doesn't exist -- it's required");
ASSERT(FALSE);
return DPERR_UNAVAILABLE;
}
if(FAILED(hr) && (hr != DPERR_BUFFERTOOSMALL))
{
DPF_ERRVAL("Failed calling GetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
}
return hr;
} // PRV_GetGroupConnectionSettings
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_GetGroupConnectionSettings"
HRESULT DPLAPI DPL_GetGroupConnectionSettings(LPDIRECTPLAY lpDP,
DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwSize)
{
HRESULT hr;
DPF(7, "Entering DPL_GetGroupConnectionSettings");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
lpDP, dwFlags, idGroup, lpData, lpdwSize);
ENTER_LOBBY_ALL();
// Set the ANSI flag to TRUE and call the internal function
hr = PRV_GetGroupConnectionSettings(lpDP, dwFlags, idGroup,
lpData, lpdwSize);
LEAVE_LOBBY_ALL();
return hr;
} // DPL_GetGroupConnectionSettings
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetGroupData"
HRESULT DPLAPI PRV_GetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
LPVOID lpData, LPDWORD lpdwDataSize)
{
SPDATA_GETGROUPDATA ggd;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_GetGroupData");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
this, dwGroupID, lpData, lpdwDataSize);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLOBBY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&ggd, 0, sizeof(SPDATA_GETGROUPDATA));
ggd.dwSize = sizeof(SPDATA_GETGROUPDATA);
ggd.dwGroupID = dwGroupID;
ggd.lpdwDataSize = lpdwDataSize;
ggd.lpData = lpData;
// Call the GetGroupData method in the SP
if(CALLBACK_EXISTS(GetGroupData))
{
ggd.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, GetGroupData, &ggd);
ENTER_DPLOBBY();
}
else
{
// GetGroupData is required
DPF_ERR("The Lobby Provider callback for GetGroupData doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling GetGroupData in the Lobby Provider, hr = 0x%08x", hr);
}
LEAVE_DPLOBBY();
return hr;
} // PRV_GetGroupData
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_GetGroupOwner"
HRESULT DPAPI DPL_GetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
LPDPID lpidOwner)
{
LPDPLAYI_DPLAY this;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr;
DPF(7, "Entering DPL_GetGroupOwner");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
lpDP, dwGroupID, lpidOwner);
ENTER_DPLAY();
TRY
{
this = DPLAY_FROM_INT(lpDP);
hr = VALID_DPLAY_PTR( this );
if (FAILED(hr))
{
LEAVE_DPLAY();
DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
return hr;
}
lpGroup = GroupFromID(this, dwGroupID);
if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
{
LEAVE_DPLAY();
DPF_ERR("Invalid group id");
return DPERR_INVALIDGROUP;
}
if (!VALID_DWORD_PTR(lpidOwner))
{
LEAVE_DPLAY();
DPF_ERR("Invalid owner id pointer");
return DPERR_INVALIDPARAMS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLAY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// This method is only valid in lobby session
if(IS_LOBBY_OWNED(this))
{
*lpidOwner = lpGroup->dwOwnerID;
}
else
{
DPF_ERR("GetGroupOwner is only supported for lobby sessions");
hr = DPERR_UNSUPPORTED;
}
LEAVE_DPLAY();
return hr;
} // DPL_GetGroupOwner
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SetGroupConnectionSettings"
HRESULT PRV_SetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
DWORD dwGroupID, LPDPLCONNECTION lpConn, BOOL bAnsi)
{
SPDATA_SETGROUPCONNECTIONSETTINGS scs;
LPDPLOBBYI_DPLOBJECT this = NULL;
LPDPLAYI_DPLAY lpDPObject = NULL;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_SetGroupConnectionSettings");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu",
lpDP, dwFlags, dwGroupID, lpConn, bAnsi);
TRY
{
lpDPObject = DPLAY_FROM_INT(lpDP);
hr = VALID_DPLAY_PTR( lpDPObject );
if (FAILED(hr))
{
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
return hr;
}
if(!IS_LOBBY_OWNED(lpDPObject))
{
DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
return DPERR_UNSUPPORTED;
}
this = lpDPObject->lpLobbyObject;
if(!VALID_DPLOBBY_PTR(this))
{
DPF_ERR("Bad DPLobby object");
return DPERR_INVALIDOBJECT;
}
lpGroup = GroupFromID(lpDPObject, dwGroupID);
if (!VALID_DPLAY_GROUP(lpGroup))
{
DPF_ERR("Invalid group id");
return DPERR_INVALIDGROUP;
}
hr = PRV_ValidateDPLCONNECTION(lpConn, FALSE);
if(FAILED(hr))
{
DPF_ERR("Invalid DPLCONNECTION structure");
return hr;
}
// We haven't defined any flags for this release
if( (dwFlags) )
{
return DPERR_INVALIDFLAGS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&scs, 0, sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS));
scs.dwSize = sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS);
scs.dwFlags = dwFlags;
scs.dwGroupID = dwGroupID;
scs.lpConn = lpConn;
// Ensure that the guidInstance in the DPLCONNECTION structure is NULL
lpConn->lpSessionDesc->guidInstance = GUID_NULL;
// Call the SetGroupConnectionSettings method in the SP
if(CALLBACK_EXISTS(SetGroupConnectionSettings))
{
scs.lpISP = PRV_GetDPLobbySPInterface(this);
// Drop the dplay lock since we're sending a guaranteed message
LEAVE_LOBBY_ALL();
hr = CALL_LP(this, SetGroupConnectionSettings, &scs);
// Take the lock back
ENTER_LOBBY_ALL();
}
else
{
// SetGroupConnectionSettings is required
DPF_ERR("The Lobby Provider callback for SetGroupConnectionSettings doesn't exist -- it's required");
ASSERT(FALSE);
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling SetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
}
return hr;
} // PRV_SetGroupConnectionSettings
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_SetGroupConnectionSettings"
HRESULT DPLAPI DPL_SetGroupConnectionSettings(LPDIRECTPLAY lpDP,
DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConn)
{
HRESULT hr;
DPF(7, "Entering DPL_SetGroupConnectionSettings");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
lpDP, dwFlags, idGroup, lpConn);
ENTER_LOBBY_ALL();
// Set the ANSI flag to TRUE and call the internal function
hr = PRV_SetGroupConnectionSettings(lpDP, dwFlags, idGroup, lpConn, FALSE);
LEAVE_LOBBY_ALL();
return hr;
} // DPL_SetGroupConnectionSettings
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SetGroupData"
HRESULT DPLAPI PRV_SetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
LPVOID lpData, DWORD dwDataSize, DWORD dwFlags)
{
SPDATA_SETGROUPDATA sgd;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_SetGroupData");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu, 0x%08x",
this, dwGroupID, lpData, dwDataSize, dwFlags);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLAY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLAY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&sgd, 0, sizeof(SPDATA_SETGROUPDATA));
sgd.dwSize = sizeof(SPDATA_SETGROUPDATA);
sgd.dwGroupID = dwGroupID;
sgd.dwDataSize = dwDataSize;
sgd.lpData = lpData;
sgd.dwFlags = dwFlags;
// Call the SetGroupData method in the SP
if(CALLBACK_EXISTS(SetGroupData))
{
sgd.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, SetGroupData, &sgd);
ENTER_DPLOBBY();
}
else
{
// SetGroupData is required
DPF_ERR("The Lobby Provider callback for SetGroupData doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_SETGROUPDATA;
}
// If it succeeded, send the SetGroupData message to our local players
if(SUCCEEDED(hr))
{
hr = PRV_SendDataChangedMessageLocally(this, dwGroupID, lpData, dwDataSize);
}
else
{
DPF_ERRVAL("Failed calling SetGroupData in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_SETGROUPDATA:
LEAVE_DPLOBBY();
return hr;
} // PRV_SetGroupData
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SetGroupName"
HRESULT DPLAPI PRV_SetGroupName(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
LPDPNAME lpName, DWORD dwFlags)
{
SPDATA_SETGROUPNAME sgn;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_SetGroupName");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
this, dwGroupID, lpName, dwFlags);
ENTER_DPLOBBY();
TRY
{
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_DPLAY();
return DPERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLAY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Setup our SPDATA struct
memset(&sgn, 0, sizeof(SPDATA_SETGROUPNAME));
sgn.dwSize = sizeof(SPDATA_SETGROUPNAME);
sgn.dwGroupID = dwGroupID;
sgn.lpName = lpName;
sgn.dwFlags = dwFlags;
// Call the SetGroupName method in the SP
if(CALLBACK_EXISTS(SetGroupName))
{
sgn.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, SetGroupName, &sgn);
ENTER_DPLOBBY();
}
else
{
// SetGroupName is required
DPF_ERR("The Lobby Provider callback for SetGroupName doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_SETGROUPNAME;
}
// If it succeeded, send the SetGroupName message to our local players
if(SUCCEEDED(hr))
{
hr = PRV_SendNameChangedMessageLocally(this, dwGroupID, lpName, FALSE);
}
else
{
DPF_ERRVAL("Failed calling SetGroupName in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_SETGROUPNAME:
LEAVE_DPLOBBY();
return hr;
} // PRV_SetGroupName
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_SetGroupOwner"
HRESULT DPLAPI DPL_SetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
DWORD dwOwnerID)
{
LPDPLOBBYI_DPLOBJECT this;
LPDPLAYI_DPLAY lpDPlayObject;
SPDATA_SETGROUPOWNER sgo;
LPDPLAYI_PLAYER lpNewOwner = NULL;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DWORD dwOldOwnerID;
DPF(7, "Entering DPL_SetGroupOwner");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
lpDP, dwGroupID, dwOwnerID);
ENTER_LOBBY_ALL();
TRY
{
lpDPlayObject = DPLAY_FROM_INT(lpDP);
hr = VALID_DPLAY_PTR( lpDPlayObject );
if (FAILED(hr))
{
LEAVE_LOBBY_ALL();
DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
return hr;
}
this = lpDPlayObject->lpLobbyObject;
if( !VALID_DPLOBBY_PTR( this ) )
{
LEAVE_LOBBY_ALL();
return DPERR_INVALIDOBJECT;
}
lpGroup = GroupFromID(lpDPlayObject, dwGroupID);
if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
{
LEAVE_LOBBY_ALL();
DPF_ERR("Invalid group id");
return DPERR_INVALIDGROUP;
}
// DPID_SERVERPLAYER is valid here
if(dwOwnerID != DPID_SERVERPLAYER)
{
lpNewOwner = PlayerFromID(lpDPlayObject, dwOwnerID);
if (!VALID_DPLAY_PLAYER(lpNewOwner))
{
LEAVE_LOBBY_ALL();
DPF_ERR("Invalid new owner player id");
return DPERR_INVALIDPLAYER;
}
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_LOBBY_ALL();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// do the send
if(!IS_LOBBY_OWNED(lpDPlayObject))
{
DPF_ERR("SetGroupOwner is only supported for lobby sessions");
hr = DPERR_UNSUPPORTED;
goto EXIT_SETGROUPOWNER;
}
// Setup our SPDATA struct
memset(&sgo, 0, sizeof(SPDATA_SETGROUPOWNER));
sgo.dwSize = sizeof(SPDATA_SETGROUPOWNER);
sgo.dwGroupID = dwGroupID;
sgo.dwOwnerID = dwOwnerID;
// Call the SetGroupOwner method in the SP
if(CALLBACK_EXISTS(SetGroupOwner))
{
sgo.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
// response (which always happens)
LEAVE_LOBBY_ALL();
hr = CALL_LP(this, SetGroupOwner, &sgo);
ENTER_LOBBY_ALL();
}
else
{
// SetGroupOwner is required
DPF_ERR("The Lobby Provider callback for SetGroupOwner doesn't exist");
hr = DPERR_UNAVAILABLE;
goto EXIT_SETGROUPOWNER;
}
// If it succeeded, send the SetGroupOwner message to our local players
if(SUCCEEDED(hr))
{
// Get a pointer to our internal data struct for the group, just in
// case it changed for some reason while we had dropped the locks
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
if(!lpGroup)
{
DPF_ERR("Unable to find group in nametable -- local nametable will be incorrect");
goto EXIT_SETGROUPOWNER;
}
// Save the old owner so we can put it in the message
dwOldOwnerID = lpGroup->dwOwnerID;
// Change the owner
lpGroup->dwOwnerID = dwOwnerID;
// Send a SetGroupOwner message locally
PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwOwnerID, dwOldOwnerID);
}
else
{
DPF_ERRVAL("Failed calling SetGroupOwner in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_SETGROUPOWNER:
LEAVE_LOBBY_ALL();
return hr;
} // DPL_SetGroupOwner
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_StartSession"
HRESULT DPLAPI DPL_StartSession(LPDIRECTPLAY lpDP, DWORD dwFlags, DWORD dwGroupID)
{
SPDATA_STARTSESSION ss;
LPDPLOBBYI_DPLOBJECT this = NULL;
LPDPLAYI_DPLAY lpDPObject = NULL;
LPDPLAYI_GROUP lpGroup = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_StartSession");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
lpDP, dwFlags, dwGroupID);
ENTER_LOBBY_ALL();
TRY
{
lpDPObject = DPLAY_FROM_INT(lpDP);
hr = VALID_DPLAY_PTR( lpDPObject );
if (FAILED(hr))
{
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
goto ERROR_STARTSESSION;
}
if(!IS_LOBBY_OWNED(lpDPObject))
{
DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
hr = DPERR_UNSUPPORTED;
goto ERROR_STARTSESSION;
}
this = lpDPObject->lpLobbyObject;
if(!VALID_DPLOBBY_PTR(this))
{
DPF_ERR("Bad DPLobby object");
hr = DPERR_INVALIDOBJECT;
goto ERROR_STARTSESSION;
}
if(dwFlags)
{
DPF_ERR("Invalid flags");
hr = DPERR_INVALIDFLAGS;
goto ERROR_STARTSESSION;
}
lpGroup = GroupFromID(lpDPObject, dwGroupID);
if (!VALID_DPLAY_GROUP(lpGroup))
{
DPF_ERR("Invalid group id");
hr = DPERR_INVALIDGROUP;
goto ERROR_STARTSESSION;
}
// Make sure the group is a staging area
if(!(lpGroup->dwFlags & DPLAYI_GROUP_STAGINGAREA))
{
DPF_ERR("StartSession can only be called on a Staging Area");
hr = DPERR_INVALIDGROUP;
goto ERROR_STARTSESSION;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
hr = DPERR_INVALIDPARAMS;
goto ERROR_STARTSESSION;
}
// Setup our SPDATA struct
memset(&ss, 0, sizeof(SPDATA_STARTSESSION));
ss.dwSize = sizeof(SPDATA_STARTSESSION);
ss.dwGroupID = dwGroupID;
ss.dwFlags = dwFlags;
// Call the StartSession method in the SP
if(CALLBACK_EXISTS(StartSession))
{
ss.lpISP = PRV_GetDPLobbySPInterface(this);
// Drop the dplay lock so we can send a guarateed message
LEAVE_LOBBY_ALL();
hr = CALL_LP(this, StartSession, &ss);
// Take the lock back
ENTER_LOBBY_ALL();
}
else
{
// StartSession is required
DPF_ERR("The Lobby Provider callback for StartSession doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto ERROR_STARTSESSION;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling StartSession in the Lobby Provider, hr = 0x%08x", hr);
}
ERROR_STARTSESSION:
LEAVE_LOBBY_ALL();
return hr;
} // DPL_StartSession
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CreateAndMapNewGroup"
HRESULT PRV_CreateAndMapNewGroup(LPDPLOBBYI_DPLOBJECT this,
DPID * lpdpid, LPDPNAME lpName, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, DWORD dwLobbyID,
DPID dpidParent, DWORD dwOwnerID)
{
LPDPLAYI_GROUP lpGroup = NULL, lpSysGroup = NULL;
HRESULT hr;
DPID dpidGroup, dpidSysPlayer;
// Take the dplay lock
ENTER_DPLAY();
// Make sure the lobby ID is valid
if(!IsValidLobbyID(dwLobbyID))
{
DPF_ERRVAL("ID %lu is reserved, cannot create new player", dwLobbyID);
hr = DPERR_INVALIDPLAYER;
goto EXIT_CREATEANDMAPNEWGROUP;
}
// If this is a remote player, we need allocate a new nametable entry
// for them and set the correct system player ID
if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
// Allocate a new ID for the player
hr = NS_AllocNameTableEntry(this->lpDPlayObject, &dpidGroup);
if(FAILED(hr))
{
DPF_ERRVAL("Unable to allocate new nametable id, hr = 0x%08x", hr);
goto EXIT_CREATEANDMAPNEWGROUP;
}
// Make sure we have a lobby system player (for all remote players
// & groups). If we don't then allocate a new one.
if(!(this->dpidSysPlayer))
{
hr = PRV_CreateAndMapNewPlayer(this, &dpidSysPlayer, NULL, NULL,
NULL, 0, DPLAYI_PLAYER_SYSPLAYER,
DPID_LOBBYREMOTESYSTEMPLAYER, TRUE);
if(FAILED(hr))
{
DPF_ERRVAL("Unable to create lobby system player, hr = 0x%08x", hr);
ASSERT(FALSE);
goto EXIT_CREATEANDMAPNEWGROUP;
}
// Set the lobby system player ID pointer to the new ID
this->dpidSysPlayer = dpidSysPlayer;
}
}
// Get a group struct for the group (if it's local, this will add it
// to the nametable. If it's remote, we need to add it below)
hr = GetGroup(this->lpDPlayObject, &lpGroup, lpName, lpData,
dwDataSize, dwFlags, dpidParent, dwLobbyID);
if(FAILED(hr))
{
DPF_ERRVAL("Failed trying to add group to the nametable, hr = 0x%08x", hr);
goto EXIT_CREATEANDMAPNEWGROUP;
}
// Fixup the group's owner
lpGroup->dwOwnerID = dwOwnerID;
// If the group is remote, set the group's ID to the new one we
// allocated and then set the system group ID to the lobby system group
if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
//
lpGroup->dwIDSysPlayer = this->dpidSysPlayer;
// Add the group to the nametable
hr = AddItemToNameTable(this->lpDPlayObject, (DWORD_PTR)lpGroup,
&dpidGroup, TRUE, dwLobbyID);
if (FAILED(hr))
{
DPF_ERRVAL("Unable to add new group to the nametable, hr = 0x%08x", hr);
ASSERT(FALSE);
goto EXIT_CREATEANDMAPNEWGROUP;
}
// Set the group's ID
lpGroup->dwID = dpidGroup;
}
// Set the output dpid pointer
*lpdpid = lpGroup->dwID;
EXIT_CREATEANDMAPNEWGROUP:
LEAVE_DPLAY();
return hr;
} // PRV_CreateAndMapNewGroup