Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

571 lines
15 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dplunk.c
  6. * Content: IUnknown implementation for dplobby
  7. *
  8. * History:
  9. * Date By Reason
  10. * ======= ======= ======
  11. * 4/13/96 myronth Created it
  12. * 10/23/96 myronth Added client/server methods
  13. * 11/08/96 myronth Added PRV_GetDPLobbySPInterface
  14. * 11/20/96 myronth Added LogoffServer call to Release code
  15. * 2/12/97 myronth Mass DX5 changes
  16. * 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
  17. * 3/12/97 myronth New release code for DPlay3 (order different)
  18. * 3/13/97 myronth Added FreeLibrary code for LP's
  19. * 3/17/97 myronth Cleanup map table
  20. * 3/24/97 kipo Added support for IDirectPlayLobby2 interface
  21. * 4/3/97 myronth Changed CALLSP macro to CALL_LP
  22. * 5/8/97 myronth Drop the lobby lock when calling the LP, Purged
  23. * dead code
  24. * 7/30/97 myronth Added request node cleanup for standard lobby messaging
  25. * 8/19/97 myronth Added PRV_GetLobbyObjectFromInterface
  26. * 8/19/97 myronth Removed PRV_GetLobbyObjectFromInterface (not needed)
  27. * 12/2/97 myronth Added IDirectPlayLobby3 interface
  28. * 2/2/99 aarono Added lobbies to refcount on DPLAY dll to avoid
  29. * accidental unload.
  30. ***************************************************************************/
  31. #include "dplobpr.h"
  32. //--------------------------------------------------------------------------
  33. //
  34. // Definitions
  35. //
  36. //--------------------------------------------------------------------------
  37. //--------------------------------------------------------------------------
  38. //
  39. // Functions
  40. //
  41. //--------------------------------------------------------------------------
  42. #undef DPF_MODNAME
  43. #define DPF_MODNAME "PRV_GetDPLobbySPInterface"
  44. LPDPLOBBYSP PRV_GetDPLobbySPInterface(LPDPLOBBYI_DPLOBJECT this)
  45. {
  46. LPDPLOBBYI_INTERFACE lpInt;
  47. ASSERT(this);
  48. // Get an IDPLobbySP interface
  49. if(FAILED(PRV_GetInterface(this, &lpInt, &dplCallbacksSP)))
  50. {
  51. DPF_ERR("Unable to get non-reference counted DPLobbySP Interface pointer");
  52. ASSERT(FALSE);
  53. return NULL;
  54. }
  55. // Decrement the ref cnt on the interface
  56. lpInt->dwIntRefCnt--;
  57. // Return the interface pointer
  58. return (LPDPLOBBYSP)lpInt;
  59. } // PRV_GetDPLobbySPInterface
  60. // Find an interface with the pCallbacks vtbl on this object.
  61. // If one doesn't exist, create it, increment the ref count,
  62. // and return the interface
  63. #undef DPF_MODNAME
  64. #define DPF_MODNAME "PRV_GetInterface"
  65. HRESULT PRV_GetInterface(LPDPLOBBYI_DPLOBJECT this,
  66. LPDPLOBBYI_INTERFACE * ppInt,
  67. LPVOID lpCallbacks)
  68. {
  69. LPDPLOBBYI_INTERFACE lpCurrentInts = this->lpInterfaces;
  70. BOOL bFound = FALSE;
  71. DPF(7, "Entering PRV_GetInterface");
  72. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  73. this, ppInt, lpCallbacks);
  74. ASSERT(ppInt);
  75. // See if there is already an interface
  76. while (lpCurrentInts && !bFound)
  77. {
  78. if (lpCurrentInts->lpVtbl == lpCallbacks)
  79. {
  80. bFound = TRUE;
  81. }
  82. else
  83. lpCurrentInts = lpCurrentInts->lpNextInterface;
  84. }
  85. // If there is one, return it
  86. if(bFound)
  87. {
  88. *ppInt = lpCurrentInts;
  89. (*ppInt)->dwIntRefCnt++;
  90. // we don't increment this->dwRefCnt, since it's one / interface object
  91. return DP_OK;
  92. }
  93. // Otherwise create one
  94. *ppInt = DPMEM_ALLOC(sizeof(DPLOBBYI_INTERFACE));
  95. if (!(*ppInt))
  96. {
  97. DPF_ERR("Could not alloc interface - out of memory");
  98. return E_OUTOFMEMORY;
  99. }
  100. (*ppInt)->dwIntRefCnt = 1;
  101. (*ppInt)->lpDPLobby = this;
  102. (*ppInt)->lpNextInterface = this->lpInterfaces;
  103. (*ppInt)->lpVtbl = lpCallbacks;
  104. this->lpInterfaces = *ppInt;
  105. this->dwRefCnt++; // One time only for each interface object
  106. return DP_OK;
  107. } // PRV_GetInterface
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "DPL_QueryInterface"
  110. HRESULT DPLAPI DPL_QueryInterface(LPDIRECTPLAYLOBBY lpDPL, REFIID riid, LPVOID * ppvObj)
  111. {
  112. LPDPLOBBYI_DPLOBJECT this;
  113. HRESULT hr;
  114. DPF(7, "Entering DPL_QueryInterface");
  115. DPF(9, "Parameters: 0x%08x, refiid, 0x%08x", lpDPL, ppvObj);
  116. ENTER_DPLOBBY();
  117. TRY
  118. {
  119. if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
  120. {
  121. LEAVE_DPLOBBY();
  122. return DPERR_INVALIDINTERFACE;
  123. }
  124. this = DPLOBJECT_FROM_INTERFACE(lpDPL);
  125. if( !VALID_DPLOBBY_PTR( this ) )
  126. {
  127. LEAVE_DPLOBBY();
  128. return DPERR_INVALIDOBJECT;
  129. }
  130. if ( !VALID_READ_UUID_PTR(riid) )
  131. {
  132. LEAVE_DPLOBBY();
  133. return DPERR_INVALIDPARAMS;
  134. }
  135. if ((!VALID_UUID_PTR(ppvObj)) )
  136. {
  137. LEAVE_DPLOBBY();
  138. DPF_ERR("Object pointer is invalid!");
  139. return DPERR_INVALIDPARAMS;
  140. }
  141. }
  142. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  143. {
  144. DPF_ERR( "Exception encountered validating parameters" );
  145. LEAVE_DPLOBBY();
  146. return DPERR_INVALIDPARAMS;
  147. }
  148. *ppvObj=NULL;
  149. if( IsEqualIID(riid, &IID_IUnknown) ||
  150. IsEqualIID(riid, &IID_IDirectPlayLobby) )
  151. {
  152. // Get an IDirectPlayLobby Interface (Unicode)
  153. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  154. &dplCallbacks);
  155. }
  156. else if( IsEqualIID(riid, &IID_IDirectPlayLobbyA) )
  157. {
  158. // Get an IDirectPlayLobbyA Interface (ANSI)
  159. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  160. &dplCallbacksA);
  161. }
  162. else if( IsEqualIID(riid, &IID_IDirectPlayLobby2) )
  163. {
  164. // Get an IDirectPlayLobby2 Interface (Unicode)
  165. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  166. &dplCallbacks2);
  167. }
  168. else if( IsEqualIID(riid, &IID_IDirectPlayLobby2A) )
  169. {
  170. // Get an IDirectPlayLobby2A Interface (ANSI)
  171. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  172. &dplCallbacks2A);
  173. }
  174. else if( IsEqualIID(riid, &IID_IDirectPlayLobby3) )
  175. {
  176. // Get an IDirectPlayLobby3 Interface (Unicode)
  177. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  178. &dplCallbacks3);
  179. }
  180. else if( IsEqualIID(riid, &IID_IDirectPlayLobby3A) )
  181. {
  182. // Get an IDirectPlayLobby3A Interface (ANSI)
  183. hr = PRV_GetInterface(this, (LPDPLOBBYI_INTERFACE *) ppvObj,
  184. &dplCallbacks3A);
  185. }
  186. else
  187. {
  188. hr = E_NOINTERFACE;
  189. }
  190. LEAVE_DPLOBBY();
  191. return hr;
  192. } //DPL_QueryInterface
  193. #undef DPF_MODNAME
  194. #define DPF_MODNAME "DPL_AddRef"
  195. ULONG DPLAPI DPL_AddRef(LPDIRECTPLAYLOBBY lpDPL)
  196. {
  197. LPDPLOBBYI_INTERFACE lpInt = (LPDPLOBBYI_INTERFACE)lpDPL;
  198. LPDPLOBBYI_DPLOBJECT this;
  199. DPF(7, "Entering DPL_AddRef");
  200. DPF(9, "Parameters: 0x%08x", lpDPL);
  201. ENTER_DPLOBBY();
  202. TRY
  203. {
  204. if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
  205. {
  206. LEAVE_DPLOBBY();
  207. return 0;
  208. }
  209. this = DPLOBJECT_FROM_INTERFACE(lpDPL);
  210. if( !VALID_DPLOBBY_PTR( this ) )
  211. {
  212. LEAVE_DPLOBBY();
  213. return 0;
  214. }
  215. }
  216. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  217. {
  218. DPF_ERR( "Exception encountered validating parameters" );
  219. LEAVE_DPLOBBY();
  220. return 0;
  221. }
  222. // Make sure someone isn't calling AddRef on our IDPLobbySP interface
  223. if(lpInt->lpVtbl == &dplCallbacksSP)
  224. {
  225. DPF_ERR("You cannot call AddRef on an IDPLobbySP interface");
  226. ASSERT(FALSE);
  227. LEAVE_DPLOBBY();
  228. return 0;
  229. }
  230. // Increment the interface's reference count
  231. lpInt->dwIntRefCnt++;
  232. LEAVE_DPLOBBY();
  233. return (lpInt->dwIntRefCnt);
  234. } //DPL_AddRef
  235. #undef DPF_MODNAME
  236. #define DPF_MODNAME "PRV_DestroyDPLobby"
  237. HRESULT PRV_DestroyDPLobby(LPDPLOBBYI_DPLOBJECT this)
  238. {
  239. HRESULT hr = DP_OK;
  240. DPF(7, "Entering PRV_DestroyDPLobby");
  241. DPF(9, "Parameters: 0x%08x", this);
  242. // Since we can now be called from the DPlay3 object's Release code,
  243. // make sure we don't have any interface objects when we go to
  244. // free our lobby object. Assert here if any interfaces exist.
  245. ASSERT(!this->lpInterfaces);
  246. // Walk the list of GameNodes, freeing them as you go
  247. while(this->lpgnHead)
  248. PRV_RemoveGameNodeFromList(this->lpgnHead);
  249. // Walk the list of pending lobby server requests and free them
  250. while(this->lprnHead)
  251. PRV_RemoveRequestNode(this, this->lprnHead);
  252. // Free our callback table if one exists
  253. if(this->pcbSPCallbacks)
  254. DPMEM_FREE(this->pcbSPCallbacks);
  255. // Free our ID Map Table if it exists
  256. if(this->lpMap)
  257. DPMEM_FREE(this->lpMap);
  258. // Free the dplobby object
  259. DPMEM_FREE(this);
  260. gnObjects--;
  261. ASSERT(((int)gnObjects) >= 0);
  262. return DP_OK;
  263. } // PRV_DestroyDPlayLobby
  264. #undef DPF_MODNAME
  265. #define DPF_MODNAME "PRV_DestroyDPLobbyInterface"
  266. HRESULT PRV_DestroyDPLobbyInterface(LPDPLOBBYI_DPLOBJECT this,
  267. LPDPLOBBYI_INTERFACE lpInterface)
  268. {
  269. LPDPLOBBYI_INTERFACE lpIntPrev; // The interface preceeding pInt in the list
  270. BOOL bFound = FALSE;
  271. DPF(7, "Entering PRV_DestroyDPLobbyInterface");
  272. DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpInterface);
  273. // Remove pInt from the list of interfaces
  274. if (this->lpInterfaces == lpInterface)
  275. {
  276. // It's the 1st one, just remove it
  277. this->lpInterfaces = lpInterface->lpNextInterface;
  278. }
  279. else
  280. {
  281. lpIntPrev = this->lpInterfaces;
  282. while (lpIntPrev && !bFound)
  283. {
  284. if (lpIntPrev->lpNextInterface == lpInterface)
  285. {
  286. bFound = TRUE;
  287. }
  288. else lpIntPrev = lpIntPrev->lpNextInterface;
  289. }
  290. if (!bFound)
  291. {
  292. ASSERT(FALSE);
  293. return E_UNEXPECTED;
  294. }
  295. // take pint out of the list
  296. lpIntPrev->lpNextInterface = lpInterface->lpNextInterface;
  297. }
  298. DPMEM_FREE(lpInterface);
  299. return DP_OK;
  300. } // PRV_DestroyDPLobbyInterface
  301. #undef DPF_MODNAME
  302. #define DPF_MODNAME "DPL_Release"
  303. ULONG PRV_Release(LPDPLOBBYI_DPLOBJECT this, LPDPLOBBYI_INTERFACE lpInterface)
  304. {
  305. HRESULT hr = DP_OK;
  306. SPDATA_SHUTDOWN sdd;
  307. DWORD dwError;
  308. DPF(7, "==> PRV_Release");
  309. DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpInterface);
  310. ENTER_DPLOBBY();
  311. // Decrement the interface ref count
  312. if (0 == --(lpInterface->dwIntRefCnt))
  313. {
  314. LPDPLOBBYI_GAMENODE lpgn;
  315. // Notifying apps we launched that we are releasing
  316. // our lobby interface.
  317. lpgn=this->lpgnHead;
  318. while(lpgn){
  319. if(lpgn->dwFlags & GN_LOBBY_CLIENT) {
  320. hr=PRV_SendStandardSystemMessage((LPDIRECTPLAYLOBBY)lpInterface, DPLSYS_LOBBYCLIENTRELEASE, lpgn->dwGameProcessID);
  321. if(DP_OK != hr){
  322. DPF(0,"Couldn't send system message to game pid %x, hr=%x",lpgn->dwGameProcessID,hr);
  323. } else {
  324. DPF(9,"Told Process %x we are releasing the lobby interface",lpgn->dwGameProcessID);
  325. }
  326. }
  327. lpgn=lpgn->lpgnNext;
  328. }
  329. DPF(7,"Lobby interface Refcount hit 0, freeing\n");
  330. // Since we're destroying an interface, dec the object count
  331. this->dwRefCnt--;
  332. // If our object ref cnt just went to zero, we need to call
  333. // shutdown in the LP if one is loaded
  334. if(this->dwFlags & DPLOBBYPR_SPINTERFACE)
  335. {
  336. // Clear our stack-based structure
  337. memset(&sdd, 0, sizeof(SPDATA_SHUTDOWN));
  338. // Call the Shutdown method in the SP
  339. if(CALLBACK_EXISTS(Shutdown))
  340. {
  341. sdd.lpISP = PRV_GetDPLobbySPInterface(this);
  342. // Drop the lock so the lobby provider's receive thread can get back
  343. // in with other messages if they show up in the queue before our
  344. // CreatePlayer response (which always happens)
  345. LEAVE_DPLOBBY();
  346. hr = CALL_LP(this, Shutdown, &sdd);
  347. ENTER_DPLOBBY();
  348. }
  349. else
  350. {
  351. // All LP's should support Shutdown
  352. ASSERT(FALSE);
  353. hr = DPERR_UNAVAILABLE;
  354. }
  355. if (FAILED(hr))
  356. {
  357. DPF_ERR("Could not invoke Shutdown method in the Service Provider");
  358. }
  359. }
  360. // REVIEW!!!! -- Are we going to have the same problem dplay has
  361. // with SP's hanging around and crashing after we go away? We
  362. // need to make sure the LP goes away first.
  363. if(this->hInstanceLP)
  364. {
  365. DPF(7,"About to free lobby provider library, hInstance %x\n",this->hInstanceLP);
  366. if (!FreeLibrary(this->hInstanceLP))
  367. {
  368. dwError = GetLastError();
  369. DPF_ERRVAL("Unable to free Lobby Provider DLL, dwError = %lu", dwError);
  370. ASSERT(FALSE);
  371. }
  372. // Just to be safe
  373. this->hInstanceLP = NULL;
  374. }
  375. // If the interface is the IDPLobbySP interface, we had to have been
  376. // called from the DPlay3 release code, so clear the SP flag since
  377. // we are going to remove the IDPLobbySP interface just below here.
  378. this->dwFlags &= ~DPLOBBYPR_SPINTERFACE;
  379. // Take the interface out of the table
  380. hr = PRV_DestroyDPLobbyInterface(this, lpInterface);
  381. if (FAILED(hr))
  382. {
  383. DPF(0,"Could not destroy DPLobby interface! hr = 0x%08lx\n", hr);
  384. ASSERT(FALSE);
  385. }
  386. // Now destroy the interface if the ref cnt is 0
  387. if(0 == this->dwRefCnt)
  388. {
  389. // Destroy the DPLobby object
  390. DPF(0,"Destroying DirectPlayLobby object - ref cnt = 0!");
  391. hr = PRV_DestroyDPLobby(this);
  392. if (FAILED(hr))
  393. {
  394. DPF(0,"Could not destroy DPLobby! hr = 0x%08lx\n",hr);
  395. ASSERT(FALSE);
  396. }
  397. } // 0 == this->dwRefCnt
  398. LEAVE_DPLOBBY();
  399. return 0;
  400. } //0 == pInt->dwIntRefCnt
  401. DPF(7, "<==PRV_Release, rc=%d\n",lpInterface->dwIntRefCnt);
  402. LEAVE_DPLOBBY();
  403. return (lpInterface->dwIntRefCnt);
  404. } // PRV_Release
  405. #undef DPF_MODNAME
  406. #define DPF_MODNAME "DPL_Release"
  407. ULONG DPLAPI DPL_Release(LPDIRECTPLAYLOBBY lpDPL)
  408. {
  409. LPDPLOBBYI_INTERFACE lpInterface;
  410. LPDPLOBBYI_DPLOBJECT this;
  411. HRESULT hr = DP_OK;
  412. DPF(7, "Entering DPL_Release");
  413. DPF(9, "Parameters: 0x%08x", lpDPL);
  414. TRY
  415. {
  416. lpInterface = (LPDPLOBBYI_INTERFACE)lpDPL;
  417. if( !VALID_DPLOBBY_INTERFACE( lpInterface ))
  418. {
  419. return 0;
  420. }
  421. this = DPLOBJECT_FROM_INTERFACE(lpDPL);
  422. if( !VALID_DPLOBBY_PTR( this ) )
  423. {
  424. return 0;
  425. }
  426. }
  427. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  428. {
  429. DPF_ERR( "Exception encountered validating parameters" );
  430. return 0;
  431. }
  432. // Make sure someone isn't calling Release on our IDPLobbySP interface
  433. if(lpInterface->lpVtbl == &dplCallbacksSP)
  434. {
  435. DPF_ERR("You cannot call Release on an IDPLobbySP interface");
  436. ASSERT(FALSE);
  437. return 0;
  438. }
  439. // Call our internal release function
  440. return PRV_Release(this, lpInterface);
  441. } //DPL_Release
  442. #undef DPF_MODNAME
  443. #define DPF_MODNAME "PRV_FreeAllLobbyObjects"
  444. void PRV_FreeAllLobbyObjects(LPDPLOBBYI_DPLOBJECT this)
  445. {
  446. DPF(7, "Entering PRV_FreeAllLobbyObjects");
  447. DPF(9, "Parameters: 0x%08x", this);
  448. ASSERT(this);
  449. // If we have an SP interface, just call release on it
  450. if(this->dwFlags & DPLOBBYPR_SPINTERFACE)
  451. {
  452. // Assert if an interface doesn't exist, because it should
  453. ASSERT(this->lpInterfaces);
  454. PRV_Release(this, this->lpInterfaces);
  455. return;
  456. }
  457. // Otherwise, we should only have an uninitialized object,
  458. // which we should just be able to destroy
  459. PRV_DestroyDPLobby(this);
  460. }