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

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: group.c
  6. * Content: Methods for managing groups
  7. *
  8. * History:
  9. * Date By Reason
  10. * ======= ======= ======
  11. * 2/27/97 myronth Created it
  12. * 3/17/97 myronth Create/DestroyGroup, Removed unnecessary Enum functions
  13. * 3/20/97 myronth AddPlayerToGroup, DeletePlayerFromGroup
  14. * 3/21/97 myronth SetGroupName, Get/SetGroupData
  15. * 3/31/97 myronth Removed dead code, Added CreateAndMapNewGroup function
  16. * 4/3/97 myronth Changed CALLSP macro to CALL_LP
  17. * 5/6/97 kipo GetGroup() now takes a parent ID
  18. * 5/8/97 myronth Subgroup support, GroupConnSettings, StartSession,
  19. * and drop the lobby lock when calling the LP
  20. * 5/12/97 myronth Handle remote groups properly
  21. * 5/17/97 myronth Added parent ID to CreateAndMapNewGroup calls,
  22. * Added send message code for DestroyGroup and
  23. * DeletePlayerFromGroup on the local machine
  24. * 5/20/97 myronth Send Delete & DestroyPlayer messages for remote
  25. * players when a local player leaves a group (#8586)
  26. * Made AddPlayerToGroup & DeletePlayerFromGroup return
  27. * DPERR_ACCESSDENIED on remote players (#8679),
  28. * Fixed a bunch of other lock bugs, Changed debug levels
  29. * 5/21/97 myronth Pass CreateGroup flags through the lobby (#8813)
  30. * 5/22/97 myronth Added functions to destroy remote subgroups when
  31. * a local player leaves a group (#8810)
  32. * 5/23/97 myronth Send messages locally for CreateGroup and
  33. * CreateGroupInGroup (#8870)
  34. * 6/3/97 myronth Added PRV_DestroySubgroups function (#9134) and
  35. * rearranged some of the DestroyGroup code
  36. * 6/5/97 myronth Added shortcut checking to PRV_DestroySubgroups by
  37. * adding the PRV_AreSubgroupsShortcuts function
  38. * 6/6/97 myronth Added PRV_DestroyGroupAndParents and PRV_Destroy-
  39. * ShortcutsForExitingPlayer, cleaned up PRV_Delete-
  40. * PlayerFromGroup, Fixed StartSession bugs (#9573,#9574)
  41. * 6/9/97 myronth Only delete shortcuts (don't destroy the subgoup)
  42. * in the PRV_DestroySubgroups function
  43. * 6/16/97 myronth Fixed bad deletion of uncle groups & some subgroups
  44. * during DeletePlayerFromGroup (#9655)
  45. * 6/20/97 myronth Send AddGroupToGroup message locally to avoid
  46. * sending duplicate messages. Also added code to
  47. * send local DeleteGroupFromGroup messages (#10139)
  48. * 6/24/97 myronth Send AddPlayerToGroup message locally to avoid
  49. * sending duplicate messages (#10287)
  50. * 8/22/97 myronth Force guidInstance to NULL in SetGroupConnectionSettings
  51. * 9/29/97 myronth Send local SetGroupName/Data msgs after call to
  52. * lobby server succeeds (#12554)
  53. * 10/23/97 myronth Added hidden group support (#12688), fixed crashing
  54. * bug on DeletePlayerFromGroup (#12885)
  55. * 10/29/97 myronth Added support for group owners, including
  56. * DPL_SetGroupOwner and DPL_GetGroupOwner
  57. * 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
  58. ***************************************************************************/
  59. #include "dplobpr.h"
  60. //--------------------------------------------------------------------------
  61. //
  62. // Functions
  63. //
  64. //--------------------------------------------------------------------------
  65. #undef DPF_MODNAME
  66. #define DPF_MODNAME "PRV_AddGroupToGroup"
  67. HRESULT DPLAPI PRV_AddGroupToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
  68. DWORD dwGroupID)
  69. {
  70. SPDATA_ADDGROUPTOGROUP ad;
  71. MSG_PLAYERMGMTMESSAGE msg;
  72. LPDPLAYI_GROUP lpGroupTo = NULL;
  73. HRESULT hr = DP_OK;
  74. DPF(7, "Entering DPL_AddGroupToGroup");
  75. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  76. this, dwParentID, dwGroupID);
  77. ENTER_DPLOBBY();
  78. TRY
  79. {
  80. if( !VALID_DPLOBBY_PTR( this ) )
  81. {
  82. LEAVE_DPLAY();
  83. return DPERR_INVALIDOBJECT;
  84. }
  85. }
  86. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  87. {
  88. LEAVE_DPLAY();
  89. DPF_ERR( "Exception encountered validating parameters" );
  90. return DPERR_INVALIDPARAMS;
  91. }
  92. // Setup our SPDATA struct
  93. memset(&ad, 0, sizeof(SPDATA_ADDGROUPTOGROUP));
  94. ad.dwSize = sizeof(SPDATA_ADDGROUPTOGROUP);
  95. ad.dwParentID = dwParentID;
  96. ad.dwGroupID = dwGroupID;
  97. // Call the AddGroupToGroup method in the SP
  98. if(CALLBACK_EXISTS(AddGroupToGroup))
  99. {
  100. ad.lpISP = PRV_GetDPLobbySPInterface(this);
  101. // Drop the lock so the lobby provider's receive thread can get back
  102. // in with other messages if they show up in the queue before our
  103. // CreatePlayer response (which always happens)
  104. LEAVE_DPLOBBY();
  105. hr = CALL_LP(this, AddGroupToGroup, &ad);
  106. ENTER_DPLOBBY();
  107. }
  108. else
  109. {
  110. // AddGroupToGroup is required
  111. DPF_ERR("The Lobby Provider callback for AddGroupToGroup doesn't exist -- it's required");
  112. ASSERT(FALSE);
  113. hr = DPERR_UNAVAILABLE;
  114. goto EXIT_ADDGROUPTOGROUP;
  115. }
  116. // If it succeeded, send the AddGroupToGroup message to our local players
  117. if(SUCCEEDED(hr))
  118. {
  119. // Take the dplay lock
  120. ENTER_DPLAY();
  121. // Find dplay's internal group struct for the To group
  122. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  123. if(!lpGroupTo)
  124. {
  125. LEAVE_DPLAY();
  126. DPF_ERR("Unable to find group in nametable");
  127. hr = DPERR_INVALIDGROUP;
  128. goto EXIT_ADDGROUPTOGROUP;
  129. }
  130. // Now build the system message (at least the parts we need)
  131. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  132. SET_MESSAGE_HDR(&msg);
  133. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDSHORTCUTTOGROUP);
  134. msg.dwPlayerID = dwGroupID;
  135. msg.dwGroupID = dwParentID;
  136. // Call dplay's DistributeGroupMessage function to put the message
  137. // in the queues of all the appropriate players
  138. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  139. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  140. if(FAILED(hr))
  141. {
  142. DPF(8, "Failed adding AddGroupToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  143. }
  144. // Drop the dplay lock
  145. LEAVE_DPLAY();
  146. }
  147. else
  148. {
  149. DPF_ERRVAL("Failed calling AddGroupToGroup in the Lobby Provider, hr = 0x%08x", hr);
  150. }
  151. EXIT_ADDGROUPTOGROUP:
  152. LEAVE_DPLOBBY();
  153. return hr;
  154. } // PRV_AddGroupToGroup
  155. #undef DPF_MODNAME
  156. #define DPF_MODNAME "PRV_AddPlayerToGroup"
  157. HRESULT DPLAPI PRV_AddPlayerToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
  158. DWORD dwPlayerID)
  159. {
  160. SPDATA_ADDPLAYERTOGROUP ad;
  161. LPDPLAYI_PLAYER lpPlayer = NULL;
  162. MSG_PLAYERMGMTMESSAGE msg;
  163. LPDPLAYI_GROUP lpGroupTo = NULL;
  164. LPDPLAYI_GROUP lpGroup = NULL;
  165. HRESULT hr = DP_OK;
  166. DPF(7, "Entering DPL_AddPlayerToGroup");
  167. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  168. this, dwGroupID, dwPlayerID);
  169. ENTER_DPLOBBY();
  170. TRY
  171. {
  172. if( !VALID_DPLOBBY_PTR( this ) )
  173. {
  174. LEAVE_DPLAY();
  175. return DPERR_INVALIDOBJECT;
  176. }
  177. }
  178. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  179. {
  180. LEAVE_DPLAY();
  181. DPF_ERR( "Exception encountered validating parameters" );
  182. return DPERR_INVALIDPARAMS;
  183. }
  184. // Take the dplay lock since we'll be looking at a dplay internal struct
  185. ENTER_DPLAY();
  186. // Make sure the player is a local player, otherwise return AccessDenied
  187. lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
  188. if(!lpPlayer)
  189. {
  190. LEAVE_DPLAY();
  191. DPF_ERR("Unable to find player in nametable");
  192. hr = DPERR_INVALIDPLAYER;
  193. goto EXIT_ADDPLAYERTOGROUP;
  194. }
  195. if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  196. {
  197. LEAVE_DPLAY();
  198. DPF_ERR("Cannot add a remote player to a group");
  199. hr = DPERR_ACCESSDENIED;
  200. goto EXIT_ADDPLAYERTOGROUP;
  201. }
  202. // Drop the dplay lock since we're done
  203. LEAVE_DPLAY();
  204. // Setup our SPDATA struct
  205. memset(&ad, 0, sizeof(SPDATA_ADDPLAYERTOGROUP));
  206. ad.dwSize = sizeof(SPDATA_ADDPLAYERTOGROUP);
  207. ad.dwGroupID = dwGroupID;
  208. ad.dwPlayerID = dwPlayerID;
  209. // Call the AddPlayerToGroup method in the SP
  210. if(CALLBACK_EXISTS(AddPlayerToGroup))
  211. {
  212. ad.lpISP = PRV_GetDPLobbySPInterface(this);
  213. // Drop the lock so the lobby provider's receive thread can get back
  214. // in with other messages if they show up in the queue before our
  215. // CreatePlayer response (which always happens)
  216. LEAVE_DPLOBBY();
  217. hr = CALL_LP(this, AddPlayerToGroup, &ad);
  218. ENTER_DPLOBBY();
  219. }
  220. else
  221. {
  222. // AddPlayerToGroup is required
  223. DPF_ERR("The Lobby Provider callback for AddPlayerToGroup doesn't exist -- it's required");
  224. ASSERT(FALSE);
  225. hr = DPERR_UNAVAILABLE;
  226. goto EXIT_ADDPLAYERTOGROUP;
  227. }
  228. // If it succeeded, send the AddPlayerToGroup message to our local players
  229. if(SUCCEEDED(hr))
  230. {
  231. // Take the dplay lock
  232. ENTER_DPLAY();
  233. // Find dplay's internal group struct for the To group
  234. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  235. if(!lpGroupTo)
  236. {
  237. LEAVE_DPLAY();
  238. DPF_ERR("Unable to find group in nametable");
  239. hr = DPERR_INVALIDGROUP;
  240. goto EXIT_ADDPLAYERTOGROUP;
  241. }
  242. // Now build the system message (at least the parts we need)
  243. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  244. SET_MESSAGE_HDR(&msg);
  245. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDPLAYERTOGROUP);
  246. msg.dwPlayerID = dwPlayerID;
  247. msg.dwGroupID = dwGroupID;
  248. // Call dplay's DistributeGroupMessage function to put the message
  249. // in the queues of all the appropriate players
  250. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  251. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  252. if(FAILED(hr))
  253. {
  254. DPF(8, "Failed adding AddPlayerToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  255. }
  256. else
  257. {
  258. // We need to see if this player is the group owner. If it is,
  259. // we need to send a SetGroupOwner message as well.
  260. lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
  261. if(lpGroup && (dwPlayerID == lpGroup->dwOwnerID))
  262. {
  263. // Now send the message
  264. PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwPlayerID, 0);
  265. }
  266. }
  267. // Drop the dplay lock
  268. LEAVE_DPLAY();
  269. }
  270. else
  271. {
  272. DPF_ERRVAL("Failed calling AddPlayerToGroup in the Lobby Provider, hr = 0x%08x", hr);
  273. }
  274. EXIT_ADDPLAYERTOGROUP:
  275. LEAVE_DPLOBBY();
  276. return hr;
  277. } // PRV_AddPlayerToGroup
  278. #undef DPF_MODNAME
  279. #define DPF_MODNAME "PRV_CreateGroup"
  280. HRESULT DPLAPI PRV_CreateGroup(LPDPLOBBYI_DPLOBJECT this, LPDPID lpidGroup,
  281. LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags,
  282. DWORD dwOwnerID)
  283. {
  284. SPDATA_CREATEGROUP cg;
  285. MSG_PLAYERMGMTMESSAGE msg;
  286. LPDPLAYI_GROUP lpGroupTo = NULL;
  287. DWORD dwInternalFlags;
  288. HRESULT hr = DP_OK;
  289. DPF(7, "Entering PRV_CreateGroup");
  290. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
  291. this, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
  292. ENTER_DPLOBBY();
  293. TRY
  294. {
  295. if( !VALID_DPLOBBY_PTR( this ) )
  296. {
  297. LEAVE_DPLOBBY();
  298. return DPERR_INVALIDOBJECT;
  299. }
  300. }
  301. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  302. {
  303. LEAVE_DPLOBBY();
  304. DPF_ERR( "Exception encountered validating parameters" );
  305. return DPERR_INVALIDPARAMS;
  306. }
  307. // Setup our SPDATA struct
  308. memset(&cg, 0, sizeof(SPDATA_CREATEGROUP));
  309. cg.dwSize = sizeof(SPDATA_CREATEGROUP);
  310. cg.lpName = lpName;
  311. cg.lpData = lpData;
  312. cg.dwDataSize = dwDataSize;
  313. cg.dwFlags = dwFlags;
  314. cg.dwGroupOwnerID = dwOwnerID;
  315. // Call the CreateGroup method in the SP
  316. if(CALLBACK_EXISTS(CreateGroup))
  317. {
  318. cg.lpISP = PRV_GetDPLobbySPInterface(this);
  319. // Drop the lock so the lobby provider's receive thread can get back
  320. // in with other messages if they show up in the queue before our
  321. // CreatePlayer response (which always happens)
  322. LEAVE_DPLOBBY();
  323. hr = CALL_LP(this, CreateGroup, &cg);
  324. ENTER_DPLOBBY();
  325. }
  326. else
  327. {
  328. // CreateGroup is required
  329. DPF_ERR("The Lobby Provider callback for CreateGroup doesn't exist -- it's required");
  330. ASSERT(FALSE);
  331. LEAVE_DPLOBBY();
  332. return DPERR_UNAVAILABLE;
  333. }
  334. if(FAILED(hr))
  335. {
  336. DPF_ERRVAL("Failed calling CreateGroup in the Lobby Provider, hr = 0x%08x", hr);
  337. goto EXIT_CREATEGROUP;
  338. }
  339. // Setup the flags to pass to GetGroup
  340. dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
  341. if(dwFlags & DPGROUP_STAGINGAREA)
  342. dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
  343. if(dwFlags & DPGROUP_HIDDEN)
  344. dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
  345. // Add the player to dplay's nametable and put it in our map table
  346. hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
  347. dwDataSize, dwInternalFlags, cg.dwGroupID, 0, dwOwnerID);
  348. if(FAILED(hr))
  349. {
  350. DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
  351. // REVIEW!!!! -- We need to send a message back to the server saying
  352. // we couldn't complete the deal on our end.
  353. goto EXIT_CREATEGROUP;
  354. }
  355. // Now build the system message (at least the parts we need)
  356. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  357. SET_MESSAGE_HDR(&msg);
  358. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
  359. msg.dwPlayerID = *lpidGroup;
  360. // Take the lock
  361. ENTER_DPLAY();
  362. // Find dplay's internal group struct for the To group
  363. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  364. if(!lpGroupTo)
  365. {
  366. LEAVE_DPLAY();
  367. DPF_ERRVAL("Unable to find system group in nametable, hr = 0x%08x", hr);
  368. goto EXIT_CREATEGROUP;
  369. }
  370. // Call dplay's DistributeGroupMessage function to put the message in
  371. // the queues of all the appropriate players
  372. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo, (LPBYTE)&msg,
  373. sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  374. if(FAILED(hr))
  375. {
  376. DPF(2, "Failed adding CreateGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  377. }
  378. LEAVE_DPLAY();
  379. EXIT_CREATEGROUP:
  380. LEAVE_DPLOBBY();
  381. return hr;
  382. } // PRV_CreateGroup
  383. #undef DPF_MODNAME
  384. #define DPF_MODNAME "PRV_CreateGroupInGroup"
  385. HRESULT DPLAPI PRV_CreateGroupInGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
  386. LPDPID lpidGroup, LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize,
  387. DWORD dwFlags, DWORD dwOwnerID)
  388. {
  389. SPDATA_CREATEGROUPINGROUP cgig;
  390. MSG_PLAYERMGMTMESSAGE msg;
  391. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  392. LPDPLAYI_GROUP lpGroupTo = NULL;
  393. HRESULT hr = DP_OK;
  394. DWORD dwInternalFlags;
  395. DPF(7, "Entering PRV_CreateGroupInGroup");
  396. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
  397. this, dwParentID, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
  398. ENTER_DPLOBBY();
  399. TRY
  400. {
  401. if( !VALID_DPLOBBY_PTR( this ) )
  402. {
  403. LEAVE_DPLOBBY();
  404. return DPERR_INVALIDOBJECT;
  405. }
  406. }
  407. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  408. {
  409. LEAVE_DPLOBBY();
  410. DPF_ERR( "Exception encountered validating parameters" );
  411. return DPERR_INVALIDPARAMS;
  412. }
  413. // Setup our SPDATA struct
  414. memset(&cgig, 0, sizeof(SPDATA_CREATEGROUPINGROUP));
  415. cgig.dwSize = sizeof(SPDATA_CREATEGROUPINGROUP);
  416. cgig.dwParentID = dwParentID;
  417. cgig.lpName = lpName;
  418. cgig.lpData = lpData;
  419. cgig.dwDataSize = dwDataSize;
  420. cgig.dwFlags = dwFlags;
  421. cgig.dwGroupOwnerID = dwOwnerID;
  422. // Call the CreateGroupInGroup method in the SP
  423. if(CALLBACK_EXISTS(CreateGroupInGroup))
  424. {
  425. cgig.lpISP = PRV_GetDPLobbySPInterface(this);
  426. // Drop the lock so the lobby provider's receive thread can get back
  427. // in with other messages if they show up in the queue before our
  428. // CreatePlayer response (which always happens)
  429. LEAVE_DPLOBBY();
  430. hr = CALL_LP(this, CreateGroupInGroup, &cgig);
  431. ENTER_DPLOBBY();
  432. }
  433. else
  434. {
  435. // CreateGroupInGroup is required
  436. DPF_ERR("The Lobby Provider callback for CreateGroupInGroup doesn't exist -- it's required");
  437. ASSERT(FALSE);
  438. LEAVE_DPLOBBY();
  439. return DPERR_UNAVAILABLE;
  440. }
  441. if(FAILED(hr))
  442. {
  443. DPF_ERRVAL("Failed calling CreateGroupInGroup in the Lobby Provider, hr = 0x%08x", hr);
  444. LEAVE_DPLOBBY();
  445. return hr;
  446. }
  447. // Setup the flags to pass to GetGroup
  448. dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
  449. if(dwFlags & DPGROUP_STAGINGAREA)
  450. dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
  451. if(dwFlags & DPGROUP_HIDDEN)
  452. dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
  453. // Add the group to dplay's nametable and put it in our map table
  454. hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
  455. dwDataSize, dwInternalFlags, cgig.dwGroupID, dwParentID, dwOwnerID);
  456. if(FAILED(hr))
  457. {
  458. DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
  459. // REVIEW!!!! -- We need to send a message back to the server saying
  460. // we couldn't complete the deal on our end.
  461. goto EXIT_CREATEGROUPINGROUP;
  462. }
  463. // Take the dplay lock
  464. ENTER_DPLAY();
  465. // Now build the system message (at least the parts we need)
  466. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  467. SET_MESSAGE_HDR(&msg);
  468. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
  469. msg.dwPlayerID = *lpidGroup;
  470. // Find dplay's internal group struct for the To group
  471. // Since this is local, send it to all players
  472. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  473. if(!lpGroupTo)
  474. {
  475. LEAVE_DPLAY();
  476. DPF_ERRVAL("Unable to find parent group in nametable, hr = 0x%08x", hr);
  477. goto EXIT_CREATEGROUPINGROUP;
  478. }
  479. // Call dplay's DistributeGroupMessage function to put the message
  480. // in the queues of all the appropriate players
  481. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  482. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  483. if(FAILED(hr))
  484. {
  485. DPF(2, "Failed adding CreateGroupInGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  486. }
  487. // Drop the dplay lock
  488. LEAVE_DPLAY();
  489. EXIT_CREATEGROUPINGROUP:
  490. LEAVE_DPLOBBY();
  491. return hr;
  492. } // PRV_CreateGroupInGroup
  493. #undef DPF_MODNAME
  494. #define DPF_MODNAME "PRV_DeleteGroupFromGroup"
  495. HRESULT DPLAPI PRV_DeleteGroupFromGroup(LPDPLOBBYI_DPLOBJECT this,
  496. DWORD dwParentID, DWORD dwGroupID)
  497. {
  498. SPDATA_DELETEGROUPFROMGROUP dgd;
  499. MSG_PLAYERMGMTMESSAGE msg;
  500. LPDPLAYI_GROUP lpGroupTo = NULL;
  501. HRESULT hr = DP_OK;
  502. DPF(7, "Entering DPL_DeleteGroupFromGroup");
  503. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  504. this, dwParentID, dwGroupID);
  505. ENTER_DPLOBBY();
  506. TRY
  507. {
  508. if( !VALID_DPLOBBY_PTR( this ) )
  509. {
  510. LEAVE_DPLOBBY();
  511. return DPERR_INVALIDOBJECT;
  512. }
  513. }
  514. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  515. {
  516. LEAVE_DPLOBBY();
  517. DPF_ERR( "Exception encountered validating parameters" );
  518. return DPERR_INVALIDPARAMS;
  519. }
  520. // Setup our SPDATA struct
  521. memset(&dgd, 0, sizeof(SPDATA_DELETEGROUPFROMGROUP));
  522. dgd.dwSize = sizeof(SPDATA_DELETEGROUPFROMGROUP);
  523. dgd.dwParentID = dwParentID;
  524. dgd.dwGroupID = dwGroupID;
  525. // Call the DeleteGroupFromGroup method in the SP
  526. if(CALLBACK_EXISTS(DeleteGroupFromGroup))
  527. {
  528. dgd.lpISP = PRV_GetDPLobbySPInterface(this);
  529. // Drop the lock so the lobby provider's receive thread can get back
  530. // in with other messages if they show up in the queue before our
  531. // CreatePlayer response (which always happens)
  532. LEAVE_DPLOBBY();
  533. hr = CALL_LP(this, DeleteGroupFromGroup, &dgd);
  534. ENTER_DPLOBBY();
  535. }
  536. else
  537. {
  538. // DeleteGroupFromGroup is required
  539. DPF_ERR("The Lobby Provider callback for DeleteGroupFromGroup doesn't exist -- it's required");
  540. ASSERT(FALSE);
  541. LEAVE_DPLOBBY();
  542. return DPERR_UNAVAILABLE;
  543. }
  544. // If it succeeded, send the DeleteGroupFromGroup message to all local players
  545. if(SUCCEEDED(hr))
  546. {
  547. // Take the dplay lock
  548. ENTER_DPLAY();
  549. // Get a pointer to dplay's system group
  550. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  551. if(!lpGroupTo)
  552. {
  553. LEAVE_LOBBY_ALL();
  554. DPF_ERR("Unable to find system group in nametable, not sending DeleteGroupFromGroup message");
  555. return DPERR_INVALIDGROUP;
  556. }
  557. // Now build the system message (at least the parts we need)
  558. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  559. SET_MESSAGE_HDR(&msg);
  560. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
  561. msg.dwPlayerID = dwGroupID;
  562. msg.dwGroupID = dwParentID;
  563. // Call dplay's DistributeGroupMessage function to put the message
  564. // in the queues of all the appropriate players
  565. DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  566. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  567. if(FAILED(hr))
  568. {
  569. DPF(8, "Failed adding DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  570. }
  571. // Drop the dplay lock
  572. LEAVE_DPLAY();
  573. }
  574. else
  575. {
  576. DPF_ERRVAL("Failed calling DeleteGroupFromGroup in the Lobby Provider, hr = 0x%08x", hr);
  577. }
  578. // The dplay InternalDeletePlayerFromGroup code will take care of the rest of
  579. // the internal cleanup (nametable, players, etc.), so we can just return
  580. // from here.
  581. LEAVE_DPLOBBY();
  582. return hr;
  583. } // PRV_DeleteGroupFromGroup
  584. #undef DPF_MODNAME
  585. #define DPF_MODNAME "PRV_DoSubgroupsContainLocalPlayers"
  586. BOOL PRV_DoSubgroupsContainLocalPlayers(LPDPLAYI_GROUP lpGroup,
  587. BOOL bIncludeGroup)
  588. {
  589. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  590. LPDPLAYI_SUBGROUP lpSubgroup = NULL;
  591. DPF(7, "Entering PRV_DoSubgroupsContainLocalPlayers");
  592. DPF(9, "Parameters: 0x%08x, %lu", lpGroup, bIncludeGroup);
  593. ASSERT(lpGroup);
  594. // Figure out how many local players are in this group. If it's
  595. // nonzero, just return true from this function. If the bIncludeGroup
  596. // parameter is set to FALSE, then don't look at the group passed in
  597. lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
  598. lpGroup->lpDP->pSysPlayer->dwID);
  599. if(lpGroupnode && (lpGroupnode->nPlayers > 0) && bIncludeGroup)
  600. return TRUE;
  601. // Walk the list of subgroups
  602. lpSubgroup = lpGroup->pSubgroups;
  603. while(lpSubgroup)
  604. {
  605. // We're going recursive here to do the entire heirarchy
  606. // Check out any of it's subgroups
  607. if((!(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
  608. (PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)))
  609. return TRUE;
  610. else
  611. lpSubgroup = lpSubgroup->pNextSubgroup;
  612. } // while subgroups
  613. return FALSE;
  614. } // PRV_DoSubgroupsContainLocalPlayers
  615. #undef DPF_MODNAME
  616. #define DPF_MODNAME "PRV_AreSubgroupsShortcuts"
  617. BOOL PRV_AreSubgroupsShortcuts(LPDPLAYI_GROUP lpGroup)
  618. {
  619. LPDPLAYI_SUBGROUP lpSubgroup = NULL;
  620. DPF(7, "Entering PRV_AreSubgroupsShortcuts");
  621. DPF(9, "Parameters: 0x%08x", lpGroup);
  622. ASSERT(lpGroup);
  623. // If the group is one of the following, then we want to return TRUE so
  624. // it doesn't get nuked:
  625. // 1) Root group, nGroups > 0
  626. // 2) Root group, hidden, nGroups = 0
  627. // 2) Non-root group, nGroups > 1
  628. // Otherwise, we can check it's subgroups and return FALSE as appropriate
  629. if(((lpGroup->dwIDParent == 0) && ((lpGroup->nGroups > 0) ||
  630. (!(lpGroup->dwFlags & DPLAYI_GROUP_HIDDEN)) && (lpGroup->nGroups == 0))) ||
  631. ((lpGroup->dwIDParent != 0) && (lpGroup->nGroups > 1)))
  632. return TRUE;
  633. // Walk the list of subgroups
  634. lpSubgroup = lpGroup->pSubgroups;
  635. while(lpSubgroup)
  636. {
  637. // We're going recursive here to do the entire heirarchy
  638. // Check out any of it's subgroups
  639. if(PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))
  640. return TRUE;
  641. else
  642. lpSubgroup = lpSubgroup->pNextSubgroup;
  643. } // while subgroups
  644. return FALSE;
  645. } // PRV_AreSubgroupsShortcuts
  646. #undef DPF_MODNAME
  647. #define DPF_MODNAME "PRV_DestroyGroupAndParents"
  648. void PRV_DestroyGroupAndParents(LPDPLOBBYI_DPLOBJECT this,
  649. LPDPLAYI_GROUP lpGroup, LPDPLAYI_GROUP lpStopParent)
  650. {
  651. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  652. LPDPLAYI_GROUP lpParentGroup = NULL;
  653. SPDATA_DESTROYREMOTEGROUP dg;
  654. DPID dpidParent;
  655. HRESULT hr;
  656. DPF(7, "Entering PRV_DestroyGroupAndParents");
  657. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  658. this, lpGroup, lpStopParent);
  659. ASSERT(lpGroup);
  660. // Now we need to decide if this is the last group this group was in. If
  661. // it is, then we need to destroy the group as well, and remove them from
  662. // our map table. Of course, only destroy the group if it is a remote group.
  663. // ALSO, we need to walk the heirarchy backward (up the tree) to the root
  664. // node and delete all groups that were only created to get to our shortcut.
  665. if(!(lpGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  666. {
  667. // Walk our parental heirarchy until we reach a a root group.
  668. dpidParent = lpGroup->dwIDParent;
  669. while(dpidParent)
  670. {
  671. // Get dplay's internal group structures
  672. lpParentGroup = GroupFromID(this->lpDPlayObject, dpidParent);
  673. if(!lpParentGroup)
  674. {
  675. ASSERT(FALSE);
  676. DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dpidParent);
  677. return;
  678. }
  679. // If there are any local players in the parent group, we don't want to
  680. // destroy it or any of it's subgroups (since players in the group will
  681. // be able to see subgroups)
  682. lpGroupnode = FindPlayerInGroupList(lpParentGroup->pSysPlayerGroupnodes,
  683. this->lpDPlayObject->pSysPlayer->dwID);
  684. if((lpGroupnode) && (lpGroupnode->nPlayers > 0))
  685. return;
  686. // Make sure we haven't reached our stop parent group if the caller
  687. // passed one in. This will keep us from recursively destroying
  688. // a subgroup's parent, which we might be spinning on, deleting all
  689. // of it's subgroups.
  690. if(lpStopParent && (lpStopParent == lpParentGroup))
  691. return;
  692. // Destroy the subgroups
  693. PRV_DestroySubgroups(this, lpParentGroup, TRUE);
  694. // Get the next parent
  695. dpidParent = lpParentGroup->dwIDParent;
  696. }
  697. // See if we processed any parents, or if we already have a root
  698. // group. If lpParentGroup is NULL, we have a root group, so just
  699. // stuff our group pointer in the parent group pointer
  700. if(!lpParentGroup)
  701. lpParentGroup = lpGroup;
  702. // Now see if our root group is hidden, and if it doesn't contain any
  703. // references, then we want to destroy it as well.
  704. if((!PRV_DoSubgroupsContainLocalPlayers(lpParentGroup, TRUE)) &&
  705. (!PRV_AreSubgroupsShortcuts(lpParentGroup)) &&
  706. (lpParentGroup->dwFlags & DPLAYI_GROUP_HIDDEN))
  707. {
  708. // Setup the SPDATA struct for DestroyRemoteGroup
  709. memset(&dg, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
  710. dg.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
  711. dg.dwGroupID = lpParentGroup->dwID;
  712. // Call our internal remote create
  713. hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dg);
  714. if(FAILED(hr))
  715. {
  716. DPF_ERRVAL("Failed destroying remote root group, hr = 0x%08x", hr);
  717. }
  718. }
  719. }
  720. } // PRV_DestroyGroupAndParents
  721. #undef DPF_MODNAME
  722. #define DPF_MODNAME "PRV_DestroyRemoteShortcutsForExitingPlayer"
  723. void PRV_DestroyRemoteShortcutsForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
  724. LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
  725. {
  726. SPDATA_DELETEREMOTEGROUPFROMGROUP drgd;
  727. LPDPLAYI_SUBGROUP lpSubgroup = NULL;
  728. LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
  729. HRESULT hr;
  730. DPF(7, "Entering PRV_DestroyRemoteShortcutsForExitingPlayer");
  731. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, dwGroupID);
  732. ASSERT(lpGroup);
  733. // Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
  734. memset(&drgd, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
  735. drgd.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
  736. drgd.dwParentID = dwGroupID;
  737. // Walk the list of subgroups, destroying all remote shortcuts
  738. lpSubgroup = lpGroup->pSubgroups;
  739. while(lpSubgroup)
  740. {
  741. // Save the next subgroup
  742. lpNextSubgroup = lpSubgroup->pNextSubgroup;
  743. // Make sure the group is remote and that this is really
  744. // a shortcut and not a child
  745. if(((lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
  746. (!(lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)))
  747. {
  748. // Get the subgroup's lobby ID
  749. drgd.dwGroupID = lpSubgroup->pGroup->dwID;
  750. // Call our internal DeleteGroupFromGroup routine to delete
  751. // the shortcut and send the appropriate messages
  752. // NOTE: It is imperative that we pass in a pointer to the
  753. // group who's shortcuts we are removing as the stop parent.
  754. // If we do not, we run the risk of deleting it or one of
  755. // it's children that we haven't yet looped through, which
  756. // will result in a crash as we continue to walk the
  757. // subgroup list.
  758. hr = PRV_DeleteRemoteGroupFromGroup(this, &drgd, TRUE, lpGroup);
  759. if(FAILED(hr))
  760. {
  761. DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
  762. }
  763. }
  764. // Go to the next one
  765. lpSubgroup = lpNextSubgroup;
  766. }
  767. } // PRV_DestroyRemoteShortcutsForExitingPlayer
  768. #undef DPF_MODNAME
  769. #define DPF_MODNAME "PRV_DestroyRemotePlayersForExitingPlayer"
  770. void PRV_DestroyRemotePlayersForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
  771. LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
  772. {
  773. SPDATA_DELETEREMOTEPLAYERFROMGROUP drpd;
  774. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  775. LPDPLAYI_GROUPNODE lpNextGroupnode = NULL;
  776. HRESULT hr;
  777. DPF(7, "Entering PRV_DestroyRemotePlayersForExitingPlayer");
  778. DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
  779. ASSERT(lpGroup);
  780. // Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
  781. memset(&drpd, 0, sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP));
  782. drpd.dwSize = sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP);
  783. drpd.dwGroupID = dwGroupID;
  784. // Walk the list of groupnodes, deleting remote players that are not in
  785. // any other groups
  786. lpGroupnode = lpGroup->pGroupnodes;
  787. while(lpGroupnode)
  788. {
  789. // Save our next groupnode pointer since our current groupnode
  790. // will be gone when we come back from the delete
  791. lpNextGroupnode = lpGroupnode->pNextGroupnode;
  792. // Delete the player from the group if it's remote and then
  793. // destroy the player if he is in no other groups
  794. if (!(lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  795. {
  796. // Get the remote player's ID
  797. drpd.dwPlayerID = lpGroupnode->pPlayer->dwID;
  798. // Delete the player from the group
  799. hr = PRV_DeleteRemotePlayerFromGroup(this, &drpd, TRUE);
  800. if(FAILED(hr))
  801. {
  802. DPF_ERRVAL("Failed deleting remote player from group, hr = 0x%08x", hr);
  803. }
  804. }
  805. lpGroupnode = lpNextGroupnode;
  806. } // while
  807. } // PRV_DestroyRemotePlayersForExitingPlayer
  808. #undef DPF_MODNAME
  809. #define DPF_MODNAME "PRV_DestroySubgroups"
  810. void PRV_DestroySubgroups(LPDPLOBBYI_DPLOBJECT this, LPDPLAYI_GROUP lpGroup,
  811. BOOL bRemoteOnly)
  812. {
  813. LPDPLAYI_SUBGROUP lpSubgroup = NULL;
  814. LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
  815. SPDATA_DESTROYREMOTEGROUP dgd;
  816. SPDATA_DELETEREMOTEGROUPFROMGROUP drg;
  817. HRESULT hr;
  818. DPF(7, "Entering PRV_DestroySubgroups");
  819. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, bRemoteOnly);
  820. ASSERT(lpGroup);
  821. // Setup the static part of the SPDATA structures
  822. memset(&dgd, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
  823. dgd.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
  824. memset(&drg, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
  825. drg.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
  826. drg.dwParentID = lpGroup->dwID;
  827. // Walk the list of subgroups
  828. lpSubgroup = lpGroup->pSubgroups;
  829. while(lpSubgroup)
  830. {
  831. // Save the next subgroup
  832. lpNextSubgroup = lpSubgroup->pNextSubgroup;
  833. // Make sure it's a remote group if the flag is set
  834. if((bRemoteOnly) &&
  835. (lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  836. {
  837. lpSubgroup = lpNextSubgroup;
  838. continue;
  839. }
  840. // If the subgroup doesn't contain any local players,
  841. // nor do any of it's subgroups, then destroy it
  842. if((!bRemoteOnly) ||
  843. ((!PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)) &&
  844. (!PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))))
  845. {
  846. // If the group is a shortcut, just delete the link. If it's a child,
  847. // destroy the subgroup.
  848. if(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)
  849. {
  850. // Finish setting up the SPDATA structure
  851. drg.dwGroupID = lpSubgroup->pGroup->dwID;
  852. // Destroy the subgroup
  853. hr = DPLP_DeleteGroupFromGroup((LPDPLOBBYSP)this->lpInterfaces, &drg);
  854. if(FAILED(hr))
  855. {
  856. DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
  857. }
  858. }
  859. else
  860. {
  861. // Finish setting up the SPDATA structure
  862. dgd.dwGroupID = lpSubgroup->pGroup->dwID;
  863. // Destroy the subgroup
  864. hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dgd);
  865. if(FAILED(hr))
  866. {
  867. DPF_ERRVAL("Failed destroying remote group, hr = 0x%08x", hr);
  868. }
  869. }
  870. }
  871. lpSubgroup = lpNextSubgroup;
  872. } // while lpSubgroups
  873. } // PRV_DestroySubgroups
  874. #undef DPF_MODNAME
  875. #define DPF_MODNAME "PRV_DeletePlayerFromGroup"
  876. HRESULT DPLAPI PRV_DeletePlayerFromGroup(LPDPLOBBYI_DPLOBJECT this,
  877. DWORD dwGroupID, DWORD dwPlayerID)
  878. {
  879. SPDATA_DELETEPLAYERFROMGROUP dpd;
  880. MSG_PLAYERMGMTMESSAGE msg;
  881. LPDPLAYI_PLAYER lpPlayer = NULL;
  882. LPDPLAYI_GROUP lpGroup =NULL;
  883. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  884. HRESULT hr = DP_OK;
  885. DPF(7, "Entering PRV_DeletePlayerFromGroup");
  886. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  887. this, dwGroupID, dwPlayerID);
  888. ENTER_DPLOBBY();
  889. TRY
  890. {
  891. if( !VALID_DPLOBBY_PTR( this ) )
  892. {
  893. LEAVE_DPLOBBY();
  894. return DPERR_INVALIDOBJECT;
  895. }
  896. }
  897. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  898. {
  899. LEAVE_DPLOBBY();
  900. DPF_ERR( "Exception encountered validating parameters" );
  901. return DPERR_INVALIDPARAMS;
  902. }
  903. // Take the dplay lock since we'll be looking at a dplay internal struct
  904. ENTER_DPLAY();
  905. // Make sure the player is a local player, otherwise return AccessDenied
  906. lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
  907. if(!lpPlayer)
  908. {
  909. DPF_ERR("Unable to find player in nametable");
  910. hr = DPERR_INVALIDGROUP;
  911. goto EXIT_DELETEPLAYERFROMGROUP;
  912. }
  913. if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  914. {
  915. DPF_ERR("Cannot delete a remote player from a group");
  916. hr = DPERR_INVALIDPLAYER;
  917. goto EXIT_DELETEPLAYERFROMGROUP;
  918. }
  919. // Drop the dplay lock since we're done
  920. LEAVE_DPLAY();
  921. // Setup our SPDATA struct
  922. memset(&dpd, 0, sizeof(SPDATA_DELETEPLAYERFROMGROUP));
  923. dpd.dwSize = sizeof(SPDATA_DELETEPLAYERFROMGROUP);
  924. dpd.dwGroupID = dwGroupID;
  925. dpd.dwPlayerID = dwPlayerID;
  926. // Call the DeletePlayerFromGroup method in the SP
  927. if(CALLBACK_EXISTS(DeletePlayerFromGroup))
  928. {
  929. dpd.lpISP = PRV_GetDPLobbySPInterface(this);
  930. // Drop the lock so the lobby provider's receive thread can get back
  931. // in with other messages if they show up in the queue before our
  932. // CreatePlayer response (which always happens)
  933. LEAVE_DPLOBBY();
  934. hr = CALL_LP(this, DeletePlayerFromGroup, &dpd);
  935. ENTER_DPLOBBY();
  936. }
  937. else
  938. {
  939. // DeletePlayerFromGroup is required
  940. DPF_ERR("The Lobby Provider callback for DeletePlayerFromGroup doesn't exist -- it's required");
  941. ASSERT(FALSE);
  942. LEAVE_DPLOBBY();
  943. return DPERR_UNAVAILABLE;
  944. }
  945. if(FAILED(hr))
  946. {
  947. DPF_ERRVAL("Failed calling DeletePlayerFromGroup in the Lobby Provider, hr = 0x%08x", hr);
  948. LEAVE_DPLOBBY();
  949. return hr;
  950. }
  951. // Take the dplay lock
  952. ENTER_DPLAY();
  953. // We need to remove all other players in the group and send the appropriate
  954. // message to the player we are about to delete because he won't see the
  955. // system messages for them once he leaves the group. However, if any other
  956. // local players are in the group, we don't want to remove the remote players
  957. // from the nametable because the other local players need to see them.
  958. // Get a pointer to dplay's internal group structure
  959. lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
  960. if(!lpGroup)
  961. {
  962. DPF_ERRVAL("Unable to find group in nametable, idGroup = %lu", dwGroupID);
  963. hr = DPERR_INVALIDGROUP;
  964. goto EXIT_DELETEPLAYERFROMGROUP;
  965. }
  966. // Get a pointer to dplay's internal player structure
  967. lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
  968. if(!lpPlayer)
  969. {
  970. DPF_ERRVAL("Unable to find player in nametable, hr = 0x%08x", hr);
  971. hr = DPERR_INVALIDPLAYER;
  972. goto EXIT_DELETEPLAYERFROMGROUP;
  973. }
  974. // We need to send a DeletePlayerFromGroup message to the player who
  975. // was deleted since he won't get the group message once he's gone
  976. // Now build the system message (at least the parts we need)
  977. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  978. SET_MESSAGE_HDR(&msg);
  979. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEPLAYERFROMGROUP);
  980. msg.dwPlayerID = dwPlayerID;
  981. msg.dwGroupID = dwGroupID;
  982. // Call dplay's handleplayermessage function to put the message in the queue
  983. hr = HandlePlayerMessage(lpPlayer, (LPBYTE)&msg,
  984. sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  985. if(FAILED(hr))
  986. {
  987. DPF_ERRVAL("Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
  988. // Set the hresult back to DP_OK since only the message failed
  989. hr = DP_OK;
  990. }
  991. // Figure out how many local players are in this group. If it's only 1,
  992. // then delete all the remote players.
  993. lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
  994. this->lpDPlayObject->pSysPlayer->dwID);
  995. if((!lpGroupnode) || (lpGroupnode->nPlayers == 0))
  996. {
  997. // Destroy all remote players that are only in this group
  998. PRV_DestroyRemotePlayersForExitingPlayer(this, lpGroup, dwGroupID);
  999. // Destroy all the remote shortcut groups, making sure we are
  1000. // not in them, and removing their entire parental heirarchy
  1001. PRV_DestroyRemoteShortcutsForExitingPlayer(this, lpGroup, dwGroupID);
  1002. // Destroy all remote subgroups of this group, making sure we're
  1003. // not in them for some reason
  1004. PRV_DestroySubgroups(this, lpGroup, TRUE);
  1005. // Destroy the group we're leaving if it is remote as well as it's
  1006. // parental chain.
  1007. PRV_DestroyGroupAndParents(this, lpGroup, NULL);
  1008. }
  1009. EXIT_DELETEPLAYERFROMGROUP:
  1010. // The dplay InternalDeletePlayerFromGroup code will take care of the rest of
  1011. // the internal cleanup (nametable, players, etc.), so we can just return
  1012. // from here.
  1013. LEAVE_LOBBY_ALL();
  1014. return hr;
  1015. } // PRV_DeletePlayerFromGroup
  1016. #undef DPF_MODNAME
  1017. #define DPF_MODNAME "PRV_DestroyGroup"
  1018. HRESULT DPLAPI PRV_DestroyGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
  1019. {
  1020. SPDATA_DESTROYGROUP dg;
  1021. LPDPLAYI_GROUP lpGroup = NULL;
  1022. HRESULT hr = DP_OK;
  1023. DPF(7, "Entering PRV_DestroyGroup");
  1024. DPF(9, "Parameters: 0x%08x, 0x%08x", this, dwLobbyID);
  1025. ENTER_DPLOBBY();
  1026. TRY
  1027. {
  1028. if( !VALID_DPLOBBY_PTR( this ) )
  1029. {
  1030. LEAVE_DPLOBBY();
  1031. return DPERR_INVALIDOBJECT;
  1032. }
  1033. }
  1034. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1035. {
  1036. LEAVE_DPLOBBY();
  1037. DPF_ERR( "Exception encountered validating parameters" );
  1038. return DPERR_INVALIDPARAMS;
  1039. }
  1040. // Setup our SPDATA struct
  1041. memset(&dg, 0, sizeof(SPDATA_DESTROYGROUP));
  1042. dg.dwSize = sizeof(SPDATA_DESTROYGROUP);
  1043. dg.dwGroupID = dwLobbyID;
  1044. // Call the DestroyGroup method in the SP
  1045. if(CALLBACK_EXISTS(DestroyGroup))
  1046. {
  1047. dg.lpISP = PRV_GetDPLobbySPInterface(this);
  1048. // Drop the lock so the lobby provider's receive thread can get back
  1049. // in with other messages if they show up in the queue before our
  1050. // CreatePlayer response (which always happens)
  1051. LEAVE_DPLOBBY();
  1052. hr = CALL_LP(this, DestroyGroup, &dg);
  1053. ENTER_DPLOBBY();
  1054. }
  1055. else
  1056. {
  1057. // DestroyGroup is required
  1058. DPF_ERR("The Lobby Provider callback for DestroyGroup doesn't exist -- it's required");
  1059. ASSERT(FALSE);
  1060. LEAVE_DPLOBBY();
  1061. return DPERR_UNAVAILABLE;
  1062. }
  1063. if(FAILED(hr))
  1064. {
  1065. DPF_ERRVAL("Failed calling DestroyGroup in the Lobby Provider, hr = 0x%08x", hr);
  1066. LEAVE_DPLOBBY();
  1067. return hr;
  1068. }
  1069. // Take the lock
  1070. ENTER_DPLAY();
  1071. // So, get dplay's internal group structure
  1072. lpGroup = GroupFromID(this->lpDPlayObject, dwLobbyID);
  1073. if(!lpGroup)
  1074. {
  1075. // This shouldn't ever happen. If the groups isn't in the nametable,
  1076. // we should never get this far.
  1077. ASSERT(FALSE);
  1078. LEAVE_LOBBY_ALL();
  1079. DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dwLobbyID);
  1080. return DPERR_INVALIDGROUP;
  1081. }
  1082. // Send messages to remove shortcuts to this group (since dplay won't
  1083. // do it for us)
  1084. PRV_SendDeleteShortcutMessageForExitingGroup(this, lpGroup);
  1085. // Destroy all the subgroups and remote players
  1086. PRV_RemoveSubgroupsAndPlayersFromGroup(this, lpGroup, dwLobbyID, FALSE);
  1087. // Drop the dplay lock since we're done mucking around with it's structures
  1088. LEAVE_DPLAY();
  1089. // Broadcast the DestroyGroup message
  1090. hr = PRV_BroadcastDestroyGroupMessage(this, dwLobbyID);
  1091. if(FAILED(hr))
  1092. {
  1093. DPF_ERRVAL("Failed to send DestroyGroup message to local players, hr = 0x%08x", hr);
  1094. }
  1095. // The dplay InternalDestroyGroup code will take care of the rest of
  1096. // the internal cleanup (nametable, players, etc.), so we can just return
  1097. // from here.
  1098. LEAVE_DPLOBBY();
  1099. return hr;
  1100. } // PRV_DestroyGroup
  1101. #undef DPF_MODNAME
  1102. #define DPF_MODNAME "PRV_GetGroupConnectionSettings"
  1103. HRESULT PRV_GetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
  1104. DWORD dwGroupID, LPVOID lpData, LPDWORD lpdwSize)
  1105. {
  1106. SPDATA_GETGROUPCONNECTIONSETTINGS gcs;
  1107. LPDPLOBBYI_DPLOBJECT this = NULL;
  1108. LPDPLAYI_DPLAY lpDPObject = NULL;
  1109. LPDPLAYI_GROUP lpGroup = NULL;
  1110. HRESULT hr = DP_OK;
  1111. DPF(7, "Entering PRV_GetGroupConnectionSettings");
  1112. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
  1113. lpDP, dwFlags, dwGroupID, lpData, lpdwSize);
  1114. TRY
  1115. {
  1116. lpDPObject = DPLAY_FROM_INT(lpDP);
  1117. hr = VALID_DPLAY_PTR( lpDPObject );
  1118. if (FAILED(hr))
  1119. {
  1120. DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
  1121. return hr;
  1122. }
  1123. if(!IS_LOBBY_OWNED(lpDPObject))
  1124. {
  1125. DPF_ERR("GetGroupConnectionSettings is only supported for lobby connections");
  1126. return DPERR_UNSUPPORTED;
  1127. }
  1128. this = lpDPObject->lpLobbyObject;
  1129. if(!VALID_DPLOBBY_PTR(this))
  1130. {
  1131. DPF_ERR("Bad DPLobby object");
  1132. return DPERR_INVALIDOBJECT;
  1133. }
  1134. lpGroup = GroupFromID(lpDPObject, dwGroupID);
  1135. if (!VALID_DPLAY_GROUP(lpGroup))
  1136. {
  1137. DPF_ERR("Invalid group id");
  1138. return DPERR_INVALIDGROUP;
  1139. }
  1140. if( !VALID_DWORD_PTR( lpdwSize ) )
  1141. {
  1142. DPF_ERR("lpdwSize was not a valid dword pointer!");
  1143. return DPERR_INVALIDPARAMS;
  1144. }
  1145. if(lpData)
  1146. {
  1147. if( !VALID_WRITE_PTR(lpData, *lpdwSize) )
  1148. {
  1149. DPF_ERR("lpData is not a valid output buffer of the size specified in *lpdwSize");
  1150. return DPERR_INVALIDPARAMS;
  1151. }
  1152. }
  1153. // We haven't defined any flags for this release
  1154. if( (dwFlags) )
  1155. {
  1156. return DPERR_INVALIDFLAGS;
  1157. }
  1158. }
  1159. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1160. {
  1161. DPF_ERR( "Exception encountered validating parameters" );
  1162. return DPERR_INVALIDPARAMS;
  1163. }
  1164. // Setup our SPDATA struct
  1165. memset(&gcs, 0, sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS));
  1166. gcs.dwSize = sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS);
  1167. gcs.dwFlags = dwFlags;
  1168. gcs.dwGroupID = dwGroupID;
  1169. gcs.lpdwBufferSize = lpdwSize;
  1170. gcs.lpBuffer = lpData;
  1171. // Call the GetGroupConnectionSettings method in the SP
  1172. if(CALLBACK_EXISTS(GetGroupConnectionSettings))
  1173. {
  1174. gcs.lpISP = PRV_GetDPLobbySPInterface(this);
  1175. // Drop the dplay lock since we are going to send a guaranteed message
  1176. LEAVE_LOBBY_ALL();
  1177. hr = CALL_LP(this, GetGroupConnectionSettings, &gcs);
  1178. // Take the lock back
  1179. ENTER_LOBBY_ALL();
  1180. }
  1181. else
  1182. {
  1183. // GetGroupConnectionSettings is required
  1184. DPF_ERR("The Lobby Provider callback for GetGroupConnectionSettings doesn't exist -- it's required");
  1185. ASSERT(FALSE);
  1186. return DPERR_UNAVAILABLE;
  1187. }
  1188. if(FAILED(hr) && (hr != DPERR_BUFFERTOOSMALL))
  1189. {
  1190. DPF_ERRVAL("Failed calling GetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
  1191. }
  1192. return hr;
  1193. } // PRV_GetGroupConnectionSettings
  1194. #undef DPF_MODNAME
  1195. #define DPF_MODNAME "DPL_GetGroupConnectionSettings"
  1196. HRESULT DPLAPI DPL_GetGroupConnectionSettings(LPDIRECTPLAY lpDP,
  1197. DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwSize)
  1198. {
  1199. HRESULT hr;
  1200. DPF(7, "Entering DPL_GetGroupConnectionSettings");
  1201. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
  1202. lpDP, dwFlags, idGroup, lpData, lpdwSize);
  1203. ENTER_LOBBY_ALL();
  1204. // Set the ANSI flag to TRUE and call the internal function
  1205. hr = PRV_GetGroupConnectionSettings(lpDP, dwFlags, idGroup,
  1206. lpData, lpdwSize);
  1207. LEAVE_LOBBY_ALL();
  1208. return hr;
  1209. } // DPL_GetGroupConnectionSettings
  1210. #undef DPF_MODNAME
  1211. #define DPF_MODNAME "PRV_GetGroupData"
  1212. HRESULT DPLAPI PRV_GetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
  1213. LPVOID lpData, LPDWORD lpdwDataSize)
  1214. {
  1215. SPDATA_GETGROUPDATA ggd;
  1216. HRESULT hr = DP_OK;
  1217. DPF(7, "Entering DPL_GetGroupData");
  1218. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
  1219. this, dwGroupID, lpData, lpdwDataSize);
  1220. ENTER_DPLOBBY();
  1221. TRY
  1222. {
  1223. if( !VALID_DPLOBBY_PTR( this ) )
  1224. {
  1225. LEAVE_DPLOBBY();
  1226. return DPERR_INVALIDOBJECT;
  1227. }
  1228. }
  1229. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1230. {
  1231. LEAVE_DPLOBBY();
  1232. DPF_ERR( "Exception encountered validating parameters" );
  1233. return DPERR_INVALIDPARAMS;
  1234. }
  1235. // Setup our SPDATA struct
  1236. memset(&ggd, 0, sizeof(SPDATA_GETGROUPDATA));
  1237. ggd.dwSize = sizeof(SPDATA_GETGROUPDATA);
  1238. ggd.dwGroupID = dwGroupID;
  1239. ggd.lpdwDataSize = lpdwDataSize;
  1240. ggd.lpData = lpData;
  1241. // Call the GetGroupData method in the SP
  1242. if(CALLBACK_EXISTS(GetGroupData))
  1243. {
  1244. ggd.lpISP = PRV_GetDPLobbySPInterface(this);
  1245. // Drop the lock so the lobby provider's receive thread can get back
  1246. // in with other messages if they show up in the queue before our
  1247. // CreatePlayer response (which always happens)
  1248. LEAVE_DPLOBBY();
  1249. hr = CALL_LP(this, GetGroupData, &ggd);
  1250. ENTER_DPLOBBY();
  1251. }
  1252. else
  1253. {
  1254. // GetGroupData is required
  1255. DPF_ERR("The Lobby Provider callback for GetGroupData doesn't exist -- it's required");
  1256. ASSERT(FALSE);
  1257. LEAVE_DPLOBBY();
  1258. return DPERR_UNAVAILABLE;
  1259. }
  1260. if(FAILED(hr))
  1261. {
  1262. DPF_ERRVAL("Failed calling GetGroupData in the Lobby Provider, hr = 0x%08x", hr);
  1263. }
  1264. LEAVE_DPLOBBY();
  1265. return hr;
  1266. } // PRV_GetGroupData
  1267. #undef DPF_MODNAME
  1268. #define DPF_MODNAME "DPL_GetGroupOwner"
  1269. HRESULT DPAPI DPL_GetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
  1270. LPDPID lpidOwner)
  1271. {
  1272. LPDPLAYI_DPLAY this;
  1273. LPDPLAYI_GROUP lpGroup = NULL;
  1274. HRESULT hr;
  1275. DPF(7, "Entering DPL_GetGroupOwner");
  1276. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  1277. lpDP, dwGroupID, lpidOwner);
  1278. ENTER_DPLAY();
  1279. TRY
  1280. {
  1281. this = DPLAY_FROM_INT(lpDP);
  1282. hr = VALID_DPLAY_PTR( this );
  1283. if (FAILED(hr))
  1284. {
  1285. LEAVE_DPLAY();
  1286. DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
  1287. return hr;
  1288. }
  1289. lpGroup = GroupFromID(this, dwGroupID);
  1290. if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
  1291. {
  1292. LEAVE_DPLAY();
  1293. DPF_ERR("Invalid group id");
  1294. return DPERR_INVALIDGROUP;
  1295. }
  1296. if (!VALID_DWORD_PTR(lpidOwner))
  1297. {
  1298. LEAVE_DPLAY();
  1299. DPF_ERR("Invalid owner id pointer");
  1300. return DPERR_INVALIDPARAMS;
  1301. }
  1302. }
  1303. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1304. {
  1305. LEAVE_DPLAY();
  1306. DPF_ERR( "Exception encountered validating parameters" );
  1307. return DPERR_INVALIDPARAMS;
  1308. }
  1309. // This method is only valid in lobby session
  1310. if(IS_LOBBY_OWNED(this))
  1311. {
  1312. *lpidOwner = lpGroup->dwOwnerID;
  1313. }
  1314. else
  1315. {
  1316. DPF_ERR("GetGroupOwner is only supported for lobby sessions");
  1317. hr = DPERR_UNSUPPORTED;
  1318. }
  1319. LEAVE_DPLAY();
  1320. return hr;
  1321. } // DPL_GetGroupOwner
  1322. #undef DPF_MODNAME
  1323. #define DPF_MODNAME "PRV_SetGroupConnectionSettings"
  1324. HRESULT PRV_SetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
  1325. DWORD dwGroupID, LPDPLCONNECTION lpConn, BOOL bAnsi)
  1326. {
  1327. SPDATA_SETGROUPCONNECTIONSETTINGS scs;
  1328. LPDPLOBBYI_DPLOBJECT this = NULL;
  1329. LPDPLAYI_DPLAY lpDPObject = NULL;
  1330. LPDPLAYI_GROUP lpGroup = NULL;
  1331. HRESULT hr = DP_OK;
  1332. DPF(7, "Entering PRV_SetGroupConnectionSettings");
  1333. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu",
  1334. lpDP, dwFlags, dwGroupID, lpConn, bAnsi);
  1335. TRY
  1336. {
  1337. lpDPObject = DPLAY_FROM_INT(lpDP);
  1338. hr = VALID_DPLAY_PTR( lpDPObject );
  1339. if (FAILED(hr))
  1340. {
  1341. DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
  1342. return hr;
  1343. }
  1344. if(!IS_LOBBY_OWNED(lpDPObject))
  1345. {
  1346. DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
  1347. return DPERR_UNSUPPORTED;
  1348. }
  1349. this = lpDPObject->lpLobbyObject;
  1350. if(!VALID_DPLOBBY_PTR(this))
  1351. {
  1352. DPF_ERR("Bad DPLobby object");
  1353. return DPERR_INVALIDOBJECT;
  1354. }
  1355. lpGroup = GroupFromID(lpDPObject, dwGroupID);
  1356. if (!VALID_DPLAY_GROUP(lpGroup))
  1357. {
  1358. DPF_ERR("Invalid group id");
  1359. return DPERR_INVALIDGROUP;
  1360. }
  1361. hr = PRV_ValidateDPLCONNECTION(lpConn, FALSE);
  1362. if(FAILED(hr))
  1363. {
  1364. DPF_ERR("Invalid DPLCONNECTION structure");
  1365. return hr;
  1366. }
  1367. // We haven't defined any flags for this release
  1368. if( (dwFlags) )
  1369. {
  1370. return DPERR_INVALIDFLAGS;
  1371. }
  1372. }
  1373. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1374. {
  1375. DPF_ERR( "Exception encountered validating parameters" );
  1376. return DPERR_INVALIDPARAMS;
  1377. }
  1378. // Setup our SPDATA struct
  1379. memset(&scs, 0, sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS));
  1380. scs.dwSize = sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS);
  1381. scs.dwFlags = dwFlags;
  1382. scs.dwGroupID = dwGroupID;
  1383. scs.lpConn = lpConn;
  1384. // Ensure that the guidInstance in the DPLCONNECTION structure is NULL
  1385. lpConn->lpSessionDesc->guidInstance = GUID_NULL;
  1386. // Call the SetGroupConnectionSettings method in the SP
  1387. if(CALLBACK_EXISTS(SetGroupConnectionSettings))
  1388. {
  1389. scs.lpISP = PRV_GetDPLobbySPInterface(this);
  1390. // Drop the dplay lock since we're sending a guaranteed message
  1391. LEAVE_LOBBY_ALL();
  1392. hr = CALL_LP(this, SetGroupConnectionSettings, &scs);
  1393. // Take the lock back
  1394. ENTER_LOBBY_ALL();
  1395. }
  1396. else
  1397. {
  1398. // SetGroupConnectionSettings is required
  1399. DPF_ERR("The Lobby Provider callback for SetGroupConnectionSettings doesn't exist -- it's required");
  1400. ASSERT(FALSE);
  1401. return DPERR_UNAVAILABLE;
  1402. }
  1403. if(FAILED(hr))
  1404. {
  1405. DPF_ERRVAL("Failed calling SetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
  1406. }
  1407. return hr;
  1408. } // PRV_SetGroupConnectionSettings
  1409. #undef DPF_MODNAME
  1410. #define DPF_MODNAME "DPL_SetGroupConnectionSettings"
  1411. HRESULT DPLAPI DPL_SetGroupConnectionSettings(LPDIRECTPLAY lpDP,
  1412. DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConn)
  1413. {
  1414. HRESULT hr;
  1415. DPF(7, "Entering DPL_SetGroupConnectionSettings");
  1416. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
  1417. lpDP, dwFlags, idGroup, lpConn);
  1418. ENTER_LOBBY_ALL();
  1419. // Set the ANSI flag to TRUE and call the internal function
  1420. hr = PRV_SetGroupConnectionSettings(lpDP, dwFlags, idGroup, lpConn, FALSE);
  1421. LEAVE_LOBBY_ALL();
  1422. return hr;
  1423. } // DPL_SetGroupConnectionSettings
  1424. #undef DPF_MODNAME
  1425. #define DPF_MODNAME "PRV_SetGroupData"
  1426. HRESULT DPLAPI PRV_SetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
  1427. LPVOID lpData, DWORD dwDataSize, DWORD dwFlags)
  1428. {
  1429. SPDATA_SETGROUPDATA sgd;
  1430. HRESULT hr = DP_OK;
  1431. DPF(7, "Entering DPL_SetGroupData");
  1432. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu, 0x%08x",
  1433. this, dwGroupID, lpData, dwDataSize, dwFlags);
  1434. ENTER_DPLOBBY();
  1435. TRY
  1436. {
  1437. if( !VALID_DPLOBBY_PTR( this ) )
  1438. {
  1439. LEAVE_DPLAY();
  1440. return DPERR_INVALIDOBJECT;
  1441. }
  1442. }
  1443. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1444. {
  1445. LEAVE_DPLAY();
  1446. DPF_ERR( "Exception encountered validating parameters" );
  1447. return DPERR_INVALIDPARAMS;
  1448. }
  1449. // Setup our SPDATA struct
  1450. memset(&sgd, 0, sizeof(SPDATA_SETGROUPDATA));
  1451. sgd.dwSize = sizeof(SPDATA_SETGROUPDATA);
  1452. sgd.dwGroupID = dwGroupID;
  1453. sgd.dwDataSize = dwDataSize;
  1454. sgd.lpData = lpData;
  1455. sgd.dwFlags = dwFlags;
  1456. // Call the SetGroupData method in the SP
  1457. if(CALLBACK_EXISTS(SetGroupData))
  1458. {
  1459. sgd.lpISP = PRV_GetDPLobbySPInterface(this);
  1460. // Drop the lock so the lobby provider's receive thread can get back
  1461. // in with other messages if they show up in the queue before our
  1462. // CreatePlayer response (which always happens)
  1463. LEAVE_DPLOBBY();
  1464. hr = CALL_LP(this, SetGroupData, &sgd);
  1465. ENTER_DPLOBBY();
  1466. }
  1467. else
  1468. {
  1469. // SetGroupData is required
  1470. DPF_ERR("The Lobby Provider callback for SetGroupData doesn't exist -- it's required");
  1471. ASSERT(FALSE);
  1472. hr = DPERR_UNAVAILABLE;
  1473. goto EXIT_SETGROUPDATA;
  1474. }
  1475. // If it succeeded, send the SetGroupData message to our local players
  1476. if(SUCCEEDED(hr))
  1477. {
  1478. hr = PRV_SendDataChangedMessageLocally(this, dwGroupID, lpData, dwDataSize);
  1479. }
  1480. else
  1481. {
  1482. DPF_ERRVAL("Failed calling SetGroupData in the Lobby Provider, hr = 0x%08x", hr);
  1483. }
  1484. EXIT_SETGROUPDATA:
  1485. LEAVE_DPLOBBY();
  1486. return hr;
  1487. } // PRV_SetGroupData
  1488. #undef DPF_MODNAME
  1489. #define DPF_MODNAME "PRV_SetGroupName"
  1490. HRESULT DPLAPI PRV_SetGroupName(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
  1491. LPDPNAME lpName, DWORD dwFlags)
  1492. {
  1493. SPDATA_SETGROUPNAME sgn;
  1494. HRESULT hr = DP_OK;
  1495. DPF(7, "Entering DPL_SetGroupName");
  1496. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
  1497. this, dwGroupID, lpName, dwFlags);
  1498. ENTER_DPLOBBY();
  1499. TRY
  1500. {
  1501. if( !VALID_DPLOBBY_PTR( this ) )
  1502. {
  1503. LEAVE_DPLAY();
  1504. return DPERR_INVALIDOBJECT;
  1505. }
  1506. }
  1507. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1508. {
  1509. LEAVE_DPLAY();
  1510. DPF_ERR( "Exception encountered validating parameters" );
  1511. return DPERR_INVALIDPARAMS;
  1512. }
  1513. // Setup our SPDATA struct
  1514. memset(&sgn, 0, sizeof(SPDATA_SETGROUPNAME));
  1515. sgn.dwSize = sizeof(SPDATA_SETGROUPNAME);
  1516. sgn.dwGroupID = dwGroupID;
  1517. sgn.lpName = lpName;
  1518. sgn.dwFlags = dwFlags;
  1519. // Call the SetGroupName method in the SP
  1520. if(CALLBACK_EXISTS(SetGroupName))
  1521. {
  1522. sgn.lpISP = PRV_GetDPLobbySPInterface(this);
  1523. // Drop the lock so the lobby provider's receive thread can get back
  1524. // in with other messages if they show up in the queue before our
  1525. // CreatePlayer response (which always happens)
  1526. LEAVE_DPLOBBY();
  1527. hr = CALL_LP(this, SetGroupName, &sgn);
  1528. ENTER_DPLOBBY();
  1529. }
  1530. else
  1531. {
  1532. // SetGroupName is required
  1533. DPF_ERR("The Lobby Provider callback for SetGroupName doesn't exist -- it's required");
  1534. ASSERT(FALSE);
  1535. hr = DPERR_UNAVAILABLE;
  1536. goto EXIT_SETGROUPNAME;
  1537. }
  1538. // If it succeeded, send the SetGroupName message to our local players
  1539. if(SUCCEEDED(hr))
  1540. {
  1541. hr = PRV_SendNameChangedMessageLocally(this, dwGroupID, lpName, FALSE);
  1542. }
  1543. else
  1544. {
  1545. DPF_ERRVAL("Failed calling SetGroupName in the Lobby Provider, hr = 0x%08x", hr);
  1546. }
  1547. EXIT_SETGROUPNAME:
  1548. LEAVE_DPLOBBY();
  1549. return hr;
  1550. } // PRV_SetGroupName
  1551. #undef DPF_MODNAME
  1552. #define DPF_MODNAME "DPL_SetGroupOwner"
  1553. HRESULT DPLAPI DPL_SetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
  1554. DWORD dwOwnerID)
  1555. {
  1556. LPDPLOBBYI_DPLOBJECT this;
  1557. LPDPLAYI_DPLAY lpDPlayObject;
  1558. SPDATA_SETGROUPOWNER sgo;
  1559. LPDPLAYI_PLAYER lpNewOwner = NULL;
  1560. LPDPLAYI_GROUP lpGroup = NULL;
  1561. HRESULT hr = DP_OK;
  1562. DWORD dwOldOwnerID;
  1563. DPF(7, "Entering DPL_SetGroupOwner");
  1564. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  1565. lpDP, dwGroupID, dwOwnerID);
  1566. ENTER_LOBBY_ALL();
  1567. TRY
  1568. {
  1569. lpDPlayObject = DPLAY_FROM_INT(lpDP);
  1570. hr = VALID_DPLAY_PTR( lpDPlayObject );
  1571. if (FAILED(hr))
  1572. {
  1573. LEAVE_LOBBY_ALL();
  1574. DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
  1575. return hr;
  1576. }
  1577. this = lpDPlayObject->lpLobbyObject;
  1578. if( !VALID_DPLOBBY_PTR( this ) )
  1579. {
  1580. LEAVE_LOBBY_ALL();
  1581. return DPERR_INVALIDOBJECT;
  1582. }
  1583. lpGroup = GroupFromID(lpDPlayObject, dwGroupID);
  1584. if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
  1585. {
  1586. LEAVE_LOBBY_ALL();
  1587. DPF_ERR("Invalid group id");
  1588. return DPERR_INVALIDGROUP;
  1589. }
  1590. // DPID_SERVERPLAYER is valid here
  1591. if(dwOwnerID != DPID_SERVERPLAYER)
  1592. {
  1593. lpNewOwner = PlayerFromID(lpDPlayObject, dwOwnerID);
  1594. if (!VALID_DPLAY_PLAYER(lpNewOwner))
  1595. {
  1596. LEAVE_LOBBY_ALL();
  1597. DPF_ERR("Invalid new owner player id");
  1598. return DPERR_INVALIDPLAYER;
  1599. }
  1600. }
  1601. }
  1602. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1603. {
  1604. LEAVE_LOBBY_ALL();
  1605. DPF_ERR( "Exception encountered validating parameters" );
  1606. return DPERR_INVALIDPARAMS;
  1607. }
  1608. // do the send
  1609. if(!IS_LOBBY_OWNED(lpDPlayObject))
  1610. {
  1611. DPF_ERR("SetGroupOwner is only supported for lobby sessions");
  1612. hr = DPERR_UNSUPPORTED;
  1613. goto EXIT_SETGROUPOWNER;
  1614. }
  1615. // Setup our SPDATA struct
  1616. memset(&sgo, 0, sizeof(SPDATA_SETGROUPOWNER));
  1617. sgo.dwSize = sizeof(SPDATA_SETGROUPOWNER);
  1618. sgo.dwGroupID = dwGroupID;
  1619. sgo.dwOwnerID = dwOwnerID;
  1620. // Call the SetGroupOwner method in the SP
  1621. if(CALLBACK_EXISTS(SetGroupOwner))
  1622. {
  1623. sgo.lpISP = PRV_GetDPLobbySPInterface(this);
  1624. // Drop the lock so the lobby provider's receive thread can get back
  1625. // in with other messages if they show up in the queue before our
  1626. // response (which always happens)
  1627. LEAVE_LOBBY_ALL();
  1628. hr = CALL_LP(this, SetGroupOwner, &sgo);
  1629. ENTER_LOBBY_ALL();
  1630. }
  1631. else
  1632. {
  1633. // SetGroupOwner is required
  1634. DPF_ERR("The Lobby Provider callback for SetGroupOwner doesn't exist");
  1635. hr = DPERR_UNAVAILABLE;
  1636. goto EXIT_SETGROUPOWNER;
  1637. }
  1638. // If it succeeded, send the SetGroupOwner message to our local players
  1639. if(SUCCEEDED(hr))
  1640. {
  1641. // Get a pointer to our internal data struct for the group, just in
  1642. // case it changed for some reason while we had dropped the locks
  1643. lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
  1644. if(!lpGroup)
  1645. {
  1646. DPF_ERR("Unable to find group in nametable -- local nametable will be incorrect");
  1647. goto EXIT_SETGROUPOWNER;
  1648. }
  1649. // Save the old owner so we can put it in the message
  1650. dwOldOwnerID = lpGroup->dwOwnerID;
  1651. // Change the owner
  1652. lpGroup->dwOwnerID = dwOwnerID;
  1653. // Send a SetGroupOwner message locally
  1654. PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwOwnerID, dwOldOwnerID);
  1655. }
  1656. else
  1657. {
  1658. DPF_ERRVAL("Failed calling SetGroupOwner in the Lobby Provider, hr = 0x%08x", hr);
  1659. }
  1660. EXIT_SETGROUPOWNER:
  1661. LEAVE_LOBBY_ALL();
  1662. return hr;
  1663. } // DPL_SetGroupOwner
  1664. #undef DPF_MODNAME
  1665. #define DPF_MODNAME "DPL_StartSession"
  1666. HRESULT DPLAPI DPL_StartSession(LPDIRECTPLAY lpDP, DWORD dwFlags, DWORD dwGroupID)
  1667. {
  1668. SPDATA_STARTSESSION ss;
  1669. LPDPLOBBYI_DPLOBJECT this = NULL;
  1670. LPDPLAYI_DPLAY lpDPObject = NULL;
  1671. LPDPLAYI_GROUP lpGroup = NULL;
  1672. HRESULT hr = DP_OK;
  1673. DPF(7, "Entering DPL_StartSession");
  1674. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  1675. lpDP, dwFlags, dwGroupID);
  1676. ENTER_LOBBY_ALL();
  1677. TRY
  1678. {
  1679. lpDPObject = DPLAY_FROM_INT(lpDP);
  1680. hr = VALID_DPLAY_PTR( lpDPObject );
  1681. if (FAILED(hr))
  1682. {
  1683. DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
  1684. goto ERROR_STARTSESSION;
  1685. }
  1686. if(!IS_LOBBY_OWNED(lpDPObject))
  1687. {
  1688. DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
  1689. hr = DPERR_UNSUPPORTED;
  1690. goto ERROR_STARTSESSION;
  1691. }
  1692. this = lpDPObject->lpLobbyObject;
  1693. if(!VALID_DPLOBBY_PTR(this))
  1694. {
  1695. DPF_ERR("Bad DPLobby object");
  1696. hr = DPERR_INVALIDOBJECT;
  1697. goto ERROR_STARTSESSION;
  1698. }
  1699. if(dwFlags)
  1700. {
  1701. DPF_ERR("Invalid flags");
  1702. hr = DPERR_INVALIDFLAGS;
  1703. goto ERROR_STARTSESSION;
  1704. }
  1705. lpGroup = GroupFromID(lpDPObject, dwGroupID);
  1706. if (!VALID_DPLAY_GROUP(lpGroup))
  1707. {
  1708. DPF_ERR("Invalid group id");
  1709. hr = DPERR_INVALIDGROUP;
  1710. goto ERROR_STARTSESSION;
  1711. }
  1712. // Make sure the group is a staging area
  1713. if(!(lpGroup->dwFlags & DPLAYI_GROUP_STAGINGAREA))
  1714. {
  1715. DPF_ERR("StartSession can only be called on a Staging Area");
  1716. hr = DPERR_INVALIDGROUP;
  1717. goto ERROR_STARTSESSION;
  1718. }
  1719. }
  1720. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1721. {
  1722. DPF_ERR( "Exception encountered validating parameters" );
  1723. hr = DPERR_INVALIDPARAMS;
  1724. goto ERROR_STARTSESSION;
  1725. }
  1726. // Setup our SPDATA struct
  1727. memset(&ss, 0, sizeof(SPDATA_STARTSESSION));
  1728. ss.dwSize = sizeof(SPDATA_STARTSESSION);
  1729. ss.dwGroupID = dwGroupID;
  1730. ss.dwFlags = dwFlags;
  1731. // Call the StartSession method in the SP
  1732. if(CALLBACK_EXISTS(StartSession))
  1733. {
  1734. ss.lpISP = PRV_GetDPLobbySPInterface(this);
  1735. // Drop the dplay lock so we can send a guarateed message
  1736. LEAVE_LOBBY_ALL();
  1737. hr = CALL_LP(this, StartSession, &ss);
  1738. // Take the lock back
  1739. ENTER_LOBBY_ALL();
  1740. }
  1741. else
  1742. {
  1743. // StartSession is required
  1744. DPF_ERR("The Lobby Provider callback for StartSession doesn't exist -- it's required");
  1745. ASSERT(FALSE);
  1746. hr = DPERR_UNAVAILABLE;
  1747. goto ERROR_STARTSESSION;
  1748. }
  1749. if(FAILED(hr))
  1750. {
  1751. DPF_ERRVAL("Failed calling StartSession in the Lobby Provider, hr = 0x%08x", hr);
  1752. }
  1753. ERROR_STARTSESSION:
  1754. LEAVE_LOBBY_ALL();
  1755. return hr;
  1756. } // DPL_StartSession
  1757. #undef DPF_MODNAME
  1758. #define DPF_MODNAME "PRV_CreateAndMapNewGroup"
  1759. HRESULT PRV_CreateAndMapNewGroup(LPDPLOBBYI_DPLOBJECT this,
  1760. DPID * lpdpid, LPDPNAME lpName, LPVOID lpData,
  1761. DWORD dwDataSize, DWORD dwFlags, DWORD dwLobbyID,
  1762. DPID dpidParent, DWORD dwOwnerID)
  1763. {
  1764. LPDPLAYI_GROUP lpGroup = NULL, lpSysGroup = NULL;
  1765. HRESULT hr;
  1766. DPID dpidGroup, dpidSysPlayer;
  1767. // Take the dplay lock
  1768. ENTER_DPLAY();
  1769. // Make sure the lobby ID is valid
  1770. if(!IsValidLobbyID(dwLobbyID))
  1771. {
  1772. DPF_ERRVAL("ID %lu is reserved, cannot create new player", dwLobbyID);
  1773. hr = DPERR_INVALIDPLAYER;
  1774. goto EXIT_CREATEANDMAPNEWGROUP;
  1775. }
  1776. // If this is a remote player, we need allocate a new nametable entry
  1777. // for them and set the correct system player ID
  1778. if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  1779. {
  1780. // Allocate a new ID for the player
  1781. hr = NS_AllocNameTableEntry(this->lpDPlayObject, &dpidGroup);
  1782. if(FAILED(hr))
  1783. {
  1784. DPF_ERRVAL("Unable to allocate new nametable id, hr = 0x%08x", hr);
  1785. goto EXIT_CREATEANDMAPNEWGROUP;
  1786. }
  1787. // Make sure we have a lobby system player (for all remote players
  1788. // & groups). If we don't then allocate a new one.
  1789. if(!(this->dpidSysPlayer))
  1790. {
  1791. hr = PRV_CreateAndMapNewPlayer(this, &dpidSysPlayer, NULL, NULL,
  1792. NULL, 0, DPLAYI_PLAYER_SYSPLAYER,
  1793. DPID_LOBBYREMOTESYSTEMPLAYER, TRUE);
  1794. if(FAILED(hr))
  1795. {
  1796. DPF_ERRVAL("Unable to create lobby system player, hr = 0x%08x", hr);
  1797. ASSERT(FALSE);
  1798. goto EXIT_CREATEANDMAPNEWGROUP;
  1799. }
  1800. // Set the lobby system player ID pointer to the new ID
  1801. this->dpidSysPlayer = dpidSysPlayer;
  1802. }
  1803. }
  1804. // Get a group struct for the group (if it's local, this will add it
  1805. // to the nametable. If it's remote, we need to add it below)
  1806. hr = GetGroup(this->lpDPlayObject, &lpGroup, lpName, lpData,
  1807. dwDataSize, dwFlags, dpidParent, dwLobbyID);
  1808. if(FAILED(hr))
  1809. {
  1810. DPF_ERRVAL("Failed trying to add group to the nametable, hr = 0x%08x", hr);
  1811. goto EXIT_CREATEANDMAPNEWGROUP;
  1812. }
  1813. // Fixup the group's owner
  1814. lpGroup->dwOwnerID = dwOwnerID;
  1815. // If the group is remote, set the group's ID to the new one we
  1816. // allocated and then set the system group ID to the lobby system group
  1817. if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  1818. {
  1819. //
  1820. lpGroup->dwIDSysPlayer = this->dpidSysPlayer;
  1821. // Add the group to the nametable
  1822. hr = AddItemToNameTable(this->lpDPlayObject, (DWORD_PTR)lpGroup,
  1823. &dpidGroup, TRUE, dwLobbyID);
  1824. if (FAILED(hr))
  1825. {
  1826. DPF_ERRVAL("Unable to add new group to the nametable, hr = 0x%08x", hr);
  1827. ASSERT(FALSE);
  1828. goto EXIT_CREATEANDMAPNEWGROUP;
  1829. }
  1830. // Set the group's ID
  1831. lpGroup->dwID = dpidGroup;
  1832. }
  1833. // Set the output dpid pointer
  1834. *lpdpid = lpGroup->dwID;
  1835. EXIT_CREATEANDMAPNEWGROUP:
  1836. LEAVE_DPLAY();
  1837. return hr;
  1838. } // PRV_CreateAndMapNewGroup