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.

1206 lines
39 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. #ifndef DPNBUILD_NOPARAMVAL
  127. TRY
  128. {
  129. #endif // !DPNBUILD_NOPARAMVAL
  130. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  131. #ifndef DPNBUILD_NOPARAMVAL
  132. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  133. {
  134. if( FAILED( hResultCode = DPL_ValidateEnumLocalPrograms( pInterface, pGuidApplication, pEnumData, pdwEnumDataSize, pdwEnumDataItems, dwFlags ) ) )
  135. {
  136. DPFX(DPFPREP, 0, "Error validating enum local programs params hr=[0x%lx]", hResultCode );
  137. DPF_RETURN( hResultCode );
  138. }
  139. }
  140. // Ensure we've been initialized
  141. if (pdpLobbyObject->pReceiveQueue == NULL)
  142. {
  143. DPFERR("Not initialized");
  144. DPF_RETURN(DPNERR_UNINITIALIZED);
  145. }
  146. }
  147. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  148. {
  149. DPFERR("Invalid object" );
  150. DPF_RETURN(DPNERR_INVALIDOBJECT);
  151. }
  152. #endif // !DPNBUILD_NOPARAMVAL
  153. dwSizeRequired = *pdwEnumDataSize;
  154. PackedBuffer.Initialize(pEnumData,dwSizeRequired);
  155. pwszApplicationName = NULL;
  156. pwszExecutableFilename = NULL;
  157. pdwPID = NULL;
  158. dwMaxPID = 0;
  159. dwLengthAppLoadedList = 0;
  160. dwSizeAppLoadedList = DPL_ENUM_APPGUID_BUFFER_INITIAL;
  161. pAppLoadedList = static_cast<GUID*>(DNMalloc(sizeof(GUID)*dwSizeAppLoadedList));
  162. if( !pAppLoadedList )
  163. {
  164. DPFERR("Failed allocating memory" );
  165. hResultCode = DPNERR_OUTOFMEMORY;
  166. goto EXIT_DPL_EnumLocalPrograms;
  167. }
  168. dwEnumCount = 0;
  169. DWORD dwIndex;
  170. for( dwIndex = 0; dwIndex < 2; dwIndex++ )
  171. {
  172. if( dwIndex == 0 )
  173. {
  174. hkCurrentBranch = HKEY_CURRENT_USER;
  175. }
  176. else
  177. {
  178. hkCurrentBranch = HKEY_LOCAL_MACHINE;
  179. }
  180. if (!RegistryEntry.Open(hkCurrentBranch,DPL_REG_LOCAL_APPL_SUBKEY,TRUE,FALSE,TRUE,DPL_REGISTRY_READ_ACCESS))
  181. {
  182. DPFX(DPFPREP,1,"On pass %i could not find app key", dwIndex);
  183. continue;
  184. }
  185. // Set up to enumerate
  186. if (!RegistryEntry.GetMaxKeyLen(&dwMaxKeyLen))
  187. {
  188. DPFERR("RegistryEntry.GetMaxKeyLen() failed");
  189. hResultCode = DPNERR_GENERIC;
  190. goto EXIT_DPL_EnumLocalPrograms;
  191. }
  192. dwMaxKeyLen++; // Null terminator
  193. DPFX(DPFPREP, 7,"dwMaxKeyLen = %ld",dwMaxKeyLen);
  194. if ((pwszKeyName = static_cast<WCHAR*>(DNMalloc(dwMaxKeyLen*sizeof(WCHAR)))) == NULL)
  195. {
  196. DPFERR("DNMalloc() failed");
  197. hResultCode = DPNERR_OUTOFMEMORY;
  198. goto EXIT_DPL_EnumLocalPrograms;
  199. }
  200. dwMaxApplicationNameLength = dwMaxKeyLen * sizeof(WCHAR);
  201. dwMaxExecutableFilenameLength = dwMaxApplicationNameLength;
  202. if ((pwszApplicationName = static_cast<WCHAR*>(DNMalloc(dwMaxApplicationNameLength*sizeof(WCHAR)))) == NULL) // Seed Application name size
  203. {
  204. DPFERR("DNMalloc() failed");
  205. hResultCode = DPNERR_OUTOFMEMORY;
  206. goto EXIT_DPL_EnumLocalPrograms;
  207. }
  208. if ((pwszExecutableFilename = static_cast<WCHAR*>(DNMalloc(dwMaxExecutableFilenameLength*sizeof(WCHAR)))) == NULL)
  209. {
  210. DPFERR("DNMalloc() failed");
  211. hResultCode = DPNERR_OUTOFMEMORY;
  212. goto EXIT_DPL_EnumLocalPrograms;
  213. }
  214. dwEnumIndex = 0;
  215. dwKeyLen = dwMaxKeyLen;
  216. // Enumerate !
  217. while (RegistryEntry.EnumKeys(pwszKeyName,&dwKeyLen,dwEnumIndex))
  218. {
  219. DPFX(DPFPREP, 7,"%ld - %ls (%ld)",dwEnumIndex,pwszKeyName,dwKeyLen);
  220. // Get Application name and GUID from each sub key
  221. if (!SubEntry.Open(RegistryEntry,pwszKeyName,TRUE,FALSE))
  222. {
  223. DPFX(DPFPREP, 7,"skipping %ls",pwszKeyName);
  224. goto LOOP_END;
  225. }
  226. //
  227. // Minara, double-check size vs. length for names
  228. //
  229. if (!SubEntry.GetValueLength(DPL_REG_KEYNAME_APPLICATIONNAME,&dwApplicationNameLength))
  230. {
  231. DPFX(DPFPREP, 7,"Could not get ApplicationName size. Skipping [%ls]",pwszKeyName);
  232. goto LOOP_END;
  233. }
  234. // To include null terminator
  235. dwApplicationNameLength++;
  236. if (dwApplicationNameLength > dwMaxApplicationNameLength)
  237. {
  238. // grow buffer (taking into account that the reg functions always return WCHAR) and try again
  239. DPFX(DPFPREP, 7,"Need to grow pwszApplicationName from %ld to %ld",dwMaxApplicationNameLength,dwApplicationNameLength);
  240. if (pwszApplicationName != NULL)
  241. {
  242. DNFree(pwszApplicationName);
  243. pwszApplicationName = NULL;
  244. }
  245. if ((pwszApplicationName = static_cast<WCHAR*>(DNMalloc(dwApplicationNameLength*sizeof(WCHAR)))) == NULL)
  246. {
  247. DPFERR("DNMalloc() failed");
  248. hResultCode = DPNERR_OUTOFMEMORY;
  249. goto EXIT_DPL_EnumLocalPrograms;
  250. }
  251. dwMaxApplicationNameLength = dwApplicationNameLength;
  252. }
  253. if (!SubEntry.ReadString(DPL_REG_KEYNAME_APPLICATIONNAME,pwszApplicationName,&dwApplicationNameLength))
  254. {
  255. DPFX(DPFPREP, 7,"Could not read ApplicationName. Skipping [%ls]",pwszKeyName);
  256. goto LOOP_END;
  257. }
  258. DPFX(DPFPREP, 7,"ApplicationName = %ls (%ld WCHARs)",pwszApplicationName,dwApplicationNameLength);
  259. if (!SubEntry.ReadGUID(DPL_REG_KEYNAME_GUID, &dplAppInfo.guidApplication))
  260. {
  261. DPFERR("SubEntry.ReadGUID failed - skipping entry");
  262. goto LOOP_END;
  263. }
  264. DWORD dwGuidSearchIndex;
  265. for( dwGuidSearchIndex = 0; dwGuidSearchIndex < dwLengthAppLoadedList; dwGuidSearchIndex++ )
  266. {
  267. if( pAppLoadedList[dwGuidSearchIndex] == dplAppInfo.guidApplication )
  268. {
  269. DPFX(DPFPREP, 1, "Ignoring local machine entry for current user version of entry [%ls]", pwszApplicationName );
  270. goto LOOP_END;
  271. }
  272. }
  273. if ((pGuidApplication == NULL) || (*pGuidApplication == dplAppInfo.guidApplication))
  274. {
  275. // Get process count - need executable filename
  276. //
  277. // Minara, check size vs. length
  278. //
  279. if (!SubEntry.GetValueLength(DPL_REG_KEYNAME_EXECUTABLEFILENAME,&dwExecutableFilenameLength))
  280. {
  281. DPFX(DPFPREP, 7,"Could not get ExecutableFilename size. Skipping [%ls]",pwszKeyName);
  282. goto LOOP_END;
  283. }
  284. // So we include null terminator
  285. dwExecutableFilenameLength++;
  286. if (dwExecutableFilenameLength > dwMaxExecutableFilenameLength)
  287. {
  288. // grow buffer (noting that all strings from the registry are WCHAR) and try again
  289. DPFX(DPFPREP, 7,"Need to grow pwszExecutableFilename from %ld to %ld",dwMaxExecutableFilenameLength,dwExecutableFilenameLength);
  290. if (pwszExecutableFilename != NULL)
  291. {
  292. DNFree(pwszExecutableFilename);
  293. pwszExecutableFilename = NULL;
  294. }
  295. if ((pwszExecutableFilename = static_cast<WCHAR*>(DNMalloc(dwExecutableFilenameLength*sizeof(WCHAR)))) == NULL)
  296. {
  297. DPFERR("DNMalloc() failed");
  298. hResultCode = DPNERR_OUTOFMEMORY;
  299. goto EXIT_DPL_EnumLocalPrograms;
  300. }
  301. dwMaxExecutableFilenameLength = dwExecutableFilenameLength;
  302. }
  303. if (!SubEntry.ReadString(DPL_REG_KEYNAME_EXECUTABLEFILENAME,pwszExecutableFilename,&dwExecutableFilenameLength))
  304. {
  305. DPFX(DPFPREP, 7,"Could not read ExecutableFilename. Skipping [%ls]",pwszKeyName);
  306. goto LOOP_END;
  307. }
  308. DPFX(DPFPREP, 7,"ExecutableFilename [%ls]",pwszExecutableFilename);
  309. // Count running apps
  310. dwNumPID = dwMaxPID;
  311. while ((hResultCode = DPLGetProcessList(pwszExecutableFilename,pdwPID,&dwNumPID)) == DPNERR_BUFFERTOOSMALL)
  312. {
  313. if (pdwPID)
  314. {
  315. DNFree(pdwPID);
  316. pdwPID = NULL;
  317. }
  318. dwMaxPID = dwNumPID;
  319. if ((pdwPID = static_cast<DWORD*>(DNMalloc(dwNumPID*sizeof(DWORD)))) == NULL)
  320. {
  321. DPFERR("DNMalloc() failed");
  322. hResultCode = DPNERR_OUTOFMEMORY;
  323. goto EXIT_DPL_EnumLocalPrograms;
  324. }
  325. }
  326. if (hResultCode != DPN_OK)
  327. {
  328. DPFERR("DPLGetProcessList() failed");
  329. DisplayDNError(0,hResultCode);
  330. hResultCode = DPNERR_GENERIC;
  331. goto EXIT_DPL_EnumLocalPrograms;
  332. }
  333. // Count waiting apps
  334. dplAppInfo.dwNumWaiting = 0;
  335. for (dw = 0 ; dw < dwNumPID ; dw++)
  336. {
  337. if ((hResultCode = MessageQueue.Open( pdwPID[dw],
  338. DPL_MSGQ_OBJECT_SUFFIX_APPLICATION,
  339. DPL_MSGQ_SIZE,
  340. DPL_MSGQ_OPEN_FLAG_NO_CREATE, INFINITE)) == DPN_OK)
  341. {
  342. if (MessageQueue.IsAvailable())
  343. {
  344. dplAppInfo.dwNumWaiting++;
  345. }
  346. MessageQueue.Close();
  347. }
  348. }
  349. hResultCode = PackedBuffer.AddWCHARStringToBack(pwszApplicationName);
  350. dplAppInfo.pwszApplicationName = (PWSTR)(PackedBuffer.GetTailAddress());
  351. dplAppInfo.dwFlags = 0;
  352. dplAppInfo.dwNumRunning = dwNumPID;
  353. hResultCode = PackedBuffer.AddToFront(&dplAppInfo,sizeof(DPL_APPLICATION_INFO));
  354. if( dwLengthAppLoadedList+1 > dwSizeAppLoadedList )
  355. {
  356. GUID *pTmpArray = NULL;
  357. pTmpArray = static_cast<GUID*>(DNMalloc(sizeof(GUID)*(dwSizeAppLoadedList+DPL_ENUM_APPGUID_BUFFER_GROWBY)));
  358. if( !pTmpArray )
  359. {
  360. DPFERR("DNMalloc() failed");
  361. hResultCode = DPNERR_OUTOFMEMORY;
  362. goto EXIT_DPL_EnumLocalPrograms;
  363. }
  364. memcpy( pTmpArray, pAppLoadedList, sizeof(GUID)*dwLengthAppLoadedList);
  365. dwSizeAppLoadedList += DPL_ENUM_APPGUID_BUFFER_GROWBY;
  366. DNFree(pAppLoadedList);
  367. pAppLoadedList = pTmpArray;
  368. }
  369. pAppLoadedList[dwLengthAppLoadedList] = dplAppInfo.guidApplication;
  370. dwLengthAppLoadedList++;
  371. dwEnumCount++;
  372. }
  373. LOOP_END:
  374. SubEntry.Close();
  375. dwEnumIndex++;
  376. dwKeyLen = dwMaxKeyLen;
  377. }
  378. RegistryEntry.Close();
  379. if( pwszKeyName )
  380. {
  381. DNFree(pwszKeyName);
  382. pwszKeyName= NULL;
  383. }
  384. if( pwszApplicationName )
  385. {
  386. DNFree(pwszApplicationName);
  387. pwszApplicationName = NULL;
  388. }
  389. if( pwszExecutableFilename )
  390. {
  391. DNFree(pwszExecutableFilename);
  392. pwszExecutableFilename = NULL;
  393. }
  394. }
  395. dwSizeRequired = PackedBuffer.GetSizeRequired();
  396. if (dwSizeRequired > *pdwEnumDataSize)
  397. {
  398. DPFX(DPFPREP, 7,"Buffer too small");
  399. *pdwEnumDataSize = dwSizeRequired;
  400. hResultCode = DPNERR_BUFFERTOOSMALL;
  401. }
  402. else
  403. {
  404. *pdwEnumDataItems = dwEnumCount;
  405. }
  406. if( pGuidApplication != NULL && dwEnumCount == 0 )
  407. {
  408. DPFX(DPFPREP, 0, "Specified application was not registered" );
  409. hResultCode = DPNERR_DOESNOTEXIST;
  410. }
  411. EXIT_DPL_EnumLocalPrograms:
  412. if (pwszKeyName != NULL)
  413. DNFree(pwszKeyName);
  414. if (pwszApplicationName != NULL)
  415. DNFree(pwszApplicationName);
  416. if (pwszExecutableFilename != NULL)
  417. DNFree(pwszExecutableFilename);
  418. if (pdwPID != NULL)
  419. DNFree(pdwPID);
  420. if( pAppLoadedList )
  421. DNFree(pAppLoadedList);
  422. DPF_RETURN(hResultCode);
  423. }
  424. // DPL_ConnectApplication
  425. //
  426. // Try to connect to a lobbied application. Based on DPL_CONNECT_INFO flags,
  427. // we may have to launch an application.
  428. //
  429. // If we have to launch an application, we will need to handshake the PID of the
  430. // application (as it may be ripple launched). We will pass the LobbyClient's PID on the
  431. // command line to the application launcher and expect it to be passed down to the
  432. // application. The application will open a named shared memory block using the PID and
  433. // write its PID there, and then signal a named event (using the LobbyClient's PID again).
  434. // When the waiting LobbyClient is signaled by this event, it continues its connection
  435. // process as if this was an existing running and available application.
  436. #undef DPF_MODNAME
  437. #define DPF_MODNAME "DPL_ConnectApplication"
  438. STDMETHODIMP DPL_ConnectApplication(IDirectPlay8LobbyClient *pInterface,
  439. DPL_CONNECT_INFO *const pdplConnectInfo,
  440. void *pvConnectionContext,
  441. DPNHANDLE *const hApplication,
  442. const DWORD dwTimeOut,
  443. const DWORD dwFlags)
  444. {
  445. HRESULT hResultCode = DPN_OK;
  446. DWORD dwSize = 0;
  447. BYTE *pBuffer = NULL;
  448. DPL_PROGRAM_DESC *pdplProgramDesc;
  449. DWORD *pdwProcessList = NULL;
  450. DWORD dwNumProcesses = 0;
  451. DWORD dwPID = 0;
  452. DWORD dw = 0;
  453. DPNHANDLE handle = NULL;
  454. DPL_CONNECTION *pdplConnection = NULL;
  455. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject = NULL;
  456. DPFX(DPFPREP, 3,"Parameters: pdplConnectInfo [0x%p], pvConnectionContext [0x%p], hApplication [0x%lx], dwFlags [0x%lx]",
  457. pdplConnectInfo,pvConnectionContext,hApplication,dwFlags);
  458. #ifndef DPNBUILD_NOPARAMVAL
  459. TRY
  460. {
  461. #endif // !DPNBUILD_NOPARAMVAL
  462. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  463. #ifndef DPNBUILD_NOPARAMVAL
  464. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  465. {
  466. if( FAILED( hResultCode = DPL_ValidateConnectApplication( pInterface, pdplConnectInfo, pvConnectionContext, hApplication, dwTimeOut, dwFlags ) ) )
  467. {
  468. DPFX(DPFPREP, 0, "Error validating connect application params hr=[0x%lx]", hResultCode );
  469. DPF_RETURN( hResultCode );
  470. }
  471. }
  472. // Ensure we've been initialized
  473. if (pdpLobbyObject->pReceiveQueue == NULL)
  474. {
  475. DPFERR("Not initialized");
  476. DPF_RETURN(DPNERR_UNINITIALIZED);
  477. }
  478. }
  479. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  480. {
  481. DPFERR("Invalid object" );
  482. DPF_RETURN(DPNERR_INVALIDOBJECT);
  483. }
  484. #endif // !DPNBUILD_NOPARAMVAL
  485. // Get program description
  486. dwSize = 0;
  487. pBuffer = NULL;
  488. hResultCode = DPLGetProgramDesc(&pdplConnectInfo->guidApplication,pBuffer,&dwSize);
  489. if (hResultCode != DPNERR_BUFFERTOOSMALL)
  490. {
  491. DPFERR("Could not get Program Description");
  492. goto EXIT_DPL_ConnectApplication;
  493. }
  494. if ((pBuffer = static_cast<BYTE*>(DNMalloc(dwSize))) == NULL)
  495. {
  496. DPFERR("Could not allocate space for buffer");
  497. hResultCode = DPNERR_OUTOFMEMORY;
  498. goto EXIT_DPL_ConnectApplication;
  499. }
  500. if ((hResultCode = DPLGetProgramDesc(&pdplConnectInfo->guidApplication,pBuffer,&dwSize)) != DPN_OK)
  501. {
  502. DPFERR("Could not get Program Description");
  503. DisplayDNError(0,hResultCode);
  504. goto EXIT_DPL_ConnectApplication;
  505. }
  506. pdplProgramDesc = reinterpret_cast<DPL_PROGRAM_DESC*>(pBuffer);
  507. dwPID = 0;
  508. dwNumProcesses = 0;
  509. pdwProcessList = NULL;
  510. if (!(pdplConnectInfo->dwFlags & DPLCONNECT_LAUNCHNEW)) // Only if not forcing launch
  511. {
  512. // Get process list
  513. hResultCode = DPLGetProcessList(pdplProgramDesc->pwszExecutableFilename,NULL,&dwNumProcesses);
  514. if (hResultCode != DPN_OK && hResultCode != DPNERR_BUFFERTOOSMALL)
  515. {
  516. DPFERR("Could not retrieve process list");
  517. DisplayDNError(0,hResultCode);
  518. goto EXIT_DPL_ConnectApplication;
  519. }
  520. if (hResultCode == DPNERR_BUFFERTOOSMALL)
  521. {
  522. if ((pdwProcessList = static_cast<DWORD*>(DNMalloc(dwNumProcesses*sizeof(DWORD)))) == NULL)
  523. {
  524. DPFERR("Could not create process list buffer");
  525. hResultCode = DPNERR_OUTOFMEMORY;
  526. goto EXIT_DPL_ConnectApplication;
  527. }
  528. if ((hResultCode = DPLGetProcessList(pdplProgramDesc->pwszExecutableFilename,pdwProcessList,
  529. &dwNumProcesses)) != DPN_OK)
  530. {
  531. DPFERR("Could not get process list");
  532. DisplayDNError(0,hResultCode);
  533. goto EXIT_DPL_ConnectApplication;
  534. }
  535. }
  536. // Try to connect to an already running application
  537. for (dw = 0 ; dw < dwNumProcesses ; dw++)
  538. {
  539. if ((hResultCode = DPLMakeApplicationUnavailable(pdwProcessList[dw])) == DPN_OK)
  540. {
  541. DPFX(DPFPREP, 1, "Found Existing Process=%d", pdwProcessList[dw] );
  542. dwPID = pdwProcessList[dw];
  543. break;
  544. }
  545. }
  546. if (pdwProcessList)
  547. {
  548. DNFree(pdwProcessList);
  549. pdwProcessList = NULL;
  550. }
  551. }
  552. // Launch application if none are ready to connect
  553. if ((dwPID == 0) && (pdplConnectInfo->dwFlags & (DPLCONNECT_LAUNCHNEW | DPLCONNECT_LAUNCHNOTFOUND)))
  554. {
  555. if ((hResultCode = DPLLaunchApplication(pdpLobbyObject,pdplProgramDesc,&dwPID,dwTimeOut)) != DPN_OK)
  556. {
  557. DPFERR("Could not launch application");
  558. DisplayDNError(0,hResultCode);
  559. goto EXIT_DPL_ConnectApplication;
  560. }
  561. else
  562. {
  563. DPFX(DPFPREP, 1, "Launched process dwID=%d", dwPID );
  564. }
  565. }
  566. if (dwPID == 0) // Could not make any connection
  567. {
  568. DPFERR("Could not connect to an existing application or launch a new one");
  569. hResultCode = DPNERR_NOCONNECTION;
  570. DisplayDNError( 0, hResultCode );
  571. goto EXIT_DPL_ConnectApplication;
  572. }
  573. // Create connection
  574. handle = NULL;
  575. if ((hResultCode = DPLConnectionNew(pdpLobbyObject,&handle,&pdplConnection)) != DPN_OK)
  576. {
  577. DPFERR("Could not create connection entry");
  578. DisplayDNError(0,hResultCode);
  579. goto EXIT_DPL_ConnectApplication;
  580. }
  581. pdplConnection->dwTargetProcessIdentity = dwPID;
  582. //get and store the process handle
  583. pdplConnection->hTargetProcess=DNOpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
  584. if (pdplConnection->hTargetProcess==NULL)
  585. {
  586. DPFX(DPFPREP, 0, "Could not open handle to process PID %u", dwPID);
  587. hResultCode = DPNERR_NOCONNECTION;
  588. DisplayDNError( 0, hResultCode );
  589. goto EXIT_DPL_ConnectApplication;
  590. }
  591. DPFX(DPFPREP, 0, "PID %u hProcess %u", dwPID, HANDLE_FROM_DNHANDLE(pdplConnection->hTargetProcess));
  592. // Set the context for this connection
  593. if ((hResultCode = DPLConnectionSetContext( pdpLobbyObject, handle, pvConnectionContext )) != DPN_OK )
  594. {
  595. DPFERR( "Could not set contect for connection" );
  596. DisplayDNError(0,hResultCode);
  597. goto EXIT_DPL_ConnectApplication;
  598. }
  599. // Connect to selected application instance
  600. if ((hResultCode = DPLConnectionConnect(pdpLobbyObject,handle,dwPID,TRUE)) != DPN_OK)
  601. {
  602. DPFERR("Could not connect to application");
  603. DisplayDNError(0,hResultCode);
  604. goto EXIT_DPL_ConnectApplication;
  605. }
  606. DNResetEvent(pdplConnection->hConnectEvent);
  607. // Pass lobby client info to application
  608. if ((hResultCode = DPLConnectionSendREQ(pdpLobbyObject,handle,pdpLobbyObject->dwPID,
  609. pdplConnectInfo)) != DPN_OK)
  610. {
  611. DPFERR("Could not send connection request");
  612. DisplayDNError(0,hResultCode);
  613. goto EXIT_DPL_ConnectApplication;
  614. }
  615. if (DNWaitForSingleObject(pdplConnection->hConnectEvent,INFINITE) != WAIT_OBJECT_0)
  616. {
  617. DPFERR("Wait for connection terminated");
  618. hResultCode = DPNERR_GENERIC;
  619. goto EXIT_DPL_ConnectApplication;
  620. }
  621. *hApplication = handle;
  622. hResultCode = DPN_OK;
  623. EXIT_DPL_ConnectApplication:
  624. if( FAILED(hResultCode) && handle)
  625. {
  626. DPLConnectionDisconnect(pdpLobbyObject,handle);
  627. DPLConnectionRelease(pdpLobbyObject,handle);
  628. }
  629. if (pBuffer)
  630. DNFree(pBuffer);
  631. if (pdwProcessList)
  632. DNFree(pdwProcessList);
  633. DPF_RETURN(hResultCode);
  634. }
  635. #undef DPF_MODNAME
  636. #define DPF_MODNAME "DPL_ReleaseApplication"
  637. STDMETHODIMP DPL_ReleaseApplication(IDirectPlay8LobbyClient *pInterface,
  638. const DPNHANDLE hApplication,
  639. const DWORD dwFlags )
  640. {
  641. HRESULT hResultCode;
  642. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  643. DPNHANDLE *hTargets = NULL;
  644. DWORD dwNumTargets = 0;
  645. DWORD dwTargetIndex = 0;
  646. DPFX(DPFPREP, 3,"Parameters: hApplication [0x%lx]",hApplication);
  647. #ifndef DPNBUILD_NOPARAMVAL
  648. TRY
  649. {
  650. #endif // !DPNBUILD_NOPARAMVAL
  651. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  652. #ifndef DPNBUILD_NOPARAMVAL
  653. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  654. {
  655. if( FAILED( hResultCode = DPL_ValidateReleaseApplication( pInterface, hApplication, dwFlags ) ) )
  656. {
  657. DPFX(DPFPREP, 0, "Error validating release application params hr=[0x%lx]", hResultCode );
  658. DPF_RETURN( hResultCode );
  659. }
  660. }
  661. // Ensure we've been initialized
  662. if (pdpLobbyObject->pReceiveQueue == NULL)
  663. {
  664. DPFERR("Not initialized");
  665. DPF_RETURN(DPNERR_UNINITIALIZED);
  666. }
  667. }
  668. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  669. {
  670. DPFERR("Invalid object" );
  671. DPF_RETURN(DPNERR_INVALIDOBJECT);
  672. }
  673. #endif // !DPNBUILD_NOPARAMVAL
  674. if( hApplication == DPLHANDLE_ALLCONNECTIONS )
  675. {
  676. dwNumTargets = 0;
  677. // We need loop so if someone adds a connection during our run
  678. // it gets added to our list
  679. //
  680. while( 1 )
  681. {
  682. hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
  683. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  684. {
  685. if( hTargets )
  686. {
  687. delete [] hTargets;
  688. }
  689. hTargets = new DPNHANDLE[dwNumTargets];
  690. if( hTargets == NULL )
  691. {
  692. DPFERR("Error allocating memory" );
  693. hResultCode = DPNERR_OUTOFMEMORY;
  694. dwNumTargets = 0;
  695. goto EXIT_AND_CLEANUP;
  696. }
  697. memset( hTargets, 0x00, sizeof(DPNHANDLE)*dwNumTargets);
  698. continue;
  699. }
  700. else if( FAILED( hResultCode ) )
  701. {
  702. DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode );
  703. break;
  704. }
  705. else
  706. {
  707. break;
  708. }
  709. }
  710. // Failed getting connection information
  711. if( FAILED( hResultCode ) )
  712. {
  713. if( hTargets )
  714. {
  715. delete [] hTargets;
  716. hTargets = NULL;
  717. }
  718. dwNumTargets = 0;
  719. goto EXIT_AND_CLEANUP;
  720. }
  721. }
  722. else
  723. {
  724. hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
  725. if( hTargets == NULL )
  726. {
  727. DPFERR("Error allocating memory" );
  728. hResultCode = DPNERR_OUTOFMEMORY;
  729. dwNumTargets = 0;
  730. goto EXIT_AND_CLEANUP;
  731. }
  732. dwNumTargets = 1;
  733. hTargets[0] = hApplication;
  734. }
  735. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  736. {
  737. hResultCode = DPLConnectionDisconnect(pdpLobbyObject,hTargets[dwTargetIndex]);
  738. if( FAILED( hResultCode ) )
  739. {
  740. DPFX(DPFPREP, 0, "Error disconnecting connection 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  741. }
  742. }
  743. EXIT_AND_CLEANUP:
  744. if( hTargets )
  745. delete [] hTargets;
  746. DPF_RETURN(hResultCode);
  747. }
  748. // DPLLaunchApplication
  749. //
  750. // Launch the application with a command-line argument of:
  751. // DPLID=PIDn PID=Lobby Client PID, n=launch counter (each launch increases it)
  752. // Wait for the application to signal the event (or die)
  753. #undef DPF_MODNAME
  754. #define DPF_MODNAME "DPLLaunchApplication"
  755. HRESULT DPLLaunchApplication(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  756. DPL_PROGRAM_DESC *const pdplProgramDesc,
  757. DWORD *const pdwPID,
  758. const DWORD dwTimeOut)
  759. {
  760. HRESULT hResultCode;
  761. DWORD dwAppNameLen=0; //Length of the application full name (path+exe)
  762. PWSTR pwszAppName=NULL; //Unicode version of application full name
  763. DWORD dwCmdLineLen=0; //Length of the command line string
  764. PWSTR pwszCmdLine=NULL; //Unicode version of command line to supply
  765. #ifndef UNICODE
  766. CHAR * pszAppName=NULL; //Ascii version of application full name
  767. CHAR * pszCmdLine=NULL; //Acii version of command line string
  768. CHAR *pszDefaultDir = NULL;
  769. #endif // UNICODE
  770. LONG lc;
  771. #if !defined(WINCE) || defined(WINCE_ON_DESKTOP)
  772. STARTUPINFO startupinfo;
  773. #endif // !WINCE
  774. DNPROCESS_INFORMATION pi;
  775. DWORD dwError;
  776. DNHANDLE hSyncEvents[2] = { NULL, NULL };
  777. WCHAR pwszObjectName[(sizeof(DWORD)*2)*2 + 1];
  778. TCHAR pszObjectName[(sizeof(DWORD)*2)*2 + 1 + 1]; // PID + LaunchCount + IDCHAR + NULL
  779. DPL_SHARED_CONNECT_BLOCK *pSharedBlock = NULL;
  780. DNHANDLE hFileMap = NULL;
  781. DWORD dwPID;
  782. WCHAR *wszToLaunchPath = NULL;
  783. WCHAR *wszToLaunchExecutable = NULL;
  784. DWORD dwToLaunchPathLen;
  785. // Are we launching the launcher or the executable?
  786. if( !pdplProgramDesc->pwszLauncherFilename || wcslen(pdplProgramDesc->pwszLauncherFilename) == 0 )
  787. {
  788. wszToLaunchPath = pdplProgramDesc->pwszExecutablePath;
  789. wszToLaunchExecutable = pdplProgramDesc->pwszExecutableFilename;
  790. }
  791. else
  792. {
  793. wszToLaunchPath = pdplProgramDesc->pwszLauncherPath;
  794. wszToLaunchExecutable = pdplProgramDesc->pwszLauncherFilename;
  795. }
  796. DPFX(DPFPREP, 3,"Parameters: pdplProgramDesc [0x%p]",pdplProgramDesc);
  797. DNASSERT(pdplProgramDesc != NULL);
  798. // Increment launch count
  799. lc = DNInterlockedIncrement(&pdpLobbyObject->lLaunchCount);
  800. // Synchronization event and shared memory names
  801. swprintf(pwszObjectName,L"%lx%lx",pdpLobbyObject->dwPID,lc);
  802. _stprintf(pszObjectName,_T("-%lx%lx"),pdpLobbyObject->dwPID,lc); // We will overwrite this '-' with the appropriate IDCHAR below
  803. // Compute the size of the full application name string (combination of path and exe name)
  804. if (wszToLaunchPath)
  805. {
  806. dwAppNameLen += (wcslen(wszToLaunchPath) + 1);
  807. }
  808. if (wszToLaunchExecutable)
  809. {
  810. dwAppNameLen += (wcslen(wszToLaunchExecutable) + 1);
  811. }
  812. // Compute the size of the command line string
  813. dwCmdLineLen = dwAppNameLen + 1; // Make room for the exe plus a space
  814. if (pdplProgramDesc->pwszCommandLine)
  815. {
  816. dwCmdLineLen += wcslen(pdplProgramDesc->pwszCommandLine); // Add whatever user command line exists
  817. }
  818. dwCmdLineLen += (1 + wcslen(DPL_ID_STR_W) + (sizeof(DWORD)*2*2) + 1); // Add a space plus DPLID= + PID + LaunchCount + NULL
  819. DPFX(DPFPREP, 5,"Application full name string length [%ld] WCHARs", dwAppNameLen);
  820. DPFX(DPFPREP, 5,"Command Line string length [%ld] WCHARs", dwCmdLineLen);
  821. // Allocate memory to hold the full app name and command line + check allocation was OK
  822. pwszAppName = static_cast<WCHAR *>(DNMalloc(dwAppNameLen * sizeof(WCHAR)));
  823. pwszCmdLine = static_cast<WCHAR *>(DNMalloc(dwCmdLineLen * sizeof(WCHAR)));
  824. if (pwszAppName == NULL || pwszCmdLine == NULL)
  825. {
  826. DPFERR("Could not allocate strings for app name and command line");
  827. hResultCode = DPNERR_OUTOFMEMORY;
  828. goto CLEANUP_DPLLaunch;
  829. }
  830. // Build the application full name by combining launch path with exe name
  831. *pwszAppName = L'\0';
  832. if (wszToLaunchPath)
  833. {
  834. dwToLaunchPathLen = wcslen(wszToLaunchPath);
  835. if (dwToLaunchPathLen > 0)
  836. {
  837. wcscat(pwszAppName,wszToLaunchPath);
  838. if (wszToLaunchPath[dwToLaunchPathLen - 1] != L'\\')
  839. {
  840. wcscat(pwszAppName,L"\\");
  841. }
  842. }
  843. }
  844. if (wszToLaunchExecutable)
  845. {
  846. wcscat(pwszAppName,wszToLaunchExecutable);
  847. }
  848. //
  849. // We are building: <exe> <user cmd line> DPLID=(PID and LaunchCount unique number)
  850. //
  851. //Build the command line from app name, program description and the lobby related parameters
  852. wcscpy(pwszCmdLine, pwszAppName); // Executable name and path
  853. wcscat(pwszCmdLine,L" ");
  854. if (pdplProgramDesc->pwszCommandLine)
  855. {
  856. wcscat(pwszCmdLine,pdplProgramDesc->pwszCommandLine);
  857. wcscat(pwszCmdLine,L" ");
  858. }
  859. wcscat(pwszCmdLine,DPL_ID_STR_W);
  860. wcscat(pwszCmdLine,pwszObjectName);
  861. DPFX(DPFPREP, 5,"Application full name string [%ls]",pwszAppName);
  862. DPFX(DPFPREP, 5,"Command Line string [%ls]",pwszCmdLine);
  863. // Create shared connect block to receive Application's PID
  864. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_FILEMAP;
  865. hFileMap = DNCreateFileMapping(INVALID_HANDLE_VALUE,(LPSECURITY_ATTRIBUTES) NULL,
  866. PAGE_READWRITE,(DWORD)0,sizeof(DPL_SHARED_CONNECT_BLOCK),pszObjectName);
  867. if (hFileMap == NULL)
  868. {
  869. dwError = GetLastError();
  870. DPFX(DPFPREP, 0, "CreateFileMapping() failed dwLastError [0x%lx]", dwError );
  871. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  872. goto CLEANUP_DPLLaunch;
  873. }
  874. // Map file
  875. pSharedBlock = reinterpret_cast<DPL_SHARED_CONNECT_BLOCK*>(MapViewOfFile(HANDLE_FROM_DNHANDLE(hFileMap),FILE_MAP_ALL_ACCESS,0,0,0));
  876. if (pSharedBlock == NULL)
  877. {
  878. dwError = GetLastError();
  879. DPFX(DPFPREP, 0,"MapViewOfFile() failed dwLastError [0x%lx]", dwError);
  880. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  881. goto CLEANUP_DPLLaunch;
  882. }
  883. // Create synchronization event
  884. *pszObjectName = DPL_MSGQ_OBJECT_IDCHAR_EVENT;
  885. if ((hSyncEvents[0] = DNCreateEvent(NULL,TRUE,FALSE,pszObjectName)) == NULL)
  886. {
  887. dwError = GetLastError();
  888. DPFX(DPFPREP, 0, "Create Event Failed dwLastError [0x%lx]", dwError );
  889. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  890. goto CLEANUP_DPLLaunch;
  891. }
  892. #if !defined(WINCE) || defined(WINCE_ON_DESKTOP)
  893. // More setup
  894. startupinfo.cb = sizeof(STARTUPINFO);
  895. startupinfo.lpReserved = NULL;
  896. startupinfo.lpDesktop = NULL;
  897. startupinfo.lpTitle = NULL;
  898. startupinfo.dwFlags = 0;
  899. startupinfo.cbReserved2 = 0;
  900. startupinfo.lpReserved2 = NULL;
  901. #endif // !WINCE
  902. #ifdef UNICODE
  903. #if !defined(WINCE) || defined(WINCE_ON_DESKTOP)
  904. // Launch !
  905. if (DNCreateProcess(pwszAppName, pwszCmdLine, NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  906. pdplProgramDesc->pwszCurrentDirectory,&startupinfo,&pi) == 0)
  907. #else // WINCE
  908. // WinCE AV's on a NULL first param and requires that Environment and CurrentDirectory be NULL. It also ignores STARTUPINFO.
  909. if (DNCreateProcess(pwszAppName, pwszCmdLine, NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  910. NULL,NULL,&pi) == 0)
  911. #endif // !WINCE
  912. {
  913. dwError = GetLastError();
  914. DPFX(DPFPREP, 0, "CreateProcess Failed dwLastError [0x%lx]", dwError );
  915. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  916. goto CLEANUP_DPLLaunch;
  917. }
  918. #else
  919. //Convert full app name, command line and default dir from unicode to ascii format
  920. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszAppName, pwszAppName ) ) )
  921. {
  922. dwError = GetLastError();
  923. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  924. hResultCode = DPNERR_CONVERSION;
  925. goto CLEANUP_DPLLaunch;
  926. }
  927. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszCmdLine, pwszCmdLine ) ) )
  928. {
  929. dwError = GetLastError();
  930. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  931. hResultCode = DPNERR_CONVERSION;
  932. goto CLEANUP_DPLLaunch;
  933. }
  934. if( FAILED( hResultCode = STR_AllocAndConvertToANSI( &pszDefaultDir, pdplProgramDesc->pwszCurrentDirectory ) ) )
  935. {
  936. dwError = GetLastError();
  937. DPFX(DPFPREP, 0, "String conversion failed dwError = [0x%lx]", dwError );
  938. hResultCode = DPNERR_CONVERSION;
  939. goto CLEANUP_DPLLaunch;
  940. }
  941. // Launch !
  942. if (DNCreateProcess(pszAppName,pszCmdLine,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,
  943. pszDefaultDir,&startupinfo,&pi) == 0)
  944. {
  945. dwError = GetLastError();
  946. DPFX(DPFPREP, 0, "CreateProcess Failed dwLastError [0x%lx]", dwError );
  947. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  948. goto CLEANUP_DPLLaunch;
  949. }
  950. #endif // UNICODE
  951. hSyncEvents[1] = pi.hProcess;
  952. // Wait for connection or application termination
  953. dwError = DNWaitForMultipleObjects(2,hSyncEvents,FALSE,dwTimeOut);
  954. DNCloseHandle(pi.hProcess);
  955. DNCloseHandle(pi.hThread);
  956. // Immediately clean up
  957. dwPID = pSharedBlock->dwPID;
  958. // Ensure we can continue
  959. if (dwError - WAIT_OBJECT_0 > 1)
  960. {
  961. if (dwError == WAIT_TIMEOUT)
  962. {
  963. DPFERR("Wait for application connection timed out");
  964. hResultCode = DPNERR_TIMEDOUT;
  965. goto CLEANUP_DPLLaunch;
  966. }
  967. else
  968. {
  969. DPFERR("Wait for application connection terminated mysteriously");
  970. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  971. goto CLEANUP_DPLLaunch;
  972. }
  973. }
  974. // Check if application terminated
  975. if (dwError == 1)
  976. {
  977. DPFERR("Application was terminated");
  978. hResultCode = DPNERR_CANTLAUNCHAPPLICATION;
  979. goto CLEANUP_DPLLaunch;
  980. }
  981. *pdwPID = dwPID;
  982. hResultCode = DPN_OK;
  983. CLEANUP_DPLLaunch:
  984. if( hSyncEvents[0] != NULL )
  985. DNCloseHandle( hSyncEvents[0] );
  986. if( pSharedBlock != NULL )
  987. UnmapViewOfFile(pSharedBlock);
  988. if( hFileMap != NULL )
  989. DNCloseHandle( hFileMap );
  990. if( pwszAppName != NULL )
  991. DNFree( pwszAppName );
  992. if (pwszCmdLine!=NULL)
  993. DNFree( pwszCmdLine );
  994. #ifndef UNICODE
  995. if( pszAppName != NULL )
  996. DNFree(pszAppName);
  997. if (pszCmdLine!=NULL)
  998. DNFree(pszCmdLine);
  999. if( pszDefaultDir != NULL )
  1000. DNFree(pszDefaultDir);
  1001. #endif // UNICODE
  1002. DPF_RETURN(hResultCode);
  1003. }
  1004. HRESULT DPLUpdateAppStatus(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  1005. const DPNHANDLE hSender,
  1006. BYTE *const pBuffer)
  1007. {
  1008. HRESULT hResultCode;
  1009. DPL_INTERNAL_MESSAGE_UPDATE_STATUS *pStatus;
  1010. DPL_MESSAGE_SESSION_STATUS MsgStatus;
  1011. DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p]",pBuffer);
  1012. DNASSERT(pdpLobbyObject != NULL);
  1013. DNASSERT(pBuffer != NULL);
  1014. pStatus = reinterpret_cast<DPL_INTERNAL_MESSAGE_UPDATE_STATUS*>(pBuffer);
  1015. MsgStatus.dwSize = sizeof(DPL_MESSAGE_SESSION_STATUS);
  1016. MsgStatus.dwStatus = pStatus->dwStatus;
  1017. MsgStatus.hSender = hSender;
  1018. // Return code is irrelevant, at this point we're going to indicate regardless
  1019. hResultCode = DPLConnectionGetContext( pdpLobbyObject, hSender, &MsgStatus.pvConnectionContext );
  1020. if( FAILED( hResultCode ) )
  1021. {
  1022. DPFX(DPFPREP, 0, "Error getting connection context for 0x%x hr=0x%x", hSender, hResultCode );
  1023. }
  1024. hResultCode = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
  1025. DPL_MSGID_SESSION_STATUS,
  1026. reinterpret_cast<BYTE*>(&MsgStatus));
  1027. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  1028. return(hResultCode);
  1029. }
  1030. // ----------------------------------------------------------------------------