Source code of Windows XP (NT5)
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.

1792 lines
58 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: DNLClient.cpp
  6. * Content: DirectNet Lobby Client 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/05/2000 jtk Changed GetValueSize to GetValueLength
  14. * 04/13/00 rmt First pass param validation
  15. * 04/25/2000 rmt Bug #s 33138, 33145, 33150
  16. * 04/26/00 mjn Removed dwTimeOut from Send() API call
  17. * 05/01/2000 rmt Bug #33678
  18. * 05/03/00 rmt Bug #33879 -- Status messsage missing from field
  19. * 05/30/00 rmt Bug #35618 -- ConnectApp with ShortTimeout returns DPN_OK
  20. * 06/07/00 rmt Bug #36452 -- Calling ConnectApplication twice could result in disconnection
  21. * 06/15/00 rmt Bug #33617 - Must provide method for providing automatic launch of DirectPlay instances
  22. * 07/06/00 rmt Updated for new registry parameters
  23. * 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched
  24. * rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns
  25. * rmt Bug #38755 - No way to specify player name in Connection Settings
  26. * rmt Bug #38758 - DPLOBBY8.H has incorrect comments
  27. * rmt Bug #38783 - pvUserApplicationContext is only partially implemented
  28. * rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs).
  29. * 07/14/2000 rmt Bug #39257 - LobbyClient::ReleaseApp returns E_OUTOFMEMORY when called when no one connected
  30. * 07/21/2000 rmt Bug #39578 - LobbyClient sample errors and quits -- memory corruption due to length vs. size problem
  31. * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  32. * 12/15/2000 rmt Bug #48445 - Specifying empty launcher name results in error
  33. * 04/19/2001 simonpow Bug #369842 - Altered CreateProcess calls to take app name and cmd
  34. * line as 2 separate arguments rather than one.
  35. * 06/16/2001 rodtoll WINBUG #416983 - RC1: World has full control to HKLM\Software\Microsoft\DirectPlay\Applications on Personal
  36. * Implementing mirror of keys into HKCU. Algorithm is now:
  37. * - Read of entries tries HKCU first, then HKLM
  38. * - Enum of entires is combination of HKCU and HKLM entries with duplicates removed. HKCU takes priority.
  39. * - Write of entries is HKLM and HKCU. (HKLM may fail, but is ignored).
  40. *@@END_MSINTERNAL
  41. *
  42. ***************************************************************************/
  43. #include "dnlobbyi.h"
  44. //**********************************************************************
  45. // Constant definitions
  46. //**********************************************************************
  47. //**********************************************************************
  48. // Macro definitions
  49. //**********************************************************************
  50. //**********************************************************************
  51. // Structure definitions
  52. //**********************************************************************
  53. //**********************************************************************
  54. // Variable definitions
  55. //**********************************************************************
  56. typedef STDMETHODIMP ClientQueryInterface(IDirectPlay8LobbyClient *pInterface,REFIID ridd,PVOID *ppvObj);
  57. typedef STDMETHODIMP_(ULONG) ClientAddRef(IDirectPlay8LobbyClient *pInterface);
  58. typedef STDMETHODIMP_(ULONG) ClientRelease(IDirectPlay8LobbyClient *pInterface);
  59. typedef STDMETHODIMP ClientRegisterMessageHandler(IDirectPlay8LobbyClient *pInterface,const PVOID pvUserContext,const PFNDPNMESSAGEHANDLER pfn,const DWORD dwFlags);
  60. typedef STDMETHODIMP ClientSend(IDirectPlay8LobbyClient *pInterface,const DPNHANDLE hTarget,BYTE *const pBuffer,const DWORD pBufferSize,const DWORD dwFlags);
  61. typedef STDMETHODIMP ClientClose(IDirectPlay8LobbyClient *pInterface,const DWORD dwFlags);
  62. typedef STDMETHODIMP ClientGetConnectionSettings(IDirectPlay8LobbyClient *pInterface, const DPNHANDLE hLobbyClient, DPL_CONNECTION_SETTINGS * const pdplSessionInfo, DWORD *pdwInfoSize, const DWORD dwFlags );
  63. typedef STDMETHODIMP ClientSetConnectionSettings(IDirectPlay8LobbyClient *pInterface, const DPNHANDLE hTarget, const DPL_CONNECTION_SETTINGS * const pdplSessionInfo, const DWORD dwFlags );
  64. IDirectPlay8LobbyClientVtbl DPL_Lobby8ClientVtbl =
  65. {
  66. (ClientQueryInterface*) DPL_QueryInterface,
  67. (ClientAddRef*) DPL_AddRef,
  68. (ClientRelease*) DPL_Release,
  69. (ClientRegisterMessageHandler*) DPL_RegisterMessageHandlerClient,
  70. DPL_EnumLocalPrograms,
  71. DPL_ConnectApplication,
  72. (ClientSend*) DPL_Send,
  73. DPL_ReleaseApplication,
  74. (ClientClose*) DPL_Close,
  75. (ClientGetConnectionSettings*) DPL_GetConnectionSettings,
  76. (ClientSetConnectionSettings*) DPL_SetConnectionSettings
  77. };
  78. //**********************************************************************
  79. // Function prototypes
  80. //**********************************************************************
  81. //**********************************************************************
  82. // Function definitions
  83. //**********************************************************************
  84. #define DPL_ENUM_APPGUID_BUFFER_INITIAL 8
  85. #define DPL_ENUM_APPGUID_BUFFER_GROWBY 4
  86. #undef DPF_MODNAME
  87. #define DPF_MODNAME "DPL_EnumLocalPrograms"
  88. STDMETHODIMP DPL_EnumLocalPrograms(IDirectPlay8LobbyClient *pInterface,
  89. GUID *const pGuidApplication,
  90. BYTE *const pEnumData,
  91. DWORD *const pdwEnumDataSize,
  92. DWORD *const pdwEnumDataItems,
  93. const DWORD dwFlags )
  94. {
  95. HRESULT hResultCode;
  96. CMessageQueue MessageQueue;
  97. CPackedBuffer PackedBuffer;
  98. CRegistry RegistryEntry;
  99. CRegistry SubEntry;
  100. DWORD dwSizeRequired;
  101. DWORD dwMaxKeyLen;
  102. PWSTR pwszKeyName = NULL;
  103. // Application name variables
  104. PWSTR pwszApplicationName = NULL;
  105. DWORD dwMaxApplicationNameLength; // Includes null terminator
  106. DWORD dwApplicationNameLength; // Includes null terminator
  107. // Executable name variables
  108. PWSTR pwszExecutableFilename = NULL;
  109. DWORD dwMaxExecutableFilenameLength; // Includes null terminator
  110. DWORD dwExecutableFilenameLength; // Includes null terminator
  111. DWORD *pdwPID;
  112. DWORD dwMaxPID;
  113. DWORD dwNumPID;
  114. DWORD dwEnumIndex;
  115. DWORD dwEnumCount;
  116. DWORD dwKeyLen;
  117. DWORD dw;
  118. DPL_APPLICATION_INFO dplAppInfo;
  119. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  120. GUID *pAppLoadedList = NULL; // List of GUIDs of app's we've enumerated
  121. DWORD dwSizeAppLoadedList = 0; // size of list pAppLoadedList
  122. DWORD dwLengthAppLoadedList = 0; // # of elements in list
  123. HKEY hkCurrentBranch = HKEY_LOCAL_MACHINE;
  124. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pGuidApplication [0x%p], pEnumData [0x%p], pdwEnumDataSize [0x%p], pdwEnumDataItems [0x%p], dwFlags [0x%lx]",
  125. pInterface,pGuidApplication,pEnumData,pdwEnumDataSize,pdwEnumDataItems,dwFlags);
  126. TRY
  127. {
  128. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  129. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  130. {
  131. if( FAILED( hResultCode = DPL_ValidateEnumLocalPrograms( pInterface, pGuidApplication, pEnumData, pdwEnumDataSize, pdwEnumDataItems, dwFlags ) ) )
  132. {
  133. DPFX(DPFPREP, 0, "Error validating enum local programs params hr=[0x%lx]", hResultCode );
  134. DPF_RETURN( hResultCode );
  135. }
  136. }
  137. // Ensure we've been initialized
  138. if (pdpLobbyObject->pReceiveQueue == NULL)
  139. {
  140. DPFERR("Not initialized");
  141. DPF_RETURN(DPNERR_UNINITIALIZED);
  142. }
  143. }
  144. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  145. {
  146. DPFERR("Invalid object" );
  147. DPF_RETURN(DPNERR_INVALIDOBJECT);
  148. }
  149. dwSizeRequired = *pdwEnumDataSize;
  150. PackedBuffer.Initialize(pEnumData,dwSizeRequired);
  151. pwszApplicationName = NULL;
  152. pwszExecutableFilename = NULL;
  153. pdwPID = NULL;
  154. dwMaxPID = 0;
  155. dwLengthAppLoadedList = 0;
  156. dwSizeAppLoadedList = DPL_ENUM_APPGUID_BUFFER_INITIAL;
  157. pAppLoadedList = static_cast<GUID*>(DNMalloc(sizeof(GUID)*dwSizeAppLoadedList));
  158. if( !pAppLoadedList )
  159. {
  160. DPFERR("Failed allocating memory" );
  161. hResultCode = DPNERR_OUTOFMEMORY;
  162. goto EXIT_DPL_EnumLocalPrograms;
  163. }
  164. dwEnumCount = 0;
  165. for( DWORD dwIndex = 0; dwIndex < 2; dwIndex++ )
  166. {
  167. if( dwIndex == 0 )
  168. {
  169. hkCurrentBranch = HKEY_CURRENT_USER;
  170. }
  171. else
  172. {
  173. hkCurrentBranch = HKEY_LOCAL_MACHINE;
  174. }
  175. if (!RegistryEntry.Open(hkCurrentBranch,DPL_REG_LOCAL_APPL_SUBKEY,TRUE,FALSE,TRUE,DPL_REGISTRY_READ_ACCESS))
  176. {
  177. DPFX(DPFPREP,1,"On pass %i could not find app key", dwIndex);
  178. continue;
  179. }
  180. // Set up to enumerate
  181. if (!RegistryEntry.GetMaxKeyLen(dwMaxKeyLen))
  182. {
  183. DPFERR("RegistryEntry.GetMaxKeyLen() failed");
  184. hResultCode = DPNERR_GENERIC;
  185. goto EXIT_DPL_EnumLocalPrograms;
  186. }
  187. dwMaxKeyLen++; // Null terminator
  188. DPFX(DPFPREP, 7,"dwMaxKeyLen = %ld",dwMaxKeyLen);
  189. if ((pwszKeyName = static_cast<WCHAR*>(DNMalloc(dwMaxKeyLen*sizeof(WCHAR)))) == NULL)
  190. {
  191. DPFERR("DNMalloc() failed");
  192. hResultCode = DPNERR_OUTOFMEMORY;
  193. goto EXIT_DPL_EnumLocalPrograms;
  194. }
  195. dwMaxApplicationNameLength = dwMaxKeyLen * sizeof(WCHAR);
  196. dwMaxExecutableFilenameLength = dwMaxApplicationNameLength;
  197. if ((pwszApplicationName = static_cast<WCHAR*>(DNMalloc(dwMaxApplicationNameLength*sizeof(WCHAR)))) == NULL) // Seed Application name size
  198. {
  199. DPFERR("DNMalloc() failed");
  200. hResultCode = DPNERR_OUTOFMEMORY;
  201. goto EXIT_DPL_EnumLocalPrograms;
  202. }
  203. if ((pwszExecutableFilename = static_cast<WCHAR*>(DNMalloc(dwMaxExecutableFilenameLength*sizeof(WCHAR)))) == NULL)
  204. {
  205. DPFERR("DNMalloc() failed");
  206. hResultCode = DPNERR_OUTOFMEMORY;
  207. goto EXIT_DPL_EnumLocalPrograms;
  208. }
  209. dwEnumIndex = 0;
  210. dwKeyLen = dwMaxKeyLen;
  211. // Enumerate !
  212. while (RegistryEntry.EnumKeys(pwszKeyName,&dwKeyLen,dwEnumIndex))
  213. {
  214. DPFX(DPFPREP, 7,"%ld - %S (%ld)",dwEnumIndex,pwszKeyName,dwKeyLen);
  215. // Get Application name and GUID from each sub key
  216. if (!SubEntry.Open(RegistryEntry,pwszKeyName,TRUE,FALSE))
  217. {
  218. DPFX(DPFPREP, 7,"skipping %S",pwszKeyName);
  219. goto LOOP_END;
  220. }
  221. //
  222. // Minara, double-check size vs. length for names
  223. //
  224. if (!SubEntry.GetValueLength(DPL_REG_KEYNAME_APPLICATIONNAME,&dwApplicationNameLength))
  225. {
  226. DPFX(DPFPREP, 7,"Could not get ApplicationName size. Skipping [%S]",pwszKeyName);
  227. goto LOOP_END;
  228. }
  229. // To include null terminator
  230. dwApplicationNameLength++;
  231. if (dwApplicationNameLength > dwMaxApplicationNameLength)
  232. {
  233. // grow buffer (taking into account that the reg functions always return WCHAR) and try again
  234. DPFX(DPFPREP, 7,"Need to grow pwszApplicationName from %ld to %ld",dwMaxApplicationNameLength,dwApplicationNameLength);
  235. if (pwszApplicationName != NULL)
  236. {
  237. DNFree(pwszApplicationName);
  238. pwszApplicationName = NULL;
  239. }
  240. if ((pwszApplicationName = static_cast<WCHAR*>(DNMalloc(dwApplicationNameLength*sizeof(WCHAR)))) == NULL)
  241. {
  242. DPFERR("DNMalloc() failed");
  243. hResultCode = DPNERR_OUTOFMEMORY;
  244. goto EXIT_DPL_EnumLocalPrograms;
  245. }
  246. dwMaxApplicationNameLength = dwApplicationNameLength;
  247. }
  248. if (!SubEntry.ReadString(DPL_REG_KEYNAME_APPLICATIONNAME,pwszApplicationName,&dwApplicationNameLength))
  249. {
  250. DPFX(DPFPREP, 7,"Could not read ApplicationName. Skipping [%S]",pwszKeyName);
  251. goto LOOP_END;
  252. }
  253. DPFX(DPFPREP, 7,"ApplicationName = %S (%ld WCHARs)",pwszApplicationName,dwApplicationNameLength);
  254. if (!SubEntry.ReadGUID(DPL_REG_KEYNAME_GUID,dplAppInfo.guidApplication))
  255. {
  256. DPFERR("SubEntry.ReadGUID failed - skipping entry");
  257. goto LOOP_END;
  258. }
  259. for( DWORD dwGuidSearchIndex = 0; dwGuidSearchIndex < dwLengthAppLoadedList; dwGuidSearchIndex++ )
  260. {
  261. if( pAppLoadedList[dwGuidSearchIndex] == dplAppInfo.guidApplication )
  262. {
  263. DPFX(DPFPREP, 1, "Ignoring local machine entry for current user version of entry [%S]", pwszApplicationName );
  264. goto LOOP_END;
  265. }
  266. }
  267. if ((pGuidApplication == NULL) || (*pGuidApplication == dplAppInfo.guidApplication))
  268. {
  269. // Get process count - need executable filename
  270. //
  271. // Minara, check size vs. length
  272. //
  273. if (!SubEntry.GetValueLength(DPL_REG_KEYNAME_EXECUTABLEFILENAME,&dwExecutableFilenameLength))
  274. {
  275. DPFX(DPFPREP, 7,"Could not get ExecutableFilename size. Skipping [%S]",pwszKeyName);
  276. goto LOOP_END;
  277. }
  278. // So we include null terminator
  279. dwExecutableFilenameLength++;
  280. if (dwExecutableFilenameLength > dwMaxExecutableFilenameLength)
  281. {
  282. // grow buffer (noting that all strings from the registry are WCHAR) and try again
  283. DPFX(DPFPREP, 7,"Need to grow pwszExecutableFilename from %ld to %ld",dwMaxExecutableFilenameLength,dwExecutableFilenameLength);
  284. if (pwszExecutableFilename != NULL)
  285. {
  286. DNFree(pwszExecutableFilename);
  287. pwszExecutableFilename = NULL;
  288. }
  289. if ((pwszExecutableFilename = static_cast<WCHAR*>(DNMalloc(dwExecutableFilenameLength*sizeof(WCHAR)))) == NULL)
  290. {
  291. DPFERR("DNMalloc() failed");
  292. hResultCode = DPNERR_OUTOFMEMORY;
  293. goto EXIT_DPL_EnumLocalPrograms;
  294. }
  295. dwMaxExecutableFilenameLength = dwExecutableFilenameLength;
  296. }
  297. if (!SubEntry.ReadString(DPL_REG_KEYNAME_EXECUTABLEFILENAME,pwszExecutableFilename,&dwExecutableFilenameLength))
  298. {
  299. DPFX(DPFPREP, 7,"Could not read ExecutableFilename. Skipping [%S]",pwszKeyName);
  300. goto LOOP_END;
  301. }
  302. DPFX(DPFPREP, 7,"ExecutableFilename [%S]",pwszExecutableFilename);
  303. // Count running apps
  304. dwNumPID = dwMaxPID;
  305. while ((hResultCode = DPLGetProcessList(pwszExecutableFilename,pdwPID,&dwNumPID,
  306. pdpLobbyObject->bIsUnicodePlatform)) == DPNERR_BUFFERTOOSMALL)
  307. {
  308. if (pdwPID)
  309. {
  310. DNFree(pdwPID);
  311. pdwPID = NULL;
  312. }
  313. dwMaxPID = dwNumPID;
  314. if ((pdwPID = static_cast<DWORD*>(DNMalloc(dwNumPID*sizeof(DWORD)))) == NULL)
  315. {
  316. DPFERR("DNMalloc() failed");
  317. hResultCode = DPNERR_OUTOFMEMORY;
  318. goto EXIT_DPL_EnumLocalPrograms;
  319. }
  320. }
  321. if (hResultCode != DPN_OK)
  322. {
  323. DPFERR("DPLGetProcessList() failed");
  324. DisplayDNError(0,hResultCode);
  325. hResultCode = DPNERR_GENERIC;
  326. goto EXIT_DPL_EnumLocalPrograms;
  327. }
  328. // Count waiting apps
  329. dplAppInfo.dwNumWaiting = 0;
  330. for (dw = 0 ; dw < dwNumPID ; dw++)
  331. {
  332. if ((hResultCode = MessageQueue.Open( pdwPID[dw],
  333. DPL_MSGQ_OBJECT_SUFFIX_APPLICATION,
  334. DPL_MSGQ_SIZE,
  335. DPL_MSGQ_OPEN_FLAG_NO_CREATE, INFINITE)) == DPN_OK)
  336. {
  337. if (MessageQueue.IsAvailable())
  338. {
  339. dplAppInfo.dwNumWaiting++;
  340. }
  341. MessageQueue.Close();
  342. }
  343. }
  344. hResultCode = PackedBuffer.AddWCHARStringToBack(pwszApplicationName);
  345. dplAppInfo.pwszApplicationName = (PWSTR)(PackedBuffer.GetTailAddress());
  346. dplAppInfo.dwFlags = 0;
  347. dplAppInfo.dwNumRunning = dwNumPID;
  348. hResultCode = PackedBuffer.AddToFront(&dplAppInfo,sizeof(DPL_APPLICATION_INFO));
  349. if( dwLengthAppLoadedList+1 > dwSizeAppLoadedList )
  350. {
  351. GUID *pTmpArray = NULL;
  352. pTmpArray = static_cast<GUID*>(DNMalloc(sizeof(GUID)*(dwSizeAppLoadedList+DPL_ENUM_APPGUID_BUFFER_GROWBY)));
  353. if( !pTmpArray )
  354. {
  355. DPFERR("DNMalloc() failed");
  356. hResultCode = DPNERR_OUTOFMEMORY;
  357. goto EXIT_DPL_EnumLocalPrograms;
  358. }
  359. memcpy( pTmpArray, pAppLoadedList, sizeof(GUID)*dwLengthAppLoadedList);
  360. dwSizeAppLoadedList += DPL_ENUM_APPGUID_BUFFER_GROWBY;
  361. DNFree(pAppLoadedList);
  362. pAppLoadedList = pTmpArray;
  363. }
  364. pAppLoadedList[dwLengthAppLoadedList] = dplAppInfo.guidApplication;
  365. dwLengthAppLoadedList++;
  366. dwEnumCount++;
  367. }
  368. LOOP_END:
  369. SubEntry.Close();
  370. dwEnumIndex++;
  371. dwKeyLen = dwMaxKeyLen;
  372. }
  373. RegistryEntry.Close();
  374. if( pwszKeyName )
  375. {
  376. DNFree(pwszKeyName);
  377. pwszKeyName= NULL;
  378. }
  379. if( pwszApplicationName )
  380. {
  381. DNFree(pwszApplicationName);
  382. pwszApplicationName = NULL;
  383. }
  384. if( pwszExecutableFilename )
  385. {
  386. DNFree(pwszExecutableFilename);
  387. pwszExecutableFilename = NULL;
  388. }
  389. }
  390. dwSizeRequired = PackedBuffer.GetSizeRequired();
  391. if (dwSizeRequired > *pdwEnumDataSize)
  392. {
  393. DPFX(DPFPREP, 7,"Buffer too small");
  394. *pdwEnumDataSize = dwSizeRequired;
  395. hResultCode = DPNERR_BUFFERTOOSMALL;
  396. }
  397. else
  398. {
  399. *pdwEnumDataItems = dwEnumCount;
  400. }
  401. if( pGuidApplication != NULL && dwEnumCount == 0 )
  402. {
  403. DPFX(DPFPREP, 0, "Specified application was not registered" );
  404. hResultCode = DPNERR_DOESNOTEXIST;
  405. }
  406. EXIT_DPL_EnumLocalPrograms:
  407. if (pwszKeyName != NULL)
  408. DNFree(pwszKeyName);
  409. if (pwszApplicationName != NULL)
  410. DNFree(pwszApplicationName);
  411. if (pwszExecutableFilename != NULL)
  412. DNFree(pwszExecutableFilename);
  413. if (pdwPID != NULL)
  414. DNFree(pdwPID);
  415. if( pAppLoadedList )
  416. DNFree(pAppLoadedList);
  417. DPF_RETURN(hResultCode);
  418. }
  419. // DPL_ConnectApplication
  420. //
  421. // Try to connect to a lobbied application. Based on DPL_CONNECT_INFO flags,
  422. // we may have to launch an application.
  423. //
  424. // If we have to launch an application, we will need to handshake the PID of the
  425. // application (as it may be ripple launched). We will pass the LobbyClient's PID on the
  426. // command line to the application launcher and expect it to be passed down to the
  427. // application. The application will open a named shared memory block using the PID and
  428. // write its PID there, and then signal a named event (using the LobbyClient's PID again).
  429. // When the waiting LobbyClient is signaled by this event, it continues its connection
  430. // process as if this was an existing running and available application.
  431. #undef DPF_MODNAME
  432. #define DPF_MODNAME "DPL_ConnectApplication"
  433. STDMETHODIMP DPL_ConnectApplication(IDirectPlay8LobbyClient *pInterface,
  434. DPL_CONNECT_INFO *const pdplConnectInfo,
  435. void *pvConnectionContext,
  436. DPNHANDLE *const hApplication,
  437. const DWORD dwTimeOut,
  438. const DWORD dwFlags)
  439. {
  440. HRESULT hResultCode = DPN_OK;
  441. DWORD dwSize = 0;
  442. BYTE *pBuffer = NULL;
  443. DPL_PROGRAM_DESC *pdplProgramDesc;
  444. DWORD *pdwProcessList = NULL;
  445. DWORD dwNumProcesses = 0;
  446. DWORD dwPID = 0;
  447. DWORD dw = 0;
  448. DPNHANDLE handle = NULL;
  449. DPL_CONNECTION *pdplConnection = NULL;
  450. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject = NULL;
  451. DPFX(DPFPREP, 3,"Parameters: pdplConnectInfo [0x%p], pvUserAppContext [0x%p], hApplication [0x%lx], dwFlags [0x%lx]",
  452. pdplConnectInfo,pvConnectionContext,hApplication,dwFlags);
  453. TRY
  454. {
  455. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  456. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  457. {
  458. if( FAILED( hResultCode = DPL_ValidateConnectApplication( pInterface, pdplConnectInfo, pvConnectionContext, hApplication, dwTimeOut, dwFlags ) ) )
  459. {
  460. DPFX(DPFPREP, 0, "Error validating connect application params hr=[0x%lx]", hResultCode );
  461. DPF_RETURN( hResultCode );
  462. }
  463. }
  464. // Ensure we've been initialized
  465. if (pdpLobbyObject->pReceiveQueue == NULL)
  466. {
  467. DPFERR("Not initialized");
  468. DPF_RETURN(DPNERR_UNINITIALIZED);
  469. }
  470. }
  471. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  472. {
  473. DPFERR("Invalid object" );
  474. DPF_RETURN(DPNERR_INVALIDOBJECT);
  475. }
  476. // Get program description
  477. dwSize = 0;
  478. pBuffer = NULL;
  479. hResultCode = DPLGetProgramDesc(&pdplConnectInfo->guidApplication,pBuffer,&dwSize);
  480. if (hResultCode != DPNERR_BUFFERTOOSMALL)
  481. {
  482. DPFERR("Could not get Program Description");
  483. goto EXIT_DPL_ConnectApplication;
  484. }
  485. if ((pBuffer = static_cast<BYTE*>(DNMalloc(dwSize))) == NULL)
  486. {
  487. DPFERR("Could not allocate space for buffer");
  488. hResultCode = DPNERR_OUTOFMEMORY;
  489. goto EXIT_DPL_ConnectApplication;
  490. }
  491. if ((hResultCode = DPLGetProgramDesc(&pdplConnectInfo->guidApplication,pBuffer,&dwSize)) != DPN_OK)
  492. {
  493. DPFERR("Could not get Program Description");
  494. DisplayDNError(0,hResultCode);
  495. goto EXIT_DPL_ConnectApplication;
  496. }
  497. pdplProgramDesc = reinterpret_cast<DPL_PROGRAM_DESC*>(pBuffer);
  498. dwPID = 0;
  499. dwNumProcesses = 0;
  500. pdwProcessList = NULL;
  501. if (!(pdplConnectInfo->dwFlags & DPLCONNECT_LAUNCHNEW)) // Only if not forcing launch
  502. {
  503. // Get process list
  504. hResultCode = DPLGetProcessList(pdplProgramDesc->pwszExecutableFilename,NULL,&dwNumProcesses,
  505. pdpLobbyObject->bIsUnicodePlatform);
  506. if (hResultCode != DPN_OK && hResultCode != DPNERR_BUFFERTOOSMALL)
  507. {
  508. DPFERR("Could not retrieve process list");
  509. DisplayDNError(0,hResultCode);
  510. goto EXIT_DPL_ConnectApplication;
  511. }
  512. if (hResultCode == DPNERR_BUFFERTOOSMALL)
  513. {
  514. if ((pdwProcessList = static_cast<DWORD*>(DNMalloc(dwNumProcesses*sizeof(DWORD)))) == NULL)
  515. {
  516. DPFERR("Could not create process list buffer");
  517. hResultCode = DPNERR_OUTOFMEMORY;
  518. goto EXIT_DPL_ConnectApplication;
  519. }
  520. if ((hResultCode = DPLGetProcessList(pdplProgramDesc->pwszExecutableFilename,pdwProcessList,
  521. &dwNumProcesses,pdpLobbyObject->bIsUnicodePlatform)) != DPN_OK)
  522. {
  523. DPFERR("Could not get process list");
  524. DisplayDNError(0,hResultCode);
  525. goto EXIT_DPL_ConnectApplication;
  526. }
  527. }
  528. // Try to connect to an already running application
  529. for (dw = 0 ; dw < dwNumProcesses ; dw++)
  530. {
  531. if ((hResultCode = DPLMakeApplicationUnavailable(pdwProcessList[dw])) == DPN_OK)
  532. {
  533. DPFX(DPFPREP, 1, "Found Existing Process=%d", pdwProcessList[dw] );
  534. dwPID = pdwProcessList[dw];
  535. break;
  536. }
  537. }
  538. if (pdwProcessList)
  539. {
  540. DNFree(pdwProcessList);
  541. pdwProcessList = NULL;
  542. }
  543. }
  544. // Launch application if none are ready to connect
  545. if ((dwPID == 0) && (pdplConnectInfo->dwFlags & (DPLCONNECT_LAUNCHNEW | DPLCONNECT_LAUNCHNOTFOUND)))
  546. {
  547. if ((hResultCode = DPLLaunchApplication(pdpLobbyObject,pdplProgramDesc,&dwPID,dwTimeOut)) != DPN_OK)
  548. {
  549. DPFERR("Could not launch application");
  550. DisplayDNError(0,hResultCode);
  551. goto EXIT_DPL_ConnectApplication;
  552. }
  553. else
  554. {
  555. DPFX(DPFPREP, 1, "Launched process dwID=%d", dwPID );
  556. }
  557. }
  558. if (dwPID == 0) // Could not make any connection
  559. {
  560. DPFERR("Could not connect to an existing application or launch a new one");
  561. hResultCode = DPNERR_NOCONNECTION;
  562. DisplayDNError( 0, hResultCode );
  563. goto EXIT_DPL_ConnectApplication;
  564. }
  565. handle = NULL;
  566. // Create connection
  567. if ((hResultCode = DPLConnectionNew(pdpLobbyObject,&handle,&pdplConnection)) != DPN_OK)
  568. {
  569. DPFERR("Could not create connection entry");
  570. DisplayDNError(0,hResultCode);
  571. goto EXIT_DPL_ConnectApplication;
  572. }
  573. pdplConnection->dwTargetPID = dwPID;
  574. DPFX(DPFPREP, 0, "PID=%d", dwPID );
  575. // Set the context for this connection
  576. if ((hResultCode = DPLConnectionSetContext( pdpLobbyObject, handle, pvConnectionContext )) != DPN_OK )
  577. {
  578. DPFERR( "Could not set contect for connection" );
  579. DisplayDNError(0,hResultCode);
  580. goto EXIT_DPL_ConnectApplication;
  581. }
  582. // Connect to selected application instance
  583. if ((hResultCode = DPLConnectionConnect(pdpLobbyObject,handle,dwPID,TRUE)) != DPN_OK)
  584. {
  585. DPFERR("Could not connect to application");
  586. DisplayDNError(0,hResultCode);
  587. goto EXIT_DPL_ConnectApplication;
  588. }
  589. ResetEvent(pdplConnection->hConnectEvent);
  590. // Pass lobby client info to application
  591. if ((hResultCode = DPLConnectionSendREQ(pdpLobbyObject,handle,pdpLobbyObject->dwPID,
  592. pdplConnectInfo)) != DPN_OK)
  593. {
  594. DPFERR("Could not send connection request");
  595. DisplayDNError(0,hResultCode);
  596. goto EXIT_DPL_ConnectApplication;
  597. }
  598. if (WaitForSingleObject(pdplConnection->hConnectEvent,INFINITE) != WAIT_OBJECT_0)
  599. {
  600. DPFERR("Wait for connection terminated");
  601. hResultCode = DPNERR_GENERIC;
  602. goto EXIT_DPL_ConnectApplication;
  603. }
  604. *hApplication = handle;
  605. hResultCode = DPN_OK;
  606. EXIT_DPL_ConnectApplication:
  607. if( FAILED(hResultCode) && handle )
  608. {
  609. DPLConnectionDisconnect(pdpLobbyObject,handle);
  610. DPLConnectionRelease(pdpLobbyObject,handle);
  611. }
  612. if (pBuffer)
  613. DNFree(pBuffer);
  614. if (pdwProcessList)
  615. DNFree(pdwProcessList);
  616. DPF_RETURN(hResultCode);
  617. }
  618. #undef DPF_MODNAME
  619. #define DPF_MODNAME "DPL_ReleaseApplication"
  620. STDMETHODIMP DPL_ReleaseApplication(IDirectPlay8LobbyClient *pInterface,
  621. const DPNHANDLE hApplication,
  622. const DWORD dwFlags )
  623. {
  624. HRESULT hResultCode;
  625. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  626. DPNHANDLE *hTargets = NULL;
  627. DWORD dwNumTargets = 0;
  628. DWORD dwTargetIndex = 0;
  629. DPFX(DPFPREP, 3,"Parameters: hApplication [0x%lx]",hApplication);
  630. TRY
  631. {
  632. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  633. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  634. {
  635. if( FAILED( hResultCode = DPL_ValidateReleaseApplication( pInterface, hApplication, dwFlags ) ) )
  636. {
  637. DPFX(DPFPREP, 0, "Error validating release application params hr=[0x%lx]", hResultCode );
  638. DPF_RETURN( hResultCode );
  639. }
  640. }
  641. // Ensure we've been initialized
  642. if (pdpLobbyObject->pReceiveQueue == NULL)
  643. {
  644. DPFERR("Not initialized");
  645. DPF_RETURN(DPNERR_UNINITIALIZED);
  646. }
  647. }
  648. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  649. {
  650. DPFERR("Invalid object" );
  651. DPF_RETURN(DPNERR_INVALIDOBJECT);
  652. }
  653. if( hApplication == DPLHANDLE_ALLCONNECTIONS )
  654. {
  655. dwNumTargets = 0;
  656. // We need loop so if someone adds a connection during our run
  657. // it gets added to our list
  658. //
  659. while( 1 )
  660. {
  661. hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
  662. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  663. {
  664. if( hTargets )
  665. {
  666. delete [] hTargets;
  667. }
  668. hTargets = new DPNHANDLE[dwNumTargets];
  669. if( hTargets == NULL )
  670. {
  671. DPFERR("Error allocating memory" );
  672. hResultCode = DPNERR_OUTOFMEMORY;
  673. dwNumTargets = 0;
  674. goto EXIT_AND_CLEANUP;
  675. }
  676. memset( hTargets, 0x00, sizeof(DPNHANDLE)*dwNumTargets);
  677. continue;
  678. }
  679. else if( FAILED( hResultCode ) )
  680. {
  681. DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode );
  682. break;
  683. }
  684. else
  685. {
  686. break;
  687. }
  688. }
  689. // Failed getting connection information
  690. if( FAILED( hResultCode ) )
  691. {
  692. if( hTargets )
  693. {
  694. delete [] hTargets;
  695. hTargets = NULL;
  696. }
  697. dwNumTargets = 0;
  698. goto EXIT_AND_CLEANUP;
  699. }
  700. }
  701. else
  702. {
  703. hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
  704. if( hTargets == NULL )
  705. {
  706. DPFERR("Error allocating memory" );
  707. hResultCode = DPNERR_OUTOFMEMORY;
  708. dwNumTargets = 0;
  709. goto EXIT_AND_CLEANUP;
  710. }
  711. dwNumTargets = 1;
  712. hTargets[0] = hApplication;
  713. }
  714. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  715. {
  716. hResultCode = DPLConnectionDisconnect(pdpLobbyObject,hTargets[dwTargetIndex]);
  717. if( FAILED( hResultCode ) )
  718. {
  719. DPFX(DPFPREP, 0, "Error disconnecting connection 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  720. }
  721. }
  722. EXIT_AND_CLEANUP:
  723. if( hTargets )
  724. delete [] hTargets;
  725. DPF_RETURN(hResultCode);
  726. }
  727. // DPLLaunchApplication
  728. //
  729. // Launch the application with a command-line argument of:
  730. // DPLID=PIDn PID=Lobby Client PID, n=launch counter (each launch increases it)
  731. // Wait for the application to signal the event (or die)
  732. #undef DPF_MODNAME
  733. #define DPF_MODNAME "DPLLaunchApplication"
  734. HRESULT DPLLaunchApplication(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  735. DPL_PROGRAM_DESC *const pdplProgramDesc,
  736. DWORD *const pdwPID,
  737. const DWORD dwTimeOut)
  738. {
  739. HRESULT hResultCode;
  740. DWORD dwAppNameLen=0; //Length of the application full name (path+exe)
  741. PWSTR pwszAppName=NULL; //Unicode version of application full name
  742. DWORD dwCmdLineLen=0; //Length of the command line string
  743. PWSTR pwszCmdLine=NULL; //Unicode version of command line to supply
  744. CHAR * pszAppName=NULL; //Ascii version of application full name
  745. CHAR * pszCmdLine=NULL; //Acii version of command line string
  746. LONG lc;
  747. STARTUPINFOW siW; // Unicode startup info (place holder)
  748. STARTUPINFOA siA;
  749. PROCESS_INFORMATION pi;
  750. DWORD dwError;
  751. HANDLE hSyncEvents[2] = { NULL, NULL };
  752. WCHAR pwszObjectName[(sizeof(DWORD)*2)*2 + 1];
  753. CHAR pszObjectName[(sizeof(DWORD)*2)*2 + 1 + 1];
  754. DPL_SHARED_CONNECT_BLOCK *pSharedBlock = NULL;
  755. HANDLE hFileMap = NULL;
  756. DWORD dwPID;
  757. CHAR *pszDefaultDir = NULL;
  758. WCHAR *wszToLaunchPath = NULL;
  759. WCHAR *wszToLaunchExecutable = NULL;
  760. DWORD dwToLaunchPathLen;
  761. // Are we launching the launcher or the executable?
  762. if( !pdplProgramDesc->pwszLauncherFilename || wcslen(pdplProgramDesc->pwszLauncherFilename) == 0 )
  763. {
  764. wszToLaunchPath = pdplProgramDesc->pwszExecutablePath;
  765. wszToLaunchExecutable = pdplProgramDesc->pwszExecutableFilename;
  766. }
  767. else
  768. {
  769. wszToLaunchPath = pdplProgramDesc->pwszLauncherPath;
  770. wszToLaunchExecutable = pdplProgramDesc->pwszLauncherFilename;
  771. }
  772. DPFX(DPFPREP, 3,"Parameters: pdplProgramDesc [0x%p]",pdplProgramDesc);
  773. DNASSERT(pdplProgramDesc != NULL);
  774. // Increment launch count
  775. lc = InterlockedIncrement(&pdpLobbyObject->lLaunchCount);
  776. // Synchronization event and shared memory names
  777. swprintf(pwszObjectName,L"%lx%lx",pdpLobbyObject->dwPID,lc);
  778. sprintf(pszObjectName,"-%lx%lx",pdpLobbyObject->dwPID,lc);
  779. // Compute the size of the full application name string (combination of path and exe name)
  780. if (wszToLaunchPath)
  781. dwAppNameLen += (wcslen(wszToLaunchPath) + 1);
  782. if (wszToLaunchExecutable)
  783. dwAppNameLen += (wcslen(wszToLaunchExecutable) + 1);
  784. // Compute the size of the command line string
  785. dwCmdLineLen=dwAppNameLen+1;
  786. if (pdplProgramDesc->pwszCommandLine)
  787. dwCmdLineLen += wcslen(pdplProgramDesc->pwszCommandLine);
  788. dwCmdLineLen += (1 + wcslen(DPL_ID_STR_W) + (sizeof(DWORD)*2*2) + 1);
  789. DPFX(DPFPREP, 5,"Application full name string length [%ld] WCHARs", dwAppNameLen);
  790. DPFX(DPFPREP, 5,"Command Line string length [%ld] WCHARs", dwCmdLineLen);
  791. // Allocate memory to hold the full app name and command line + check allocation was OK
  792. pwszAppName=static_cast<WCHAR *>(DNMalloc(dwAppNameLen * sizeof(WCHAR)));
  793. pwszCmdLine=static_cast<WCHAR *>(DNMalloc(dwCmdLineLen * sizeof(WCHAR)));
  794. if (pwszAppName==NULL || pwszCmdLine==NULL)
  795. {
  796. DPFERR("Could not allocate strings for app name and command line");
  797. hResultCode = DPNERR_OUTOFMEMORY;
  798. goto CLEANUP_DPLLaunch;
  799. }
  800. // Build the application full name by combining launch path with exe name
  801. *pwszAppName = L'\0';
  802. if (wszToLaunchPath)
  803. {
  804. dwToLaunchPathLen = wcslen(wszToLaunchPath);
  805. if (dwToLaunchPathLen > 0)
  806. {
  807. wcscat(pwszAppName,wszToLaunchPath);
  808. if (wszToLaunchPath[dwToLaunchPathLen - 1] != L'\\')
  809. {
  810. wcscat(pwszAppName,L"\\");
  811. }
  812. }
  813. }
  814. if (wszToLaunchExecutable)
  815. {
  816. wcscat(pwszAppName,wszToLaunchExecutable);
  817. }
  818. //Build the command line from app name, program description and the lobby related parameters
  819. wcscpy(pwszCmdLine, pwszAppName);
  820. wcscat(pwszCmdLine,L" ");
  821. if (pdplProgramDesc->pwszCommandLine)
  822. {
  823. wcscat(pwszCmdLine,pdplProgramDesc->pwszCommandLine);
  824. wcscat(pwszCmdLine,L" ");
  825. }
  826. wcscat(pwszCmdLine,DPL_ID_STR_W);
  827. wcscat(pwszCmdLine,pwszObjectName);
  828. DPFX(DPFPREP, 5,"Application full name string [%S]",pwszAppName);
  829. DPFX(DPFPREP, 5,"Command Line string [%S]",pwszCmdLine);
  830. // Create shared connect block to receive Application's PID
  831. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_FILEMAP;
  832. hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE,(LPSECURITY_ATTRIBUTES) NULL,
  833. PAGE_READWRITE,(DWORD)0,sizeof(DPL_SHARED_CONNECT_BLOCK),pszObjectName);
  834. if (hFileMap == NULL)
  835. {
  836. dwError = GetLastError();
  837. DPFX(DPFPREP, 0, "CreateFileMapping() failed dwLastError [0x%lx]", dwError );
  838. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  839. goto CLEANUP_DPLLaunch;
  840. }
  841. // Map file
  842. pSharedBlock = reinterpret_cast<DPL_SHARED_CONNECT_BLOCK*>(MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS,0,0,0));
  843. if (pSharedBlock == NULL)
  844. {
  845. dwError = GetLastError();
  846. DPFX(DPFPREP, 0,"MapViewOfFile() failed dwLastError [0x%lx]", dwError);
  847. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  848. goto CLEANUP_DPLLaunch;
  849. }
  850. // Create synchronization event
  851. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_EVENT;
  852. if ((hSyncEvents[0] = CreateEventA(NULL,TRUE,FALSE,pszObjectName)) == NULL)
  853. {
  854. dwError = GetLastError();
  855. DPFX(DPFPREP, 0, "Create Event Failed dwLastError [0x%lx]", dwError );
  856. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  857. goto CLEANUP_DPLLaunch;
  858. }
  859. if( DNGetOSType() == VER_PLATFORM_WIN32_NT )
  860. {
  861. // More setup
  862. siW.cb = sizeof(STARTUPINFO);
  863. siW.lpReserved = NULL;
  864. siW.lpDesktop = NULL;
  865. siW.lpTitle = NULL;
  866. siW.dwFlags = 0;
  867. siW.cbReserved2 = 0;
  868. siW.lpReserved2 = NULL;
  869. // Launch !
  870. if (CreateProcessW(pwszAppName, pwszCmdLine, NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  871. pdplProgramDesc->pwszCurrentDirectory,&siW,&pi) == 0)
  872. {
  873. dwError = GetLastError();
  874. DPFX(DPFPREP, 0, "CreateProcess Failed dwLastError [0x%lx]", dwError );
  875. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  876. goto CLEANUP_DPLLaunch;
  877. }
  878. }
  879. else
  880. {
  881. // More setup
  882. siA.cb = sizeof(STARTUPINFO);
  883. siA.lpReserved = NULL;
  884. siA.lpDesktop = NULL;
  885. siA.lpTitle = NULL;
  886. siA.dwFlags = 0;
  887. siA.cbReserved2 = 0;
  888. siA.lpReserved2 = NULL;
  889. DPFX(DPFPREP, 1, "Detected 9x, Doing Ansi launch" );
  890. //Convert full app name, command line and default dir from unicode to ascii format
  891. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszAppName, pwszAppName ) ) )
  892. {
  893. dwError = GetLastError();
  894. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  895. hResultCode = DPNERR_CONVERSION;
  896. goto CLEANUP_DPLLaunch;
  897. }
  898. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszCmdLine, pwszCmdLine ) ) )
  899. {
  900. dwError = GetLastError();
  901. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  902. hResultCode = DPNERR_CONVERSION;
  903. goto CLEANUP_DPLLaunch;
  904. }
  905. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszDefaultDir, pdplProgramDesc->pwszCurrentDirectory ) ) )
  906. {
  907. dwError = GetLastError();
  908. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  909. hResultCode = DPNERR_CONVERSION;
  910. goto CLEANUP_DPLLaunch;
  911. }
  912. // Launch !
  913. if (CreateProcessA(pszAppName,pszCmdLine,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  914. pszDefaultDir,&siA,&pi) == 0)
  915. {
  916. dwError = GetLastError();
  917. DPFX(DPFPREP, 0, "CreateProcess Failed dwLastError [0x%lx]", dwError );
  918. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  919. goto CLEANUP_DPLLaunch;
  920. }
  921. }
  922. hSyncEvents[1] = pi.hProcess;
  923. // Wait for connection or application termination
  924. dwError = WaitForMultipleObjects(2,hSyncEvents,FALSE,dwTimeOut);
  925. // Immediately clean up
  926. dwPID = pSharedBlock->dwPID;
  927. /* CloseHandle(hSyncEvents[0]);
  928. UnmapViewOfFile(pSharedBlock);
  929. CloseHandle(hFileMap); */
  930. // Ensure we can continue
  931. if (dwError - WAIT_OBJECT_0 > 1)
  932. {
  933. if (dwError == WAIT_TIMEOUT)
  934. {
  935. DPFERR("Wait for application connection timed out");
  936. hResultCode = DPNERR_TIMEDOUT;
  937. goto CLEANUP_DPLLaunch;
  938. }
  939. else
  940. {
  941. DPFERR("Wait for application connection terminated mysteriously");
  942. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  943. goto CLEANUP_DPLLaunch;
  944. }
  945. }
  946. // Check if application terminated
  947. if (dwError == 1)
  948. {
  949. DPFERR("Application was terminated");
  950. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  951. goto CLEANUP_DPLLaunch;
  952. }
  953. *pdwPID = dwPID;
  954. hResultCode = DPN_OK;
  955. CLEANUP_DPLLaunch:
  956. if( hSyncEvents[0] != NULL )
  957. CloseHandle( hSyncEvents[0] );
  958. if( pSharedBlock != NULL )
  959. UnmapViewOfFile(pSharedBlock);
  960. if( hFileMap != NULL )
  961. CloseHandle( hFileMap );
  962. if( pwszAppName != NULL )
  963. DNFree( pwszAppName );
  964. if (pwszCmdLine!=NULL)
  965. DNFree( pwszCmdLine );
  966. if( pszAppName != NULL )
  967. delete[] pszAppName;
  968. if (pszCmdLine!=NULL)
  969. delete[] pszCmdLine;
  970. if( pszDefaultDir != NULL )
  971. delete [] pszDefaultDir;
  972. DPF_RETURN(hResultCode);
  973. }
  974. HRESULT DPLUpdateAppStatus(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  975. const DPNHANDLE hSender,
  976. BYTE *const pBuffer)
  977. {
  978. HRESULT hResultCode;
  979. DPL_INTERNAL_MESSAGE_UPDATE_STATUS *pStatus;
  980. DPL_MESSAGE_SESSION_STATUS MsgStatus;
  981. DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p]",pBuffer);
  982. DNASSERT(pdpLobbyObject != NULL);
  983. DNASSERT(pBuffer != NULL);
  984. pStatus = reinterpret_cast<DPL_INTERNAL_MESSAGE_UPDATE_STATUS*>(pBuffer);
  985. MsgStatus.dwSize = sizeof(DPL_MESSAGE_SESSION_STATUS);
  986. MsgStatus.dwStatus = pStatus->dwStatus;
  987. MsgStatus.hSender = hSender;
  988. // Return code is irrelevant, at this point we're going to indicate regardless
  989. hResultCode = DPLConnectionGetContext( pdpLobbyObject, hSender, &MsgStatus.pvConnectionContext );
  990. if( FAILED( hResultCode ) )
  991. {
  992. DPFX(DPFPREP, 0, "Error getting connection context for 0x%x hr=0x%x", hSender, hResultCode );
  993. }
  994. hResultCode = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
  995. DPL_MSGID_SESSION_STATUS,
  996. reinterpret_cast<BYTE*>(&MsgStatus));
  997. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  998. return(hResultCode);
  999. }
  1000. // ----------------------------------------------------------------------------
  1001. #if 0
  1002. // HRESULT DNL_RegisterLcMessageHandler
  1003. // LPVOID lpv Interface pointer
  1004. // LPFNDNLCMESSAGEHANDLER lpfn Pointer to user supplied lobby client message handler function
  1005. // DWORD dwFlags Not Used
  1006. //
  1007. // Returns
  1008. // DPN_OK If the message handler was registered without incident
  1009. // DPNERR_INVALIDPARAM If there was an invalid parameter
  1010. // DPNERR_GENERIC If there were any problems
  1011. //
  1012. // Notes
  1013. // This function registers a user supplied lobby client message handler function. This function should
  1014. // only be called once, when the lobby client is launched.
  1015. //
  1016. // This will set up the required message queues, and spawn the lobby client's receive message queue thread.
  1017. // HRESULT DNL_EnumLocalPrograms
  1018. // LPVOID lpv Interface pointer
  1019. // LPGUID lpGuidApplication GUID of application to enumerate (optional)
  1020. // LPVOID lpvEnumData Buffer to be filled with DNAPPINFO structs and Unicode strings
  1021. // LPDWORD lpdwEnumData Size of lpvEnumData and number of bytes needed on return
  1022. // LPDWORD lpdwItems Number of DNAPPINFO structs in lpvEnumData
  1023. //
  1024. // Returns
  1025. // DPN_OK If the key was added successfully
  1026. // DPNERR_INVALIDPARAM If there was a problem with a parameter
  1027. // DPNERR_OUTOFMEMORY If it could not allocate memory
  1028. // DPNERR_DOESNOTEXIST If there was a problem opening reading a registry key
  1029. //
  1030. // Notes
  1031. // - This is ugly because of the need to support both WinNT and Win9x at runtime.
  1032. // WinNT registry is kept in Unicode, whereas Win9x is in ANSI. Application root key
  1033. // names should be ANSI compatible (or their GUIDs are used instead) i.e. Will be stored
  1034. // in Unicode under WinNT, but only if convertable to ANSI
  1035. // - Strings are placed in the buffer, starting at the end of the buffer and working
  1036. // backwards.
  1037. // - In most cases, errors will cause the current app being enumerated to be ignored
  1038. // and not included in the enumeration buffer.
  1039. // HRESULT DNL_ConnectApplication
  1040. // LPVOID lpv Interface pointer
  1041. // LPDNCONNECTINFO lpdnConnectionInfo Pointer to connection info structure
  1042. // LPVOID lpvUserApplicationContext User supplied application context value
  1043. // LPDWORD lpdwAppId Pointer to receive application ID (handle) in
  1044. // DWORD dwFlags Flags
  1045. //
  1046. // Returns
  1047. // DPN_OK If the application was connected to without incident
  1048. // DPNERR_INVALIDPARAM If there was an invalid parameter
  1049. // DPNERR_OUTOFMEMORY If there were any memory allocation problems
  1050. // DPNERR_GENERIC If there were any problems
  1051. //
  1052. // Notes
  1053. // This function connects the lobby client to a user specified application. If successfull, the
  1054. // DNLobby assigned application ID will be returned in lpdwAppId.
  1055. #undef DPF_MODNAME
  1056. #define DPF_MODNAME "DNL_ConnectApplication"
  1057. STDMETHODIMP DNL_ConnectApplication(LPVOID lpv,LPDNCONNECTINFO lpdnConnectionInfo,
  1058. LPVOID lpvUserApplicationContext,LPDWORD lpdwAppId, DWORD dwFlags)
  1059. {
  1060. LPDIRECTPLAYLOBBYOBJECT lpdnLobbyObject;
  1061. HRESULT hResultCode = DPN_OK;
  1062. DNPROGRAMDESC dnProgramDesc; // Program descriptor for launching applications
  1063. DWORD dwNumApps; // Number of applications currently running
  1064. LPDWORD lpdwProcessList = NULL; // Pointer to process list
  1065. DWORD dwProcessId; // Process ID of target applications
  1066. DWORD dw; // Counter
  1067. DWORD dwStrLen; // Various string lengths
  1068. LPWSTR lpwszCommandLine = NULL; // Expanded Unicode command line
  1069. LPWSTR lpwszCurrentDirectory = NULL; // Expanded Unicode current directory
  1070. LPSTR lpszCommandLine = NULL; // Expanded ANSI command line
  1071. LPSTR lpszCurrentDirectory = NULL; // Expanded ANSI current directory
  1072. LPWSTR lpwszUnexpanded = NULL; // Unexpanded command line
  1073. LPSTR lpszUnexpanded = NULL; // Unexpanded ANSI strings converted from Unicode
  1074. STARTUPINFOA siA; // ANSI startup info (place holder)
  1075. STARTUPINFOW siW; // Unicode startup info (place holder)
  1076. PROCESS_INFORMATION pi;
  1077. UUID uuid;
  1078. RPC_STATUS rpcStatus;
  1079. DWORD dwHandle;
  1080. LPDN_APP_HANDLE_ENTRY lpdnAppHandleEntry;
  1081. LPDN_MESSAGE_STRUCT lpdnMsg = NULL;
  1082. DPFX(DPFPREP, 9,"Parameters: lpv [%p], lpdnConnectionInfo [%p], lpvUserApplicationContext [%p], lpdwAppId [%p], dwFlags [%lx]",
  1083. lpv,lpdnConnectionInfo,lpvUserApplicationContext,lpdwAppId,dwFlags);
  1084. // Parameter validation
  1085. TRY
  1086. {
  1087. if (lpv == NULL || lpdnConnectionInfo == NULL || lpdwAppId == NULL)
  1088. return(DPNERR_INVALIDPARAM);
  1089. }
  1090. EXCEPT (EXCEPTION_EXECUTE_HANDLER)
  1091. {
  1092. DPFERR("Exception encountered validating parameters");
  1093. return(DPNERR_INVALIDPARAM);
  1094. }
  1095. lpdnLobbyObject = (LPDIRECTPLAYLOBBYOBJECT) GET_OBJECT_FROM_INTERFACE(lpv);
  1096. // Get program description from registry
  1097. if ((hResultCode = DnGetProgramDesc(lpdnConnectionInfo->lpGuidApplication,&dnProgramDesc))
  1098. != DPN_OK)
  1099. {
  1100. goto EXIT_DNL_ConnectApplication;
  1101. }
  1102. hResultCode = DnGetProcessListW(dnProgramDesc.lpwszFilename,NULL,&dwNumApps); // Num apps
  1103. if (hResultCode != DPN_OK && hResultCode != DPNERR_BUFFERTOOSMALL)
  1104. {
  1105. DnFreeProgramDesc(&dnProgramDesc);
  1106. goto EXIT_DNL_ConnectApplication;
  1107. }
  1108. while (hResultCode == DPNERR_BUFFERTOOSMALL) // New processes may get launched !
  1109. {
  1110. if (lpdwProcessList != NULL)
  1111. GlobalFree(lpdwProcessList);
  1112. if ((lpdwProcessList = (LPDWORD)GLOBALALLOC(dwNumApps*sizeof(DWORD))) == NULL)
  1113. {
  1114. hResultCode = DPNERR_OUTOFMEMORY;
  1115. DnFreeProgramDesc(&dnProgramDesc);
  1116. goto EXIT_DNL_ConnectApplication;
  1117. }
  1118. hResultCode = DnGetProcessListW(dnProgramDesc.lpwszFilename,lpdwProcessList,&dwNumApps);
  1119. }
  1120. if (hResultCode != DPN_OK) // Some sort of error occurred
  1121. {
  1122. DnFreeProgramDesc(&dnProgramDesc);
  1123. goto EXIT_DNL_ConnectApplication;
  1124. }
  1125. dwProcessId = 0;
  1126. for (dw = 0; dw < dwNumApps ; dw++)
  1127. {
  1128. if (DnCheckMsgQueueWaiting(lpdwProcessList[dw]))
  1129. {
  1130. if (DnSetMsgQueueWaiting(lpdwProcessList[dw],FALSE,TRUE) == DPN_OK)
  1131. {
  1132. // This is the process ID of the existing app to connect to !
  1133. dwProcessId = lpdwProcessList[dw];
  1134. break;
  1135. }
  1136. }
  1137. }
  1138. if (dwProcessId == 0) // Could not find an app to connect to - launch a new one
  1139. {
  1140. dwStrLen = wcslen(dnProgramDesc.lpwszPath) + 1
  1141. + wcslen(dnProgramDesc.lpwszApplicationLauncher) + 1
  1142. + wcslen(dnProgramDesc.lpwszCommandLine) + 1 + DN_LC_ID_STR_LEN + DN_GUID_STR_LEN + 1;
  1143. if ((lpwszUnexpanded = (LPWSTR)GLOBALALLOC(dwStrLen*sizeof(WCHAR))) == NULL)
  1144. {
  1145. DnFreeProgramDesc(&dnProgramDesc);
  1146. hResultCode = DPNERR_OUTOFMEMORY;
  1147. goto EXIT_DNL_ConnectApplication;
  1148. }
  1149. *lpwszUnexpanded = L'\0';
  1150. if (wcslen(dnProgramDesc.lpwszPath) > 0)
  1151. {
  1152. wcscpy(lpwszUnexpanded,dnProgramDesc.lpwszPath);
  1153. wcscat(lpwszUnexpanded,L"\\");
  1154. }
  1155. wcscat(lpwszUnexpanded,dnProgramDesc.lpwszApplicationLauncher);
  1156. wcscat(lpwszUnexpanded,L" ");
  1157. wcscat(lpwszUnexpanded,dnProgramDesc.lpwszCommandLine);
  1158. wcscat(lpwszUnexpanded,L" ");
  1159. wcscat(lpwszUnexpanded,DN_LC_ID_WSTR);
  1160. rpcStatus = CoCreateGuid(&uuid);
  1161. if (rpcStatus != RPC_S_OK && rpcStatus != RPC_S_UUID_LOCAL_ONLY)
  1162. {
  1163. DnFreeProgramDesc(&dnProgramDesc);
  1164. hResultCode = DPNERR_GENERIC;
  1165. goto EXIT_DNL_ConnectApplication;
  1166. }
  1167. StringFromGUID(&uuid,lpwszUnexpanded+wcslen(lpwszUnexpanded),DN_GUID_STR_LEN+1);
  1168. if (DN_RUNNING_NT) // Unicode on WinNT
  1169. {
  1170. // Expand environment strings
  1171. if ((hResultCode = DnExpandEnvStringW(lpwszUnexpanded,&lpwszCommandLine)) != DPN_OK)
  1172. {
  1173. DPFX(DPFPREP, 0,"DnExpandEnvStringW() failed [%lX]",hResultCode);
  1174. DnFreeProgramDesc(&dnProgramDesc);
  1175. goto EXIT_DNL_ConnectApplication;
  1176. }
  1177. if ((hResultCode = DnExpandEnvStringW(dnProgramDesc.lpwszCurrentDirectory,
  1178. &lpwszCurrentDirectory)) != DPN_OK)
  1179. {
  1180. DPFX(DPFPREP, 0,"DnExpandEnvStringW() failed [%lX]",hResultCode);
  1181. DnFreeProgramDesc(&dnProgramDesc);
  1182. goto EXIT_DNL_ConnectApplication;
  1183. }
  1184. // Set up to Launch application
  1185. siW.cb = sizeof(STARTUPINFO);
  1186. siW.lpReserved = NULL;
  1187. siW.lpDesktop = NULL;
  1188. siW.lpTitle = NULL;
  1189. siW.dwFlags = (DWORD)NULL;
  1190. siW.cbReserved2 = (BYTE)NULL;
  1191. siW.lpReserved2 = NULL;
  1192. // Launch application (finally !)
  1193. if (CreateProcessW(NULL,lpwszCommandLine,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  1194. lpwszCurrentDirectory,&siW,&pi) == 0)
  1195. {
  1196. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  1197. DnFreeProgramDesc(&dnProgramDesc);
  1198. goto EXIT_DNL_ConnectApplication;
  1199. }
  1200. }
  1201. else // ANSI on Win9x
  1202. {
  1203. // Convert command line from Unicode to ANSI
  1204. if ((lpszUnexpanded = (LPSTR)GLOBALALLOC(dwStrLen)) == NULL)
  1205. {
  1206. DnFreeProgramDesc(&dnProgramDesc);
  1207. hResultCode = DPNERR_OUTOFMEMORY;
  1208. goto EXIT_DNL_ConnectApplication;
  1209. }
  1210. WideToAnsi(lpszUnexpanded,lpwszUnexpanded,dwStrLen);
  1211. DPFX(DPFPREP, 7,"Unexpanded Command Line [%s]",lpszUnexpanded);
  1212. // Expand command line environment strings
  1213. if ((hResultCode = DnExpandEnvStringA(lpszUnexpanded,&lpszCommandLine)) != DPN_OK)
  1214. {
  1215. DPFX(DPFPREP, 0,"DnExpandEnvStringA() failed [%lX]",hResultCode);
  1216. DnFreeProgramDesc(&dnProgramDesc);
  1217. goto EXIT_DNL_ConnectApplication;
  1218. }
  1219. DPFX(DPFPREP, 7,"Expanded Command Line [%s]",lpszCommandLine);
  1220. // Convert current directory from Unicode to ANSI
  1221. GlobalFree(lpszUnexpanded);
  1222. lpszUnexpanded = NULL;
  1223. dwStrLen = wcslen(dnProgramDesc.lpwszCurrentDirectory);
  1224. if ((lpszUnexpanded = (LPSTR)GLOBALALLOC(dwStrLen+1)) == NULL)
  1225. {
  1226. DnFreeProgramDesc(&dnProgramDesc);
  1227. hResultCode = DPNERR_OUTOFMEMORY;
  1228. goto EXIT_DNL_ConnectApplication;
  1229. }
  1230. WideToAnsi(lpszUnexpanded,dnProgramDesc.lpwszCurrentDirectory,dwStrLen+1);
  1231. DPFX(DPFPREP, 7,"Unexpanded Current Directory [%s]",lpszUnexpanded);
  1232. // Expand current directory environment strings
  1233. if ((hResultCode = DnExpandEnvStringA(lpszUnexpanded,&lpszCurrentDirectory)) != DPN_OK)
  1234. {
  1235. DPFX(DPFPREP, 0,"DnExpandEnvStringA() failed [%lX]",hResultCode);
  1236. DnFreeProgramDesc(&dnProgramDesc);
  1237. goto EXIT_DNL_ConnectApplication;
  1238. }
  1239. DPFX(DPFPREP, 7,"Expanded Current Directory [%s]",lpszCurrentDirectory);
  1240. // Set up to Launch application
  1241. siA.cb = sizeof(STARTUPINFO);
  1242. siA.lpReserved = NULL;
  1243. siA.lpDesktop = NULL;
  1244. siA.lpTitle = NULL;
  1245. siA.dwFlags = (DWORD)NULL;
  1246. siA.cbReserved2 = (BYTE)NULL;
  1247. siA.lpReserved2 = NULL;
  1248. // Launch application (finally !)
  1249. if (CreateProcessA(NULL,lpszCommandLine,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  1250. lpszCurrentDirectory,&siA,&pi) == 0)
  1251. {
  1252. DPFERR("CreateProcess() failed !");
  1253. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  1254. DnFreeProgramDesc(&dnProgramDesc);
  1255. goto EXIT_DNL_ConnectApplication;
  1256. }
  1257. }
  1258. // Get Application Process ID
  1259. if ((hResultCode = DnHandShakeAppPid(TRUE,&uuid,&dwProcessId)) != DPN_OK)
  1260. {
  1261. DPFERR("Hand shake to retrieve App PID failed !");
  1262. DnFreeProgramDesc(&dnProgramDesc);
  1263. goto EXIT_DNL_ConnectApplication;
  1264. }
  1265. DPFX(DPFPREP, 0,"Application PID = [0x%08lX]",dwProcessId);
  1266. }
  1267. DnFreeProgramDesc(&dnProgramDesc);
  1268. // Create application handle
  1269. if ((lpdnAppHandleEntry = (LPDN_APP_HANDLE_ENTRY)GLOBALALLOC(
  1270. sizeof(DN_APP_HANDLE_ENTRY))) == NULL)
  1271. {
  1272. hResultCode = DPNERR_OUTOFMEMORY;
  1273. goto EXIT_DNL_ConnectApplication;
  1274. }
  1275. lpdnAppHandleEntry->dwAppProcessId = dwProcessId;
  1276. if ((lpdnAppHandleEntry->lpmqSendMsgQueue =
  1277. (DN_MSG_QUEUE_STRUCT *)GLOBALALLOC(sizeof(DN_MSG_QUEUE_STRUCT))) == NULL)
  1278. {
  1279. hResultCode = DPNERR_OUTOFMEMORY;
  1280. goto EXIT_DNL_ConnectApplication;
  1281. }
  1282. if ((hResultCode = CreateHandle(lpdnLobbyObject->lphsApplicationHandles,&dwHandle,lpdnAppHandleEntry)) != DPN_OK)
  1283. {
  1284. goto EXIT_DNL_ConnectApplication;
  1285. }
  1286. lpdnAppHandleEntry->dwHandle = dwHandle;
  1287. lpdnAppHandleEntry->lpvUserApplicationContext = lpvUserApplicationContext;
  1288. *lpdwAppId = dwHandle;
  1289. // Connect to Application's receive message queue
  1290. if ((hResultCode = DnOpenMsgQueue(lpdnAppHandleEntry->lpmqSendMsgQueue,dwProcessId,
  1291. DN_MSG_OBJECT_SUFFIX_APPLICATION,DN_MSG_QUEUE_SIZE,(DWORD)NULL)) != DPN_OK)
  1292. {
  1293. goto EXIT_DNL_ConnectApplication;
  1294. }
  1295. // Pass lobby client connection info to application
  1296. if ((hResultCode = DnSendLcInfo(lpdnAppHandleEntry->lpmqSendMsgQueue,dwHandle,
  1297. GetCurrentProcessId())) != DPN_OK)
  1298. {
  1299. goto EXIT_DNL_ConnectApplication;
  1300. }
  1301. // Pass connection info - TODO check if valid
  1302. DPFX(DPFPREP, 9,"Sending Connection Info ...");
  1303. // Get string lengths
  1304. dwStrLen = ((wcslen(lpdnConnectionInfo->lpwszPlayerName)+ 1 ) * sizeof(WCHAR))
  1305. + strlen(lpdnConnectionInfo->lpszDNAddressLocalSettings) + 1
  1306. + strlen(lpdnConnectionInfo->lpszDNAddressRemote) + 1
  1307. + sizeof(GUID);
  1308. dw = sizeof(DN_MESSAGE_STRUCT) + dwStrLen;
  1309. // Create message
  1310. if ((lpdnMsg = (LPDN_MESSAGE_STRUCT)GLOBALALLOC(dw)) == NULL)
  1311. {
  1312. hResultCode = DPNERR_OUTOFMEMORY;
  1313. goto EXIT_DNL_ConnectApplication;
  1314. }
  1315. lpdnMsg->dwMessageType = DN_MSGTYPE_CONNECTION_SETTINGS;
  1316. lpdnMsg->dwParam1 = 0;
  1317. lpdnMsg->dwParam2 = (wcslen(lpdnConnectionInfo->lpwszPlayerName) + 1) * sizeof(WCHAR);
  1318. lpdnMsg->dwParam3 = lpdnMsg->dwParam2 + strlen(lpdnConnectionInfo->lpszDNAddressRemote) + 1;
  1319. lpdnMsg->dwParam4 = lpdnMsg->dwParam3 + strlen(lpdnConnectionInfo->lpszDNAddressLocalSettings) + 1;
  1320. lpdnMsg->dwTagLen = dwStrLen;
  1321. memcpy(&lpdnMsg->cTags + lpdnMsg->dwParam1,lpdnConnectionInfo->lpwszPlayerName,
  1322. lpdnMsg->dwParam2);
  1323. memcpy(&lpdnMsg->cTags + lpdnMsg->dwParam2,lpdnConnectionInfo->lpszDNAddressRemote,
  1324. lpdnMsg->dwParam3-lpdnMsg->dwParam2);
  1325. memcpy(&lpdnMsg->cTags + lpdnMsg->dwParam3,lpdnConnectionInfo->lpszDNAddressLocalSettings,
  1326. lpdnMsg->dwParam4-lpdnMsg->dwParam3);
  1327. memcpy(&lpdnMsg->cTags + lpdnMsg->dwParam4,lpdnConnectionInfo->lpGuidApplication,
  1328. dwStrLen-lpdnMsg->dwParam4);
  1329. if ((hResultCode = DnSendMsg(lpdnAppHandleEntry->lpmqSendMsgQueue,lpdnMsg,dw,FALSE,
  1330. 0)) != DPN_OK)
  1331. {
  1332. GlobalFree(lpdnMsg);
  1333. goto EXIT_DNL_ConnectApplication;
  1334. }
  1335. GlobalFree(lpdnMsg);
  1336. EXIT_DNL_ConnectApplication:
  1337. if (lpwszUnexpanded != NULL)
  1338. GlobalFree(lpwszUnexpanded);
  1339. if (lpwszCommandLine != NULL)
  1340. GlobalFree(lpwszCommandLine);
  1341. if (lpwszCurrentDirectory != NULL)
  1342. GlobalFree(lpwszCurrentDirectory);
  1343. if (lpszUnexpanded != NULL)
  1344. GlobalFree(lpszUnexpanded);
  1345. if (lpszCommandLine != NULL)
  1346. GlobalFree(lpszCommandLine);
  1347. if (lpszCurrentDirectory != NULL)
  1348. GlobalFree(lpszCurrentDirectory);
  1349. if (lpdwProcessList != NULL)
  1350. GlobalFree(lpdwProcessList);
  1351. return(hResultCode);
  1352. }
  1353. // HRESULT DnProcessLcMessage
  1354. // LPDIRECTNETLOBBYOBJECT lpdnLobbyObject Pointer to lobby object
  1355. // LPVOID lpvUserHandler Pointer to user message handler routine
  1356. // LPVOID lpvMsgBuff Pointer to message buffer
  1357. // DWORD dwMsgLen Length of message buffer
  1358. // DWORD dwId Application ID which sent the message
  1359. // LPVOID lpvContext User context value associated with the app ID
  1360. //
  1361. // Returns
  1362. // DPN_OK If the message was processed without incident
  1363. // DPNERR_GENERIC If there were any problems from the user supplied handler
  1364. //
  1365. // Notes
  1366. // This function processes messages received by the lobby client from the applications it is connected to.
  1367. // One Lobby Client may be connected to one or more applications. Internal messages are processed here,
  1368. // and all others are passed to the user supplied message handler.
  1369. #undef DPF_MODNAME
  1370. #define DPF_MODNAME "DnProcessLcMessage"
  1371. HRESULT DnProcessLcMessage(LPDIRECTNETLOBBYOBJECT lpdnLobbyObject,LPVOID lpvUserHandler,
  1372. LPVOID lpvMsgBuff, DWORD dwMsgLen,DWORD dwId,LPVOID lpvContext)
  1373. {
  1374. HRESULT hResultCode = DPN_OK;
  1375. LPDN_MESSAGE_STRUCT lpdnMsg;
  1376. DPFX(DPFPREP, 9,"Parameters: lpdnLobbyObject [0x%p], lpvUserHandler [0x%p], lpvMsgBuff [0x%p], dwMsgLen [%lx], dwId [%lx], lpvContext [0x%p]",
  1377. lpdnLobbyObject,lpvUserHandler,lpvMsgBuff,dwMsgLen,dwId,lpvContext);
  1378. lpdnMsg = (LPDN_MESSAGE_STRUCT)lpvMsgBuff;
  1379. switch(lpdnMsg->dwMessageType)
  1380. {
  1381. case DN_MSGTYPE_TERMINATE:
  1382. DPFX(DPFPREP, 9,"Received Terminate");
  1383. ExitThread(0);
  1384. break;
  1385. default: // Pass message to user message handler
  1386. DPFX(DPFPREP, 9,"User Message ...");
  1387. hResultCode = ((LPFNDNLCMESSAGEHANDLER)lpvUserHandler)(dwId,lpvContext,lpdnMsg->dwMessageType,lpdnMsg->dwUserToken,
  1388. lpdnMsg->dwParam1,lpdnMsg->dwParam2,lpdnMsg->dwParam3,lpdnMsg->dwParam4,
  1389. lpdnMsg->dwTagLen,&(lpdnMsg->cTags));
  1390. break;
  1391. }
  1392. return(hResultCode);
  1393. }
  1394. // HRESULT DNL_SendToApplication
  1395. // LPVOID lpv Interface pointer
  1396. // DWORD dwAppId Application ID to send message to
  1397. // DWORD dwMessageId Message ID code
  1398. // DWORD dwUserToken User supplied token
  1399. // DWORD dwParam1
  1400. // DWORD dwParam2
  1401. // DWORD dwParam3
  1402. // DWORD dwParam4
  1403. // DWORD dwFlags
  1404. // DWORD dwTagLen Length of tags field (in bytes)
  1405. // LPVOID lpvTags Tag field
  1406. //
  1407. // Returns
  1408. // DPN_OK If the message was sent without incident
  1409. // DPNERR_INVALIDPARAM If there was an invalid parameter
  1410. // DPNERR_OUTOFMEMORY If there were any memory allocation problems
  1411. // DPNERR_GENERIC If there were any problems
  1412. //
  1413. // Notes
  1414. // This function sends messages from the lobby client to a specified application.
  1415. #undef DPF_MODNAME
  1416. #define DPF_MODNAME "DNL_SendToApplication"
  1417. STDMETHODIMP DNL_SendToApplication(LPVOID lpv,DWORD dwAppId,DWORD dwMessageId,DWORD dwUserToken,
  1418. DWORD dwParam1,DWORD dwParam2,DWORD dwParam3,DWORD dwParam4,
  1419. DWORD dwFlags,DWORD dwTagLen,LPVOID lpvTags)
  1420. {
  1421. LPDIRECTNETLOBBYOBJECT lpdnLobbyObject;
  1422. HRESULT hResultCode = DPN_OK;
  1423. LPDN_APP_HANDLE_ENTRY lpdnAppHandleEntry;
  1424. LPDN_MESSAGE_STRUCT lpdnMessage;
  1425. DN_MESSAGE_STRUCT dnMessage;
  1426. DWORD dwMsgLen;
  1427. DPFX(DPFPREP, 9,"Parameters: lpv [%p], dwAppId [%lx], dwMessageId [%lx], dwUserToken [%lx], dwParams [%lx], [%lx], [%lx], [%lx], dwFlags [%lx], dwTagLen [%lx], lpvTags [%p]",
  1428. lpv,dwAppId,dwMessageId,dwUserToken,dwParam1,dwParam2,dwParam3,dwParam4,dwFlags,dwTagLen,lpvTags);
  1429. // Parameter validation
  1430. TRY
  1431. {
  1432. if (lpv == NULL || dwAppId == 0)
  1433. return(DPNERR_INVALIDPARAM);
  1434. if (dwFlags != 0)
  1435. return(DPNERR_INVALIDFLAGS);
  1436. }
  1437. EXCEPT (EXCEPTION_EXECUTE_HANDLER)
  1438. {
  1439. DPFERR("Exception encountered validating parameters");
  1440. return(DPNERR_INVALIDPARAM);
  1441. }
  1442. lpdnLobbyObject = (LPDIRECTNETLOBBYOBJECT) GET_OBJECT_FROM_INTERFACE(lpv);
  1443. // Ensure app ID is valid, and then retrieve connection (message queue) information for it
  1444. if (!IsHandleValid(lpdnLobbyObject->lphsApplicationHandles,dwAppId))
  1445. {
  1446. hResultCode = DPNERR_INVALIDPARAM;
  1447. goto EXIT_DNL_SendToApplication;
  1448. }
  1449. if ((hResultCode = RetrieveHandleData(lpdnLobbyObject->lphsApplicationHandles,dwAppId,
  1450. (LPVOID *)&lpdnAppHandleEntry)) != DPN_OK)
  1451. {
  1452. goto EXIT_DNL_SendToApplication;
  1453. }
  1454. dwMsgLen = sizeof(DN_MESSAGE_STRUCT);
  1455. if (dwTagLen > 0) // Create buffer if there are tags
  1456. {
  1457. dwMsgLen += dwTagLen;
  1458. if ((lpdnMessage = (LPDN_MESSAGE_STRUCT)GLOBALALLOC(dwMsgLen)) == NULL)
  1459. {
  1460. hResultCode = DPNERR_OUTOFMEMORY;
  1461. goto EXIT_DNL_SendToApplication;
  1462. }
  1463. }
  1464. else // Use default static buffer (avoid malloc call)
  1465. {
  1466. lpdnMessage = &dnMessage;
  1467. }
  1468. lpdnMessage->dwMessageType = dwMessageId;
  1469. lpdnMessage->dwUserToken = dwUserToken;
  1470. lpdnMessage->dwParam1 = dwParam1;
  1471. lpdnMessage->dwParam2 = dwParam2;
  1472. lpdnMessage->dwParam3 = dwParam3;
  1473. lpdnMessage->dwParam4 = dwParam4;
  1474. lpdnMessage->dwTagLen = dwTagLen;
  1475. if (dwTagLen > 0)
  1476. {
  1477. memcpy(&(lpdnMessage->cTags),lpvTags,dwTagLen);
  1478. }
  1479. else
  1480. {
  1481. lpdnMessage->cTags = '\0';
  1482. }
  1483. // Send message
  1484. hResultCode = DnSendMsg(lpdnAppHandleEntry->lpmqSendMsgQueue,lpdnMessage,dwMsgLen,FALSE,
  1485. (DWORD)NULL);
  1486. // Free buffer if it was malloc'd
  1487. if (dwTagLen > 0)
  1488. GlobalFree(lpdnMessage);
  1489. EXIT_DNL_SendToApplication:
  1490. return(hResultCode);
  1491. }
  1492. // HRESULT DNL_ReleaseApplication
  1493. // LPVOID lpv Interface pointer
  1494. // DWORD dwAppId Application ID to release
  1495. //
  1496. // Returns
  1497. // DPN_OK If the message was sent without incident
  1498. // DPNERR_INVALIDPARAM If there was an invalid parameter
  1499. // DPNERR_INVALIDHANDLE If the application ID is not valid
  1500. // DPNERR_GENERIC If there were any problems
  1501. //
  1502. // Notes
  1503. // This function causes the lobby client to terminate it's association with a lobbied
  1504. // application (whether the lobby client launched the application or not). This allows the
  1505. // application to either terminate gracefully (if still running) and then be made available
  1506. // for re-connection to another (or the same) lobby client later. This should be called
  1507. // whenever a lobby client is finished with a lobbied application.
  1508. #undef DPF_MODNAME
  1509. #define DPF_MODNAME "DNL_ReleaseApplication"
  1510. STDMETHODIMP DNL_ReleaseApplication(LPVOID lpv,DWORD dwAppId)
  1511. {
  1512. LPDIRECTNETLOBBYOBJECT lpdnLobbyObject;
  1513. HRESULT hResultCode = DPN_OK;
  1514. LPDN_APP_HANDLE_ENTRY lph;
  1515. DPFX(DPFPREP, 9,"Parameters: lpv [%lx], dwAppId [%lx]", lpv,dwAppId);
  1516. // Parameter validation
  1517. TRY
  1518. {
  1519. if (lpv == NULL || dwAppId == 0)
  1520. return(DPNERR_INVALIDPARAM);
  1521. }
  1522. EXCEPT (EXCEPTION_EXECUTE_HANDLER)
  1523. {
  1524. DPFERR("Exception encountered validating parameters");
  1525. return(DPNERR_INVALIDPARAM);
  1526. }
  1527. lpdnLobbyObject = (LPDIRECTNETLOBBYOBJECT) GET_OBJECT_FROM_INTERFACE(lpv);
  1528. // TODO - wait for messages to be processed
  1529. if ((hResultCode = RetrieveHandleData(lpdnLobbyObject->lphsApplicationHandles,dwAppId,&lph)) == DPN_OK)
  1530. {
  1531. if ((hResultCode = DnCloseMsgQueue(lph->lpmqSendMsgQueue)) == DPN_OK)
  1532. {
  1533. if ((hResultCode = DestroyHandle(lpdnLobbyObject->lphsApplicationHandles,dwAppId)) == DPN_OK)
  1534. {
  1535. }
  1536. }
  1537. GlobalFree(lph);
  1538. }
  1539. //EXIT_DNL_ReleaseApplication:
  1540. return(hResultCode);
  1541. }
  1542. #endif