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.

541 lines
16 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: DPLApp.cpp
  6. * Content: DirectPlay Lobbied Application Functions
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 02/21/00 mjn Created
  12. * 03/22/2000 jtk Changed interface names
  13. * 04/18/2000 rmt Added additional parameter validation
  14. * 04/25/2000 rmt Bug #s 33138, 33145, 33150
  15. * 04/26/00 mjn Removed dwTimeOut from Send() API call
  16. * 05/03/00 rmt DPL_UnRegister was not implemented!!
  17. * 05/08/00 rmt Bug #34301 - Add flag to SetAppAvail to allow for multiple connects
  18. * 06/15/00 rmt Bug #33617 - Must provide method for providing automatic launch of DirectPlay instances
  19. * 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched
  20. * rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns
  21. * rmt Bug #38755 - No way to specify player name in Connection Settings
  22. * rmt Bug #38758 - DPLOBBY8.H has incorrect comments
  23. * rmt Bug #38783 - pvUserApplicationContext is only partially implemented
  24. * rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs).
  25. * 07/14/2000 rmt Bug #39257 - LobbyClient::ReleaseApp returns E_OUTOFMEMORY when called when no one connected
  26. * rmt Bug #39487 - Remove WaitForConnect
  27. * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  28. * 08/15/2000 rmt Bug #42273 - DPLAY8: Samples sometimes get a DPNERR_ALREADYREGISTERED error. (Double connections)
  29. * 08/18/2000 rmt Bug #42751 - DPLOBBY8: Prohibit more than one lobby client or lobby app per process
  30. *@@END_MSINTERNAL
  31. *
  32. ***************************************************************************/
  33. #include "dnlobbyi.h"
  34. //**********************************************************************
  35. // Macro definitions
  36. //**********************************************************************
  37. //**********************************************************************
  38. // Structure definitions
  39. //**********************************************************************
  40. //**********************************************************************
  41. // Variable definitions
  42. //**********************************************************************
  43. typedef STDMETHODIMP AppQueryInterface(IDirectPlay8LobbiedApplication *pInterface,REFIID ridd,PVOID *ppvObj);
  44. typedef STDMETHODIMP_(ULONG) AppAddRef(IDirectPlay8LobbiedApplication *pInterface);
  45. typedef STDMETHODIMP_(ULONG) AppRelease(IDirectPlay8LobbiedApplication *pInterface);
  46. typedef STDMETHODIMP AppRegisterMessageHandler(IDirectPlay8LobbiedApplication *pInterface,const PVOID pvUserContext,const PFNDPNMESSAGEHANDLER pfn, DPNHANDLE * const pdpnhConnection, const DWORD dwFlags);
  47. typedef STDMETHODIMP AppSend(IDirectPlay8LobbiedApplication *pInterface,const DPNHANDLE hTarget,BYTE *const pBuffer,const DWORD pBufferSize,const DWORD dwFlags);
  48. typedef STDMETHODIMP AppClose(IDirectPlay8LobbiedApplication *pInterface, const DWORD dwFlags);
  49. typedef STDMETHODIMP AppGetConnectionSettings(IDirectPlay8LobbiedApplication *pInterface, const DPNHANDLE hLobbyClient, DPL_CONNECTION_SETTINGS * const pdplSessionInfo, DWORD *pdwInfoSize, const DWORD dwFlags );
  50. typedef STDMETHODIMP AppSetConnectionSettings(IDirectPlay8LobbiedApplication *pInterface, const DPNHANDLE hTarget, const DPL_CONNECTION_SETTINGS * const pdplSessionInfo, const DWORD dwFlags );
  51. IDirectPlay8LobbiedApplicationVtbl DPL_8LobbiedApplicationVtbl =
  52. {
  53. (AppQueryInterface*) DPL_QueryInterface,
  54. (AppAddRef*) DPL_AddRef,
  55. (AppRelease*) DPL_Release,
  56. (AppRegisterMessageHandler*) DPL_RegisterMessageHandler,
  57. DPL_RegisterProgram,
  58. DPL_UnRegisterProgram,
  59. (AppSend*) DPL_Send,
  60. DPL_SetAppAvailable,
  61. DPL_UpdateStatus,
  62. (AppClose*) DPL_Close,
  63. (AppGetConnectionSettings*) DPL_GetConnectionSettings,
  64. (AppSetConnectionSettings*) DPL_SetConnectionSettings
  65. };
  66. //**********************************************************************
  67. // Function prototypes
  68. //**********************************************************************
  69. //**********************************************************************
  70. // Function definitions
  71. //**********************************************************************
  72. #undef DPF_MODNAME
  73. #define DPF_MODNAME "DPL_RegisterProgram"
  74. STDMETHODIMP DPL_RegisterProgram(IDirectPlay8LobbiedApplication *pInterface,
  75. DPL_PROGRAM_DESC *const pdplProgramDesc,
  76. const DWORD dwFlags)
  77. {
  78. HRESULT hResultCode;
  79. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pdplProgramDesc [0x%p], dwFlags [0x%lx]",
  80. pInterface,pdplProgramDesc,dwFlags);
  81. #ifndef DPNBUILD_NOPARAMVAL
  82. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  83. TRY
  84. {
  85. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  86. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  87. {
  88. if( FAILED( hResultCode = DPL_ValidateRegisterProgram( pInterface , pdplProgramDesc, dwFlags ) ) )
  89. {
  90. DPFX(DPFPREP, 0, "Error validating register params hr=[0x%lx]", hResultCode );
  91. DPF_RETURN( hResultCode );
  92. }
  93. }
  94. }
  95. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  96. {
  97. DPFERR("Invalid object" );
  98. DPF_RETURN(DPNERR_INVALIDOBJECT);
  99. }
  100. #endif // !DPNBUILD_NOPARAMVAL
  101. hResultCode = DPLWriteProgramDesc(pdplProgramDesc);
  102. DPF_RETURN(hResultCode);
  103. }
  104. #undef DPF_MODNAME
  105. #define DPF_MODNAME "DPL_UnRegisterProgram"
  106. STDMETHODIMP DPL_UnRegisterProgram(IDirectPlay8LobbiedApplication *pInterface,
  107. GUID *const pGuidApplication,
  108. const DWORD dwFlags)
  109. {
  110. HRESULT hResultCode;
  111. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pGuidApplication [0x%p], dwFlags [0x%lx]",
  112. pInterface,pGuidApplication,dwFlags);
  113. #ifndef DPNBUILD_NOPARAMVAL
  114. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  115. TRY
  116. {
  117. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  118. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  119. {
  120. if( FAILED( hResultCode = DPL_ValidateUnRegisterProgram( pInterface , pGuidApplication, dwFlags ) ) )
  121. {
  122. DPFX(DPFPREP, 0, "Error validating unregister params hr=[0x%lx]", hResultCode );
  123. DPF_RETURN( hResultCode );
  124. }
  125. }
  126. }
  127. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  128. {
  129. DPFERR("Invalid object" );
  130. DPF_RETURN(DPNERR_INVALIDOBJECT);
  131. }
  132. #endif // !DPNBUILD_NOPARAMVAL
  133. hResultCode = DPLDeleteProgramDesc( pGuidApplication );
  134. DPF_RETURN(hResultCode);
  135. }
  136. #undef DPF_MODNAME
  137. #define DPF_MODNAME "DPL_SetAppAvailable"
  138. STDMETHODIMP DPL_SetAppAvailable(IDirectPlay8LobbiedApplication *pInterface, const BOOL fAvailable, const DWORD dwFlags )
  139. {
  140. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  141. HRESULT hResultCode;
  142. DPFX(DPFPREP, 3,"Parameters: (none)");
  143. #ifndef DPNBUILD_NOPARAMVAL
  144. TRY
  145. {
  146. #endif // !DPNBUILD_NOPARAMVAL
  147. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  148. #ifndef DPNBUILD_NOPARAMVAL
  149. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  150. {
  151. if( FAILED( hResultCode = DPL_ValidateSetAppAvailable( pInterface, fAvailable, dwFlags ) ) )
  152. {
  153. DPFX(DPFPREP, 0, "Error validating makeappavail params hr=[0x%lx]", hResultCode );
  154. DPF_RETURN( hResultCode );
  155. }
  156. }
  157. // Ensure we've been initialized
  158. if (pdpLobbyObject->pReceiveQueue == NULL)
  159. {
  160. DPFERR("Not initialized");
  161. DPF_RETURN(DPNERR_UNINITIALIZED);
  162. }
  163. }
  164. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  165. {
  166. DPFERR("Invalid object" );
  167. DPF_RETURN(DPNERR_INVALIDOBJECT);
  168. }
  169. #endif // !DPNBUILD_NOPARAMVAL
  170. if( fAvailable )
  171. {
  172. // Indicate that we are waiting
  173. pdpLobbyObject->pReceiveQueue->MakeAvailable();
  174. if( dwFlags & DPLAVAILABLE_ALLOWMULTIPLECONNECT )
  175. {
  176. pdpLobbyObject->dwFlags |= DPL_OBJECT_FLAG_MULTICONNECT;
  177. }
  178. else
  179. {
  180. pdpLobbyObject->dwFlags &= ~(DPL_OBJECT_FLAG_MULTICONNECT);
  181. }
  182. }
  183. else
  184. {
  185. pdpLobbyObject->pReceiveQueue->MakeUnavailable();
  186. }
  187. hResultCode = DPN_OK;
  188. DPF_RETURN(hResultCode);
  189. }
  190. // DPL_UpdateStatus
  191. //
  192. // Send session status information to the lobby client. This should be called whenever
  193. // the lobbied application connects to the game, fails to connect, disconnects, or is
  194. // terminated (booted).
  195. #undef DPF_MODNAME
  196. #define DPF_MODNAME "DPL_UpdateStatus"
  197. STDMETHODIMP DPL_UpdateStatus(IDirectPlay8LobbiedApplication *pInterface,
  198. const DPNHANDLE hLobbyClient,
  199. const DWORD dwStatus, const DWORD dwFlags )
  200. {
  201. HRESULT hResultCode;
  202. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  203. DPL_CONNECTION *pdplConnection;
  204. DPL_INTERNAL_MESSAGE_UPDATE_STATUS Msg;
  205. DPNHANDLE *hTargets = NULL;
  206. DWORD dwNumTargets = 0;
  207. DWORD dwTargetIndex = 0;
  208. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], hLobbyClient [0x%lx], dwStatus [0x%lx]",
  209. pInterface,hLobbyClient,dwStatus);
  210. #ifndef DPNBUILD_NOPARAMVAL
  211. TRY
  212. {
  213. #endif // !DPNBUILD_NOPARAMVAL
  214. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  215. #ifndef DPNBUILD_NOPARAMVAL
  216. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  217. {
  218. if( FAILED( hResultCode = DPL_ValidateUpdateStatus( pInterface, hLobbyClient, dwStatus, dwFlags ) ) )
  219. {
  220. DPFX(DPFPREP, 0, "Error validating updatestatus params hr=[0x%lx]", hResultCode );
  221. DPF_RETURN( hResultCode );
  222. }
  223. }
  224. // Ensure we've been initialized
  225. if (pdpLobbyObject->pReceiveQueue == NULL)
  226. {
  227. DPFERR("Not initialized");
  228. DPF_RETURN(DPNERR_UNINITIALIZED);
  229. }
  230. }
  231. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  232. {
  233. DPFERR("Invalid object" );
  234. DPF_RETURN(DPNERR_INVALIDOBJECT);
  235. }
  236. #endif // !DPNBUILD_NOPARAMVAL
  237. Msg.dwMsgId = DPL_MSGID_INTERNAL_UPDATE_STATUS;
  238. Msg.dwStatus = dwStatus;
  239. if( hLobbyClient == DPLHANDLE_ALLCONNECTIONS )
  240. {
  241. dwNumTargets = 0;
  242. // We need loop so if someone adds a connection during our run
  243. // it gets added to our list
  244. //
  245. while( 1 )
  246. {
  247. hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
  248. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  249. {
  250. if( hTargets )
  251. {
  252. delete [] hTargets;
  253. }
  254. hTargets = new DPNHANDLE[dwNumTargets];
  255. if( hTargets == NULL )
  256. {
  257. DPFERR("Error allocating memory" );
  258. hResultCode = DPNERR_OUTOFMEMORY;
  259. dwNumTargets = 0;
  260. goto EXIT_AND_CLEANUP;
  261. }
  262. memset( hTargets, 0x00, sizeof(DPNHANDLE)*dwNumTargets);
  263. continue;
  264. }
  265. else if( FAILED( hResultCode ) )
  266. {
  267. DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode );
  268. break;
  269. }
  270. else
  271. {
  272. break;
  273. }
  274. }
  275. // Failed getting connection information
  276. if( FAILED( hResultCode ) )
  277. {
  278. if( hTargets )
  279. {
  280. delete [] hTargets;
  281. hTargets = NULL;
  282. }
  283. dwNumTargets = 0;
  284. goto EXIT_AND_CLEANUP;
  285. }
  286. }
  287. else
  288. {
  289. hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
  290. if( hTargets == NULL )
  291. {
  292. DPFERR("Error allocating memory" );
  293. hResultCode = DPNERR_OUTOFMEMORY;
  294. dwNumTargets = 0;
  295. goto EXIT_AND_CLEANUP;
  296. }
  297. dwNumTargets = 1;
  298. hTargets[0] = hLobbyClient;
  299. }
  300. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  301. {
  302. if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hTargets[dwTargetIndex],&pdplConnection,TRUE)) != DPN_OK)
  303. {
  304. DPFERR("Invalid send target");
  305. DisplayDNError(0,hResultCode);
  306. hResultCode = DPNERR_INVALIDHANDLE;
  307. goto EXIT_AND_CLEANUP;
  308. }
  309. DNASSERT(pdplConnection->pSendQueue != NULL);
  310. if (!pdplConnection->pSendQueue->IsReceiving())
  311. {
  312. DPFERR("Other side is not listening");
  313. hResultCode = DPNERR_INVALIDHANDLE;
  314. goto EXIT_AND_CLEANUP;
  315. }
  316. hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(&Msg),
  317. sizeof(DPL_INTERNAL_MESSAGE_UPDATE_STATUS),
  318. INFINITE,
  319. DPL_MSGQ_MSGFLAGS_USER1,
  320. 0);
  321. if( FAILED( hResultCode ) )
  322. {
  323. DPFX(DPFPREP, 0, "Error sending to connection 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  324. }
  325. }
  326. EXIT_AND_CLEANUP:
  327. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  328. {
  329. if( hTargets[dwTargetIndex] )
  330. DPLConnectionRelease(pdpLobbyObject,hTargets[dwTargetIndex]);
  331. }
  332. if( hTargets )
  333. delete [] hTargets;
  334. DPF_RETURN(hResultCode);
  335. }
  336. #undef DPF_MODNAME
  337. #define DPF_MODNAME "DPLAttemptLobbyConnection"
  338. HRESULT DPLAttemptLobbyConnection(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject)
  339. {
  340. PTSTR pszCommandLine;
  341. TCHAR *c;
  342. DWORD dwCommandLineSize;
  343. TCHAR pszObjectName[(sizeof(DWORD)*2)*2 + 1 + 1];
  344. DNHANDLE hSyncEvent;
  345. HRESULT hResultCode;
  346. DNHANDLE hFileMap;
  347. DPL_SHARED_CONNECT_BLOCK *pSharedBlock;
  348. DWORD dwError;
  349. DWORD dwReturnValue;
  350. DPFX(DPFPREP, 3,"Parameters: (none)");
  351. // Need a copy of the command line
  352. dwCommandLineSize = (_tcslen(GetCommandLine()) + 1) * sizeof(TCHAR);
  353. if ((pszCommandLine = static_cast<PTSTR>(DNMalloc(dwCommandLineSize))) == NULL)
  354. {
  355. DPFERR("Allocating memory failed");
  356. return(DPNERR_OUTOFMEMORY);
  357. }
  358. _tcscpy(pszCommandLine,GetCommandLine());
  359. DPFX(DPFPREP, 5,"Got command line [%s]",pszCommandLine);
  360. // Try to find Lobby Launch ID string
  361. c = _tcsstr(pszCommandLine,DPL_ID_STR);
  362. if (c == NULL)
  363. {
  364. DNFree(pszCommandLine);
  365. return(DPNERR_GENERIC);
  366. }
  367. c += _tcslen(DPL_ID_STR);
  368. c--; // We are going to overwrite the '=' with a IDCHAR below
  369. _tcsncpy(pszObjectName,c,(sizeof(DWORD)*2)*2 + 1);
  370. pszObjectName[(sizeof(DWORD)*2)*2 + 1] = _T('\0'); // Ensure null terminated
  371. DPFX(DPFPREP, 5,"Got object name [%s]",pszObjectName);
  372. DNFree(pszCommandLine);
  373. // Try to open shared memory
  374. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_FILEMAP;
  375. hFileMap = DNCreateFileMapping(INVALID_HANDLE_VALUE,(LPSECURITY_ATTRIBUTES) NULL,
  376. PAGE_READWRITE,0,sizeof(DPL_SHARED_CONNECT_BLOCK),pszObjectName);
  377. if (hFileMap == NULL)
  378. {
  379. DPFERR("CreateFileMapping() failed");
  380. dwError = GetLastError();
  381. DNASSERT(FALSE);
  382. return(DPNERR_GENERIC);
  383. }
  384. // Ensure it existed already
  385. dwError = GetLastError();
  386. if (dwError != ERROR_ALREADY_EXISTS)
  387. {
  388. DPFERR("File mapping did not already exist");
  389. // DNASSERT(FALSE);
  390. DNCloseHandle(hFileMap);
  391. return(DPNERR_GENERIC);
  392. }
  393. // Map file
  394. pSharedBlock = reinterpret_cast<DPL_SHARED_CONNECT_BLOCK*>(MapViewOfFile(HANDLE_FROM_DNHANDLE(hFileMap),FILE_MAP_ALL_ACCESS,0,0,0));
  395. if (pSharedBlock == NULL)
  396. {
  397. DPFERR("MapViewOfFile() failed");
  398. dwError = GetLastError();
  399. DNASSERT(FALSE);
  400. DNCloseHandle(hFileMap);
  401. return(DPNERR_GENERIC);
  402. }
  403. // Try to open connection event
  404. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_EVENT;
  405. hSyncEvent = DNOpenEvent(EVENT_MODIFY_STATE,FALSE,pszObjectName);
  406. if (hSyncEvent == NULL)
  407. {
  408. DPFERR("OpenEvent() failed");
  409. dwError = GetLastError();
  410. DNASSERT(FALSE);
  411. UnmapViewOfFile(pSharedBlock);
  412. DNCloseHandle(hFileMap);
  413. return(DPNERR_GENERIC);
  414. }
  415. DPFX(DPFPREP, 5,"Opened sync event");
  416. DNResetEvent(pdpLobbyObject->hConnectEvent);
  417. // Look for lobby launch -- set lobby launch value if connection is received
  418. pdpLobbyObject->dwFlags |= DPL_OBJECT_FLAG_LOOKINGFORLOBBYLAUNCH;
  419. // Make application available for connection by lobby client
  420. DNASSERT(pdpLobbyObject->pReceiveQueue != NULL);
  421. // Signal lobby client
  422. pSharedBlock->dwPID = pdpLobbyObject->dwPID;
  423. DNSetEvent(hSyncEvent);
  424. dwReturnValue = DNWaitForSingleObject(pdpLobbyObject->hConnectEvent,DPL_LOBBYLAUNCHED_CONNECT_TIMEOUT);
  425. // Turn off the looking for lobby launch flag
  426. pdpLobbyObject->dwFlags &= ~(DPL_OBJECT_FLAG_LOOKINGFORLOBBYLAUNCH);
  427. if (dwReturnValue == WAIT_OBJECT_0)
  428. {
  429. hResultCode = DPN_OK;
  430. }
  431. else
  432. {
  433. hResultCode = DPNERR_TIMEDOUT;
  434. }
  435. // Clean up
  436. DNCloseHandle(hSyncEvent);
  437. UnmapViewOfFile(pSharedBlock);
  438. DNCloseHandle(hFileMap);
  439. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  440. return(hResultCode);
  441. }
  442. //------------------------------------------------------------------------