|
|
/*==========================================================================
* * 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
|