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.

1361 lines
38 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dplgame.c
  6. * Content: Methods for game management
  7. *
  8. * History:
  9. * Date By Reason
  10. * ======= ======= ======
  11. * 4/13/96 myronth Created it
  12. * 6/24/96 kipo changed guidGame to guidApplication.
  13. * 10/23/96 myronth added client/server methods
  14. * 12/12/96 myronth Fixed DPLCONNECTION validation
  15. * 2/12/97 myronth Mass DX5 changes
  16. * 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
  17. * 4/3/97 myronth #ifdef'd out DPLC_StartGame (Nov. spec related)
  18. * 5/8/97 myronth Purged dead code
  19. * 5/22/97 myronth Changed error code processing of RunApplication which
  20. * was calling the wrong cleanup function (#8871)
  21. * 6/4/97 myronth Fixed handle leak (#9458)
  22. * 6/19/97 myronth Fixed handle leak (#10063)
  23. * 7/30/97 myronth Added support for standard lobby messaging and fixed
  24. * additional backslash on current directory bug (#10592)
  25. * 1/20/98 myronth Added WaitForConnectionSettings
  26. * 1/26/98 myronth Added OS_CompareString function for Win95
  27. * 7/07/98 kipo Define and use PROCESSENTRY32A to avoid passing
  28. * Unicode data structures to Win95 functions expecting ANSI
  29. * 7/09/99 aarono Cleaning up GetLastError misuse, must call right away,
  30. * before calling anything else, including DPF.
  31. * 7/12/00 aarono fix GUIDs for IPC to be fully significant, otherwise won't IPC.
  32. *
  33. ***************************************************************************/
  34. #include "dplobpr.h"
  35. #include <tchar.h>
  36. #include <tlhelp32.h>
  37. #include <winperf.h>
  38. //--------------------------------------------------------------------------
  39. //
  40. // Functions
  41. //
  42. //--------------------------------------------------------------------------
  43. #undef DPF_MODNAME
  44. #define DPF_MODNAME "PRV_FindGameInRegistry"
  45. BOOL PRV_FindGameInRegistry(LPGUID lpguid, LPWSTR lpwszAppName,
  46. DWORD dwNameSize, HKEY * lphkey)
  47. {
  48. HKEY hkeyDPApps, hkeyApp;
  49. DWORD dwIndex = 0;
  50. WCHAR wszGuidStr[GUID_STRING_SIZE];
  51. DWORD dwGuidStrSize = GUID_STRING_SIZE;
  52. DWORD dwType = REG_SZ;
  53. GUID guidApp;
  54. LONG lReturn;
  55. BOOL bFound = FALSE;
  56. DWORD dwSaveNameSize = dwNameSize;
  57. DPF(7, "Entering PRV_FindGameInRegistry");
  58. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu, 0x%08x",
  59. lpguid, lpwszAppName, dwNameSize, lphkey);
  60. // Open the Applications key
  61. lReturn = OS_RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_DPLAY_APPS_KEY, 0,
  62. KEY_READ, &hkeyDPApps);
  63. if(lReturn != ERROR_SUCCESS)
  64. {
  65. DPF_ERR("Unable to open DPlay Applications registry key!");
  66. return FALSE;
  67. }
  68. // Walk the list of DPlay games in the registry, looking for
  69. // the app with the right GUID
  70. while(!bFound)
  71. {
  72. // Open the next application key
  73. dwSaveNameSize = dwNameSize;
  74. dwGuidStrSize = GUID_STRING_SIZE;
  75. lReturn = OS_RegEnumKeyEx(hkeyDPApps, dwIndex++, lpwszAppName,
  76. &dwSaveNameSize, NULL, NULL, NULL, NULL);
  77. // If the enum returns no more apps, we want to bail
  78. if(lReturn != ERROR_SUCCESS)
  79. break;
  80. // Open the application key
  81. lReturn = OS_RegOpenKeyEx(hkeyDPApps, lpwszAppName, 0,
  82. KEY_READ, &hkeyApp);
  83. if(lReturn != ERROR_SUCCESS)
  84. {
  85. DPF_ERR("Unable to open app key!");
  86. continue;
  87. }
  88. // Get the GUID of the Game
  89. lReturn = OS_RegQueryValueEx(hkeyApp, SZ_GUID, NULL, &dwType,
  90. (LPBYTE)wszGuidStr, &dwGuidStrSize);
  91. if(lReturn != ERROR_SUCCESS)
  92. {
  93. RegCloseKey(hkeyApp);
  94. DPF_ERR("Unable to query GUID key value!");
  95. continue;
  96. }
  97. // Convert the string to a real GUID & Compare it to the passed in one
  98. GUIDFromString(wszGuidStr, &guidApp);
  99. if(IsEqualGUID(&guidApp, lpguid))
  100. {
  101. bFound = TRUE;
  102. break;
  103. }
  104. // Close the App key
  105. RegCloseKey(hkeyApp);
  106. }
  107. // Close the DPApps key
  108. RegCloseKey(hkeyDPApps);
  109. if(bFound)
  110. *lphkey = hkeyApp;
  111. return bFound;
  112. } // PRV_FindGameInRegistry
  113. #undef DPF_MODNAME
  114. #define DPF_MODNAME "PRV_GetKeyStringValue"
  115. BOOL PRV_GetKeyStringValue(HKEY hkeyApp, LPWSTR lpwszKey, LPWSTR * lplpwszValue)
  116. {
  117. DWORD dwType = REG_SZ;
  118. DWORD dwSize=0;
  119. LPWSTR lpwszTemp = NULL;
  120. LONG lReturn;
  121. DPF(7, "Entering PRV_GetKeyStringValue");
  122. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
  123. hkeyApp, lpwszKey, lplpwszValue);
  124. ASSERT(lplpwszValue);
  125. // Get the size of the buffer for the Path
  126. lReturn = OS_RegQueryValueEx(hkeyApp, lpwszKey, NULL, &dwType,
  127. NULL, &dwSize);
  128. if(lReturn != ERROR_SUCCESS)
  129. {
  130. DPF_ERR("Error getting size of key value!");
  131. return FALSE;
  132. }
  133. // If the size is 2, then it is an empty string (only contains a
  134. // null terminator). Treat this the same as a NULL string or a
  135. // missing key and fail it.
  136. if(dwSize <= 2)
  137. return FALSE;
  138. // Alloc the buffer for the Path
  139. lpwszTemp = DPMEM_ALLOC(dwSize);
  140. if(!lpwszTemp)
  141. {
  142. DPF_ERR("Unable to allocate temporary string for Path!");
  143. return FALSE;
  144. }
  145. // Get the value itself
  146. lReturn = OS_RegQueryValueEx(hkeyApp, lpwszKey, NULL, &dwType,
  147. (LPBYTE)lpwszTemp, &dwSize);
  148. if(lReturn != ERROR_SUCCESS)
  149. {
  150. DPMEM_FREE(lpwszTemp);
  151. DPF_ERR("Unable to get key value!");
  152. return FALSE;
  153. }
  154. *lplpwszValue = lpwszTemp;
  155. return TRUE;
  156. } // PRV_GetKeyStringValue
  157. #undef DPF_MODNAME
  158. #define DPF_MODNAME "PRV_FreeConnectInfo"
  159. BOOL PRV_FreeConnectInfo(LPCONNECTINFO lpci)
  160. {
  161. DPF(7, "Entering PRV_FreeConnectInfo");
  162. DPF(9, "Parameters: 0x%08x", lpci);
  163. if(!lpci)
  164. return TRUE;
  165. if(lpci->lpszName)
  166. DPMEM_FREE(lpci->lpszName);
  167. if(lpci->lpszPath)
  168. DPMEM_FREE(lpci->lpszPath);
  169. if(lpci->lpszFile)
  170. DPMEM_FREE(lpci->lpszFile);
  171. if(lpci->lpszCommandLine)
  172. DPMEM_FREE(lpci->lpszCommandLine);
  173. if(lpci->lpszCurrentDir)
  174. DPMEM_FREE(lpci->lpszCurrentDir);
  175. if(lpci->lpszAppLauncherName)
  176. DPMEM_FREE(lpci->lpszAppLauncherName);
  177. return TRUE;
  178. } // PRV_FreeConnectInfo
  179. #undef DPF_MODNAME
  180. #define DPF_MODNAME "PRV_GetConnectInfoFromRegistry"
  181. BOOL PRV_GetConnectInfoFromRegistry(LPCONNECTINFO lpci)
  182. {
  183. LPWSTR lpwszAppName;
  184. HKEY hkeyApp = NULL;
  185. LPWSTR lpwszTemp;
  186. DWORD dwSize = 0;
  187. DWORD dwError;
  188. GUID guidApp;
  189. BOOL bReturn;
  190. DPF(7, "Entering PRV_GetConnectInfoFromRegistry");
  191. DPF(9, "Parameters: 0x%08x", lpci);
  192. // Clear our ConnectInfo structure since we will be overwriting
  193. // whatever is in it, and we are making assumptions that the
  194. // string pointers are NULL to start with. However, we need
  195. // the Application guid, so save it off
  196. guidApp = lpci->guidApplication;
  197. memset(lpci, 0, sizeof(CONNECTINFO));
  198. lpci->guidApplication = guidApp;
  199. // Allocate memory for the App Name
  200. lpwszAppName = DPMEM_ALLOC(DPLOBBY_REGISTRY_NAMELEN*sizeof(WCHAR));
  201. if(!lpwszAppName)
  202. {
  203. DPF_ERR("Unable to allocate memory for App Name!");
  204. return FALSE;
  205. }
  206. // Open the registry key for the App
  207. if(!PRV_FindGameInRegistry(&(lpci->guidApplication), lpwszAppName,
  208. DPLOBBY_REGISTRY_NAMELEN, &hkeyApp))
  209. {
  210. DPMEM_FREE(lpwszAppName);
  211. DPF_ERR("Unable to find game in registry!");
  212. return FALSE;
  213. }
  214. lpci->lpszName = lpwszAppName;
  215. // Get the string value for the Path. If this fails, we
  216. // can use a NULL path, which represents the default path
  217. // on the CreateProcess call
  218. if(PRV_GetKeyStringValue(hkeyApp, SZ_PATH, &lpwszTemp))
  219. {
  220. lpci->lpszPath = lpwszTemp;
  221. }
  222. // Get the string value for the File
  223. if(!PRV_GetKeyStringValue(hkeyApp, SZ_FILE, &lpwszTemp))
  224. {
  225. DPF_ERR("Error getting value for File key!");
  226. bReturn = FALSE;
  227. goto EXIT_GETCONNECTINFO;
  228. }
  229. lpci->lpszFile = lpwszTemp;
  230. // Get the string value for the CommandLine. If this fails,
  231. // we can pass a NULL command line to the CreateProcess call
  232. if(PRV_GetKeyStringValue(hkeyApp, SZ_COMMANDLINE, &lpwszTemp))
  233. {
  234. lpci->lpszCommandLine = lpwszTemp;
  235. }
  236. // Get the string value for the AppLauncherName. If this fails,
  237. // then we assume there is no launcher application.
  238. if(PRV_GetKeyStringValue(hkeyApp, SZ_LAUNCHER, &lpwszTemp))
  239. {
  240. lpci->lpszAppLauncherName = lpwszTemp;
  241. }
  242. // Get the string value for the CurrentDir. If this fails, just
  243. // use the value returned by GetCurrentDirectory.
  244. if(!PRV_GetKeyStringValue(hkeyApp, SZ_CURRENTDIR, &lpwszTemp))
  245. {
  246. // Get the size of the string
  247. dwSize = OS_GetCurrentDirectory(0, NULL);
  248. if(!dwSize)
  249. {
  250. dwError = GetLastError();
  251. // WARNING: this last error value may not be correct in debug
  252. // since OS_GetCurrentDirectory may have called another function.
  253. DPF(0, "GetCurrentDirectory returned an error! dwError = %d", dwError);
  254. bReturn = FALSE;
  255. goto EXIT_GETCONNECTINFO;
  256. }
  257. lpwszTemp = DPMEM_ALLOC(dwSize * sizeof(WCHAR));
  258. if(!lpwszTemp)
  259. {
  260. DPF_ERR("Unable to allocate temporary string for CurrentDirectory!");
  261. bReturn = FALSE;
  262. goto EXIT_GETCONNECTINFO;
  263. }
  264. if(!OS_GetCurrentDirectory(dwSize, lpwszTemp))
  265. {
  266. DPF_ERR("Unable to get CurrentDirectory!");
  267. bReturn = FALSE;
  268. goto EXIT_GETCONNECTINFO;
  269. }
  270. }
  271. lpci->lpszCurrentDir = lpwszTemp;
  272. bReturn = TRUE;
  273. EXIT_GETCONNECTINFO:
  274. // Free any string we allocated if we failed
  275. if(!bReturn)
  276. PRV_FreeConnectInfo(lpci);
  277. // Close the Apps key
  278. if(hkeyApp)
  279. RegCloseKey(hkeyApp);
  280. return bReturn;
  281. } // PRV_GetConnectInfoFromRegistry
  282. #undef DPF_MODNAME
  283. #define DPF_MODNAME "PRV_CreateGameProcess"
  284. HRESULT PRV_CreateGameProcess(LPCONNECTINFO lpci, LPPROCESS_INFORMATION lppi)
  285. {
  286. STARTUPINFO si;
  287. HRESULT hr;
  288. LPWSTR lpwszPathAndFile = NULL;
  289. LPWSTR lpwszTemp = NULL;
  290. LPWSTR lpwszCommandLine = NULL;
  291. LPWSTR lpwszFileToRun;
  292. DWORD dwPathSize,
  293. dwFileSize,
  294. dwCurrentDirSize,
  295. dwPathAndFileSize,
  296. dwCommandLineSize,
  297. dwIPCSwitchSize,
  298. dwError;
  299. DPF(7, "Entering PRV_CreateGameProcess");
  300. DPF(9, "Parameters: 0x%08x, 0x%08x", lpci, lppi);
  301. // Allocate enough memory for the Path, File, an additional backslash,
  302. // and the null termination
  303. // Note: the following two OS_StrLen calls with count the null terms
  304. // on the end of each string. Since this comes to two characters
  305. // (4 bytes), this will account for our null terminator and the
  306. // possible additional backslash after concatenation. Thus, the
  307. // size here is big enough for the concatenated string.
  308. dwPathSize = OS_StrLen(lpci->lpszPath);
  309. if(lpci->lpszAppLauncherName){
  310. // when launching with an applauncher, we need a GUID.
  311. OS_CreateGuid(&lpci->guidIPC);
  312. lpci->guidIPC.Data1 |= 0x10000000; // make life easy by having fully byte significant first dword.
  313. lpwszFileToRun = lpci->lpszAppLauncherName;
  314. } else {
  315. lpwszFileToRun = lpci->lpszFile;
  316. }
  317. dwFileSize = OS_StrLen(lpwszFileToRun);
  318. dwPathAndFileSize = dwPathSize + dwFileSize;
  319. lpwszPathAndFile = DPMEM_ALLOC(dwPathAndFileSize * sizeof(WCHAR));
  320. if(!lpwszPathAndFile)
  321. {
  322. DPF_ERR("Couldn't allocate memory for temporary string!");
  323. hr = DPERR_OUTOFMEMORY;
  324. goto ERROR_CREATE_GAME_PROCESS;
  325. }
  326. // Concatenate the path & file together
  327. if(dwPathSize)
  328. {
  329. memcpy(lpwszPathAndFile, lpci->lpszPath, (dwPathSize * sizeof(WCHAR)));
  330. lpwszTemp = lpwszPathAndFile + dwPathSize - 1;
  331. // Only add a backslash if one doesn't already exists
  332. if(memcmp((lpwszTemp - 1), SZ_BACKSLASH, sizeof(WCHAR)))
  333. memcpy(lpwszTemp++, SZ_BACKSLASH, sizeof(WCHAR));
  334. else
  335. // since we didn't add a backslash, the actual used
  336. // size is one WCHAR less than the full allocated size so
  337. // we need to reduce it so when we calculate the spot for
  338. // the command line we aren't after a NULL.
  339. dwPathAndFileSize--;
  340. }
  341. else
  342. lpwszTemp = lpwszPathAndFile;
  343. memcpy(lpwszTemp, lpwszFileToRun, (dwFileSize * sizeof(WCHAR)));
  344. // Allocate memory for temporary command line string
  345. // Note: Since the OS_StrLen function counts the null terminator,
  346. // we will be large enough to include the extra space when we
  347. // concatenate the two strings together.
  348. dwCommandLineSize = OS_StrLen(lpci->lpszCommandLine);
  349. if(lpci->lpszAppLauncherName){
  350. // leave space for GUID on the command line
  351. dwIPCSwitchSize = sizeof(SZ_DP_IPC_GUID SZ_GUID_PROTOTYPE)/sizeof(WCHAR);
  352. } else {
  353. dwIPCSwitchSize = 0;
  354. }
  355. lpwszCommandLine = DPMEM_ALLOC(((dwCommandLineSize + dwPathAndFileSize+dwIPCSwitchSize) *
  356. sizeof(WCHAR)));
  357. if(!lpwszCommandLine)
  358. {
  359. // REVIEW!!!! -- We should fix these error paths post-DX3
  360. DPF_ERR("Couldn't allocate memory for temporary command line string!");
  361. hr = DPERR_OUTOFMEMORY;
  362. goto ERROR_CREATE_GAME_PROCESS;
  363. }
  364. // Concatenate the path & file string with the rest of the command line
  365. memcpy(lpwszCommandLine, lpwszPathAndFile, (dwPathAndFileSize *
  366. sizeof(WCHAR)));
  367. // Add the rest of the command line if it exists
  368. lpwszTemp = lpwszCommandLine + dwPathAndFileSize;
  369. if(dwCommandLineSize)
  370. {
  371. // First change the null terminator to a space
  372. lpwszTemp -= 1;
  373. memcpy(lpwszTemp++, SZ_SPACE, sizeof(WCHAR));
  374. // Now copy in the command line
  375. memcpy(lpwszTemp, lpci->lpszCommandLine, (dwCommandLineSize *
  376. sizeof(WCHAR)));
  377. }
  378. if(dwIPCSwitchSize){
  379. // add switch with a GUID on the command line for IPC when
  380. // application is started by a launcher
  381. lpwszTemp += dwCommandLineSize-1;
  382. // change NULL terminator to a space
  383. memcpy(lpwszTemp++, SZ_SPACE, sizeof(WCHAR));
  384. // copy /dplay_ipc_guid: but skip the NULL
  385. memcpy(lpwszTemp, SZ_DP_IPC_GUID, sizeof(SZ_DP_IPC_GUID)-sizeof(WCHAR));
  386. lpwszTemp+=(sizeof(SZ_DP_IPC_GUID)-sizeof(WCHAR))/sizeof(WCHAR);
  387. // Copy the GUID directly into the target
  388. StringFromGUID(&lpci->guidIPC,lpwszTemp,GUID_STRING_SIZE);
  389. }
  390. // Make sure the CurrentDirectory string doesn't have a trailing backslash
  391. // (This will cause CreateProcess to not use the right directory)
  392. dwCurrentDirSize = OS_StrLen(lpci->lpszCurrentDir);
  393. if(dwCurrentDirSize > 2)
  394. {
  395. lpwszTemp = lpci->lpszCurrentDir + dwCurrentDirSize - 2;
  396. if(!(memcmp((lpwszTemp), SZ_BACKSLASH, sizeof(WCHAR))))
  397. memset(lpwszTemp, 0, sizeof(WCHAR));
  398. }
  399. // Create the game's process in a suspended state
  400. memset(&si, 0, sizeof(STARTUPINFO));
  401. si.cb = sizeof(STARTUPINFO);
  402. if(!OS_CreateProcess(lpwszPathAndFile, lpwszCommandLine, NULL,
  403. NULL, FALSE, (CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE |
  404. CREATE_NEW_CONSOLE), NULL, lpci->lpszCurrentDir, &si, lppi))
  405. {
  406. dwError = GetLastError();
  407. // WARNING Last error produced here may not be correct since OS_CreateProcess
  408. // may call out to other functions (like DPF) before returning.
  409. DPF_ERR("Couldn't create game process");
  410. DPF(0, "CreateProcess error = 0x%08x, (WARNING Error may not be correct)", dwError);
  411. hr = DPERR_CANTCREATEPROCESS;
  412. goto ERROR_CREATE_GAME_PROCESS;
  413. }
  414. hr = DP_OK;
  415. // Fall through
  416. ERROR_CREATE_GAME_PROCESS:
  417. if(lpwszPathAndFile)
  418. DPMEM_FREE(lpwszPathAndFile);
  419. if(lpwszCommandLine)
  420. DPMEM_FREE(lpwszCommandLine);
  421. return hr;
  422. } // PRV_CreateGameProcess
  423. #undef DPF_MODNAME
  424. #define DPF_MODNAME "PRV_IsAppInWaitMode"
  425. BOOL PRV_IsAppInWaitMode(DWORD dwProcessID)
  426. {
  427. DPLOBBYI_GAMENODE gn;
  428. LPDPLOBBYI_CONNCONTROL lpConnControl = NULL;
  429. SECURITY_ATTRIBUTES sa;
  430. WCHAR szName[MAX_MMFILENAME_LENGTH * sizeof(WCHAR)];
  431. HRESULT hr;
  432. HANDLE hFile = NULL;
  433. HANDLE hMutex = NULL;
  434. BOOL bReturn = FALSE;
  435. DWORD dwError;
  436. DPF(7, "Entering PRV_IsAppInWaitMode");
  437. DPF(9, "Parameters: %lu", dwProcessID);
  438. // Setup a temporary gamenode structure
  439. memset(&gn, 0, sizeof(DPLOBBYI_GAMENODE));
  440. gn.dwFlags = GN_LOBBY_CLIENT;
  441. gn.dwGameProcessID = dwProcessID;
  442. // Get the name of the shared connection settings buffer
  443. hr = PRV_GetInternalName(&gn, TYPE_CONNECT_DATA_FILE, (LPWSTR)szName);
  444. if(FAILED(hr))
  445. {
  446. DPF(5, "Unable to get name for shared conn settings buffer");
  447. goto EXIT_ISAPPINWAITMODE;
  448. }
  449. // Map the file into our process
  450. hFile = OS_OpenFileMapping(FILE_MAP_ALL_ACCESS, TRUE, (LPWSTR)szName);
  451. if(!hFile)
  452. {
  453. dwError = GetLastError();
  454. // WARNING: Error may not be correct since OpenFileMapping calls out to other functions before returning.
  455. DPF(5, "Couldn't get a handle to the shared local memory, dwError = %lu (ERROR MAY NOT BE CORRECT)", dwError);
  456. goto EXIT_ISAPPINWAITMODE;
  457. }
  458. // Map a View of the file
  459. lpConnControl = MapViewOfFile(hFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  460. if(!lpConnControl)
  461. {
  462. dwError = GetLastError();
  463. DPF(5, "Unable to get pointer to shared local memory, dwError = %lu", dwError);
  464. goto EXIT_ISAPPINWAITMODE;
  465. }
  466. // Get the name of the connection settings buffer mutex
  467. hr = PRV_GetInternalName(&gn, TYPE_CONNECT_DATA_MUTEX, (LPWSTR)szName);
  468. if(FAILED(hr))
  469. {
  470. DPF(5, "Unable to get name for shared conn settings buffer mutex");
  471. goto EXIT_ISAPPINWAITMODE;
  472. }
  473. // Set up the security attributes (so that our objects can
  474. // be inheritable)
  475. memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
  476. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  477. sa.bInheritHandle = TRUE;
  478. // Open the Mutex
  479. hMutex = OS_CreateMutex(&sa, FALSE, (LPWSTR)szName);
  480. if(!hMutex)
  481. {
  482. DPF(5, "Unable to create shared conn settings buffer mutex");
  483. goto EXIT_ISAPPINWAITMODE;
  484. }
  485. // Now grab the mutex and see if the app is in wait mode (and
  486. // it is not in pending mode)
  487. WaitForSingleObject(hMutex, INFINITE);
  488. if((lpConnControl->dwFlags & BC_WAIT_MODE) &&
  489. !(lpConnControl->dwFlags & BC_PENDING_CONNECT))
  490. {
  491. // Put the app in pending mode
  492. lpConnControl->dwFlags |= BC_PENDING_CONNECT;
  493. // Set the return code to true
  494. bReturn = TRUE;
  495. }
  496. // Release the mutex
  497. ReleaseMutex(hMutex);
  498. // Fall through
  499. EXIT_ISAPPINWAITMODE:
  500. if(lpConnControl)
  501. UnmapViewOfFile(lpConnControl);
  502. if(hFile)
  503. CloseHandle(hFile);
  504. if(hMutex)
  505. CloseHandle(hMutex);
  506. return bReturn;
  507. } // PRV_IsAppInWaitMode
  508. #undef DPF_MODNAME
  509. #define DPF_MODNAME "PRV_FindRunningAppNT"
  510. #define INITIAL_SIZE 51200
  511. #define EXTEND_SIZE 25600
  512. #define REGKEY_PERF _T("software\\microsoft\\windows nt\\currentversion\\perflib")
  513. #define REGSUBKEY_COUNTERS _T("Counters")
  514. #define PROCESS_COUNTER _T("process")
  515. #define PROCESSID_COUNTER _T("id process")
  516. #if 0
  517. HRESULT PRV_FindRunningAppNT(LPCONNECTINFO lpci, LPPROCESS_INFORMATION lppi)
  518. {
  519. HANDLE hProcess = NULL;
  520. DWORD dwProcessID = 0;
  521. DWORD dwError;
  522. HRESULT hr = -1;
  523. DWORD rc;
  524. HKEY hKeyNames;
  525. DWORD dwType;
  526. DWORD dwSize;
  527. LPBYTE buf = NULL;
  528. TCHAR szSubKey[1024];
  529. LANGID lid;
  530. LPTSTR p;
  531. LPTSTR p2;
  532. LPWSTR nameStr;
  533. PPERF_DATA_BLOCK pPerf;
  534. PPERF_OBJECT_TYPE pObj;
  535. PPERF_INSTANCE_DEFINITION pInst;
  536. PPERF_COUNTER_BLOCK pCounter;
  537. PPERF_COUNTER_DEFINITION pCounterDef;
  538. DWORD i;
  539. DWORD dwProcessIdTitle;
  540. DWORD dwProcessIdCounter;
  541. DWORD dwNumTasks;
  542. INT ccStrFind;
  543. INT ccStrMatch;
  544. // on Whistler, the string to match in the process table has changed from
  545. // being the name of the process without the ".exe" at the end to being
  546. // the name of the process followed by an '_' and the processid, so we
  547. // build that string too to compare and accept either when finding the app.
  548. WCHAR procString[64];//name concated with proc id for Whistler
  549. WCHAR *procStringBaseNameEnd;
  550. INT ccStrFindProcBased;
  551. //
  552. // Look for the list of counters. Always use the neutral
  553. // English version, regardless of the local language. We
  554. // are looking for some particular keys, and we are always
  555. // going to do our looking in English. We are not going
  556. // to show the user the counter names, so there is no need
  557. // to go find the corresponding name in the local language.
  558. //
  559. lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
  560. wsprintf( szSubKey, _T("%s\\%03x"), REGKEY_PERF, lid );
  561. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  562. szSubKey,
  563. 0,
  564. KEY_READ,
  565. &hKeyNames
  566. );
  567. if (rc != ERROR_SUCCESS) {
  568. goto exit;
  569. }
  570. //
  571. // get the buffer size for the counter names
  572. //
  573. rc = RegQueryValueEx( hKeyNames,
  574. REGSUBKEY_COUNTERS,
  575. NULL,
  576. &dwType,
  577. NULL,
  578. &dwSize
  579. );
  580. if (rc != ERROR_SUCCESS) {
  581. goto exit;
  582. }
  583. //
  584. // allocate the counter names buffer
  585. //
  586. buf = (LPBYTE) DPMEM_ALLOC( dwSize );
  587. if (buf == NULL) {
  588. goto exit;
  589. }
  590. memset( buf, 0, dwSize );
  591. //
  592. // read the counter names from the registry
  593. //
  594. rc = RegQueryValueEx( hKeyNames,
  595. REGSUBKEY_COUNTERS,
  596. NULL,
  597. &dwType,
  598. buf,
  599. &dwSize
  600. );
  601. if (rc != ERROR_SUCCESS) {
  602. goto exit;
  603. }
  604. //
  605. // now loop thru the counter names looking for the following counters:
  606. //
  607. // 1. "Process" process name
  608. // 2. "ID Process" process id
  609. //
  610. // the buffer contains multiple null terminated strings and then
  611. // finally null terminated at the end. the strings are in pairs of
  612. // counter number and counter name.
  613. //
  614. // convert the string to ansi because we can't use _wtoi
  615. p = (LPTSTR) buf;
  616. while (*p) {
  617. if (p > (LPTSTR) buf) {
  618. for( p2=p-2; _istdigit(*p2); p2--) ;
  619. }
  620. if (_tcsicmp(p, PROCESS_COUNTER) == 0) {
  621. //
  622. // look backwards for the counter number
  623. //
  624. for( p2=p-2; _istdigit(*p2); p2--) ;
  625. _tcscpy( szSubKey, p2+1 );
  626. }
  627. else
  628. if (_tcsicmp(p, PROCESSID_COUNTER) == 0) {
  629. //
  630. // look backwards for the counter number
  631. //
  632. for( p2=p-2; _istdigit(*p2); p2--) ;
  633. dwProcessIdTitle = _ttoi( p2+1 );
  634. }
  635. //
  636. // next string
  637. //
  638. p += (_tcslen(p) + 1);
  639. }
  640. //
  641. // free the counter names buffer
  642. //
  643. DPMEM_FREE( buf );
  644. //
  645. // allocate the initial buffer for the performance data
  646. //
  647. dwSize = INITIAL_SIZE;
  648. buf = DPMEM_ALLOC( dwSize );
  649. if (buf == NULL) {
  650. goto exit;
  651. }
  652. memset( buf, 0, dwSize );
  653. while (TRUE) {
  654. rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  655. szSubKey,
  656. NULL,
  657. &dwType,
  658. buf,
  659. &dwSize
  660. );
  661. pPerf = (PPERF_DATA_BLOCK) buf;
  662. //
  663. // check for success and valid perf data block signature
  664. //
  665. if ((rc == ERROR_SUCCESS) &&
  666. (dwSize > 0) &&
  667. (pPerf)->Signature[0] == (WCHAR)'P' &&
  668. (pPerf)->Signature[1] == (WCHAR)'E' &&
  669. (pPerf)->Signature[2] == (WCHAR)'R' &&
  670. (pPerf)->Signature[3] == (WCHAR)'F' ) {
  671. break;
  672. }
  673. //
  674. // if buffer is not big enough, reallocate and try again
  675. //
  676. if (rc == ERROR_MORE_DATA) {
  677. dwSize += EXTEND_SIZE;
  678. buf = DPMEM_REALLOC( buf, dwSize );
  679. memset( buf, 0, dwSize );
  680. }
  681. else {
  682. goto exit;
  683. }
  684. }
  685. //
  686. // set the perf_object_type pointer
  687. //
  688. pObj = (PPERF_OBJECT_TYPE) ((DWORD_PTR)pPerf + pPerf->HeaderLength);
  689. //
  690. // loop thru the performance counter definition records looking
  691. // for the process id counter and then save its offset
  692. //
  693. pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD_PTR)pObj + pObj->HeaderLength);
  694. for (i=0; i<(DWORD)pObj->NumCounters; i++) {
  695. if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
  696. dwProcessIdCounter = pCounterDef->CounterOffset;
  697. break;
  698. }
  699. pCounterDef++;
  700. }
  701. dwNumTasks = (DWORD)pObj->NumInstances;
  702. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pObj + pObj->DefinitionLength);
  703. //
  704. // loop thru the performance instance data extracting each process name
  705. // and process id
  706. //
  707. ccStrFind=(WSTRLEN(lpci->lpszFile)-1)-4; // don't include .exe in compare
  708. if(ccStrFind > 15){
  709. ccStrFind=15;
  710. }
  711. wcsncpy(procString, lpci->lpszFile, ccStrFind);
  712. procString[ccStrFind]=L'_';
  713. procStringBaseNameEnd=&procString[ccStrFind+1];
  714. for (i=0; i<dwNumTasks; i++) {
  715. //
  716. // pointer to the process name
  717. //
  718. nameStr = (LPWSTR) ((DWORD_PTR)pInst + pInst->NameOffset);
  719. pCounter = (PPERF_COUNTER_BLOCK) ((DWORD_PTR)pInst + pInst->ByteLength);
  720. // Compare the process name with the executable name we are
  721. // looking for
  722. dwProcessID = *((LPDWORD) ((DWORD_PTR)pCounter + dwProcessIdCounter));
  723. // tack processid onto end of base name to test on Whistler
  724. _itow(dwProcessID, procStringBaseNameEnd, 10);
  725. ccStrFindProcBased=WSTRLEN(procString)-1;
  726. ccStrMatch=WSTRLEN(nameStr)-1; // 1 for NULL
  727. if(ccStrMatch == 16){ // when it is 16, it included a trailing . so strip it.
  728. ccStrMatch--;
  729. }
  730. if((CSTR_EQUAL == OS_CompareString(LOCALE_SYSTEM_DEFAULT,
  731. NORM_IGNORECASE, nameStr, ccStrMatch, lpci->lpszFile, ccStrFind)) ||
  732. (CSTR_EQUAL == OS_CompareString(LOCALE_SYSTEM_DEFAULT,
  733. NORM_IGNORECASE, nameStr, ccStrMatch, procString, ccStrFindProcBased))
  734. )
  735. {
  736. // See if the process is in wait mode
  737. if(PRV_IsAppInWaitMode(dwProcessID))
  738. {
  739. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
  740. if(!hProcess)
  741. {
  742. dwError = GetLastError();
  743. DPF_ERRVAL("Unable to open running process, dwError = %lu", dwError);
  744. goto exit;
  745. }
  746. else
  747. {
  748. // Save off the stuff we need
  749. lppi->dwProcessId = dwProcessID;
  750. lppi->hProcess = hProcess;
  751. hr = DP_OK;
  752. goto exit;
  753. }
  754. } // IsAppInWaitMode
  755. } // Are Filenames Equal
  756. //
  757. // next process
  758. //
  759. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pCounter + pCounter->ByteLength);
  760. }
  761. exit:
  762. if (buf) {
  763. DPMEM_FREE( buf );
  764. }
  765. RegCloseKey( hKeyNames );
  766. RegCloseKey( HKEY_PERFORMANCE_DATA );
  767. return hr;
  768. } // PRV_FindRunningAppNT
  769. #endif
  770. // If you build with the UNICODE flag set, the headers will redefine PROCESSENTRY32
  771. // to be PROCESSENTRY32W. Unfortunately, passing PROCESSENTRY32W to Win9x functions
  772. // will cause them to fail (because of the embedded Unicode string).
  773. //
  774. // Fix is to define our own PROCESSENTRY32A which is guaranteed to have an ANSI
  775. // embedded string which Win9x will always accept.
  776. typedef struct tagPROCESSENTRY32 PROCESSENTRY32A;
  777. typedef PROCESSENTRY32A *LPPROCESSENTRY32A;
  778. #undef DPF_MODNAME
  779. #define DPF_MODNAME "PRV_FindRunningAppWin9x"
  780. HRESULT PRV_FindRunningAppWin9x(LPCONNECTINFO lpci, LPPROCESS_INFORMATION lppi)
  781. {
  782. HANDLE hSnapShot = NULL;
  783. PROCESSENTRY32A procentry;
  784. BOOL bFlag;
  785. HRESULT hr = DPERR_UNAVAILABLE;
  786. LPBYTE lpbTemp = NULL;
  787. DWORD dwStrSize;
  788. LPWSTR lpszFile = NULL;
  789. HANDLE hProcess = NULL;
  790. DWORD dwError;
  791. HANDLE hInstLib = NULL;
  792. HRESULT hrTemp;
  793. // ToolHelp Function Pointers.
  794. HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD);
  795. BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32A);
  796. BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32A);
  797. DPF(7, "Entering PRV_FindRunningAppWin9x");
  798. DPF(9, "Parameters: 0x%08x, 0x%08x", lpci, lppi);
  799. // Load library and get the procedures explicitly. We do
  800. // this so that we can load the entry points dynamically,
  801. // which allows us to build correctly under WinNT even
  802. // though the NT kernel32 doesn't have these entry points
  803. hInstLib = LoadLibraryA( "Kernel32.DLL" );
  804. if(hInstLib == NULL)
  805. {
  806. DPF_ERR("Unable to load Kernel32.DLL");
  807. goto EXIT_FIND_RUNNING_APP_WIN9X;
  808. }
  809. // Get procedure addresses.
  810. // We are linking to these functions of Kernel32
  811. // explicitly, because otherwise a module using
  812. // this code would fail to load under Windows NT,
  813. // which does not have the Toolhelp32
  814. // functions in the Kernel 32.
  815. lpfCreateToolhelp32Snapshot=(HANDLE(WINAPI *)(DWORD,DWORD)) GetProcAddress( hInstLib, "CreateToolhelp32Snapshot" );
  816. lpfProcess32First=(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32A)) GetProcAddress( hInstLib, "Process32First" );
  817. lpfProcess32Next=(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32A)) GetProcAddress( hInstLib, "Process32Next" );
  818. if( lpfProcess32Next == NULL || lpfProcess32First == NULL || lpfCreateToolhelp32Snapshot == NULL )
  819. {
  820. DPF_ERR("Unable to get needed entry points in PSAPI.DLL");
  821. goto EXIT_FIND_RUNNING_APP_WIN9X;
  822. }
  823. // Get a handle to a Toolhelp snapshot of the systems processes.
  824. hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  825. if(hSnapShot == INVALID_HANDLE_VALUE)
  826. {
  827. DPF_ERR("Unable to get snapshot of system processes");
  828. goto EXIT_FIND_RUNNING_APP_WIN9X;
  829. }
  830. // Get the first process' information.
  831. procentry.dwSize = sizeof(PROCESSENTRY32A);
  832. bFlag = lpfProcess32First(hSnapShot, &procentry);
  833. // While there are processes, keep looping.
  834. while(bFlag)
  835. {
  836. // Walk the path and filename string (guaranteed to be ANSI)
  837. // looking for the final backslash (\). Once we find it,
  838. // convert the filename to Unicode so we can compare it.
  839. dwStrSize = lstrlenA((LPBYTE)procentry.szExeFile);
  840. lpbTemp = (LPBYTE)procentry.szExeFile + dwStrSize - 1;
  841. while(--dwStrSize)
  842. {
  843. if(lpbTemp[0] == '\\')
  844. {
  845. lpbTemp++;
  846. break;
  847. }
  848. else
  849. lpbTemp--;
  850. }
  851. hrTemp = GetWideStringFromAnsi(&lpszFile, (LPSTR)lpbTemp);
  852. if(FAILED(hrTemp))
  853. {
  854. DPF_ERR("Failed making temporary copy of filename string");
  855. goto EXIT_FIND_RUNNING_APP_WIN9X;
  856. }
  857. // Compare the process name with the executable name we are
  858. // looking for
  859. if(CSTR_EQUAL == OS_CompareString(LOCALE_SYSTEM_DEFAULT,
  860. NORM_IGNORECASE, lpszFile, -1, lpci->lpszFile, -1))
  861. {
  862. // See if the process is in wait mode
  863. if(PRV_IsAppInWaitMode(procentry.th32ProcessID))
  864. {
  865. // Open the process since Windows9x doesn't do
  866. // it for us.
  867. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procentry.th32ProcessID);
  868. if(!hProcess)
  869. {
  870. dwError = GetLastError();
  871. DPF_ERRVAL("Unable to open running process, dwError = %lu", dwError);
  872. bFlag = FALSE;
  873. }
  874. else
  875. {
  876. // Save off the stuff we need
  877. lppi->dwProcessId = procentry.th32ProcessID;
  878. lppi->hProcess = hProcess;
  879. hr = DP_OK;
  880. bFlag = FALSE;
  881. }
  882. } // IsAppInWaitMode
  883. } // Are Filenames Equal
  884. // Free our temporary string
  885. DPMEM_FREE(lpszFile);
  886. // If we haven't found it, and we didn't error, then move to
  887. // the next process
  888. if(bFlag)
  889. {
  890. // Move to the next process
  891. procentry.dwSize = sizeof(PROCESSENTRY32A);
  892. bFlag = lpfProcess32Next(hSnapShot, &procentry);
  893. }
  894. }
  895. EXIT_FIND_RUNNING_APP_WIN9X:
  896. if(hSnapShot)
  897. CloseHandle(hSnapShot);
  898. if(hInstLib)
  899. FreeLibrary(hInstLib) ;
  900. return hr;
  901. } // PRV_FindRunningAppWin9x
  902. #undef DPF_MODNAME
  903. #define DPF_MODNAME "PRV_FindRunningApp"
  904. HRESULT PRV_FindRunningApp(LPCONNECTINFO lpci, LPPROCESS_INFORMATION lppi)
  905. {
  906. OSVERSIONINFOA ver;
  907. HRESULT hr = DPERR_UNAVAILABLE;
  908. DPF(7, "Entering PRV_FindRunningApp");
  909. DPF(9, "Parameters: 0x%08x, 0x%08x", lpci, lppi);
  910. ASSERT(lpci);
  911. ASSERT(lppi);
  912. // Clear our structure since it's on the stack
  913. memset(&ver, 0, sizeof(OSVERSIONINFOA));
  914. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  915. // Figure out which platform we are running on and
  916. // call the appropriate process enumerating function
  917. if(!GetVersionExA(&ver))
  918. {
  919. DPF_ERR("Unable to determinte platform -- not looking for running app");
  920. return DPERR_UNAVAILABLE;
  921. }
  922. switch(ver.dwPlatformId)
  923. {
  924. case VER_PLATFORM_WIN32_NT:
  925. case VER_PLATFORM_WIN32_WINDOWS:
  926. // Call the Win9x version of FindRunningApp
  927. hr = PRV_FindRunningAppWin9x(lpci, lppi);
  928. break;
  929. #if 0
  930. case VER_PLATFORM_WIN32_NT:
  931. hr = PRV_FindRunningAppNT(lpci, lppi);
  932. break;
  933. #endif
  934. default:
  935. DPF_ERR("Unable to determinte platform -- not looking for running app");
  936. hr = DPERR_UNAVAILABLE;
  937. break;
  938. }
  939. return hr;
  940. } // PRV_FindRunningApp
  941. #undef DPF_MODNAME
  942. #define DPF_MODNAME "DPL_RunApplication"
  943. HRESULT DPLAPI DPL_RunApplication(LPDIRECTPLAYLOBBY lpDPL, DWORD dwFlags,
  944. LPDWORD lpdwGameID, LPDPLCONNECTION lpConn,
  945. HANDLE hReceiveEvent)
  946. {
  947. LPDPLOBBYI_DPLOBJECT this;
  948. HRESULT hr;
  949. PROCESS_INFORMATION pi;
  950. LPDPLOBBYI_GAMENODE lpgn = NULL;
  951. CONNECTINFO ci;
  952. HANDLE hDupReceiveEvent = NULL;
  953. HANDLE hReceiveThread = NULL;
  954. HANDLE hTerminateThread = NULL;
  955. HANDLE hKillReceiveThreadEvent = NULL;
  956. HANDLE hKillTermThreadEvent = NULL;
  957. DWORD dwThreadID;
  958. BOOL bCreatedProcess = FALSE;
  959. GUID *lpguidIPC = NULL;
  960. DPF(7, "Entering DPL_RunApplication");
  961. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
  962. lpDPL, dwFlags, lpdwGameID, lpConn, hReceiveEvent);
  963. ENTER_DPLOBBY();
  964. TRY
  965. {
  966. if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
  967. {
  968. LEAVE_DPLOBBY();
  969. return DPERR_INVALIDINTERFACE;
  970. }
  971. this = DPLOBJECT_FROM_INTERFACE(lpDPL);
  972. if( !VALID_DPLOBBY_PTR( this ) )
  973. {
  974. LEAVE_DPLOBBY();
  975. return DPERR_INVALIDOBJECT;
  976. }
  977. // Validate the DPLCONNECTION structure and it's members
  978. hr = PRV_ValidateDPLCONNECTION(lpConn, FALSE);
  979. if(FAILED(hr))
  980. {
  981. LEAVE_DPLOBBY();
  982. return hr;
  983. }
  984. if( !VALID_DWORD_PTR( lpdwGameID ) )
  985. {
  986. LEAVE_DPLOBBY();
  987. return DPERR_INVALIDPARAMS;
  988. }
  989. // We haven't defined any flags for this release
  990. if( (dwFlags) )
  991. {
  992. LEAVE_DPLOBBY();
  993. return DPERR_INVALIDFLAGS;
  994. }
  995. // Validate the handle
  996. if(hReceiveEvent)
  997. {
  998. if(!OS_IsValidHandle(hReceiveEvent))
  999. {
  1000. LEAVE_DPLOBBY();
  1001. DPF_ERR("Invalid hReceiveEvent handle");
  1002. return DPERR_INVALIDPARAMS;
  1003. }
  1004. }
  1005. }
  1006. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1007. {
  1008. LEAVE_DPLOBBY();
  1009. DPF_ERR( "Exception encountered validating parameters" );
  1010. return DPERR_INVALIDPARAMS;
  1011. }
  1012. // Clear the CONNECTINFO structure since it's on the stack
  1013. memset(&ci, 0, sizeof(CONNECTINFO));
  1014. // Get the guid of the game we want to launch
  1015. if(lpConn && lpConn->lpSessionDesc)
  1016. ci.guidApplication = lpConn->lpSessionDesc->guidApplication;
  1017. else
  1018. {
  1019. LEAVE_DPLOBBY();
  1020. return DPERR_UNKNOWNAPPLICATION;
  1021. }
  1022. // Get the information out the registry based on the GUID
  1023. if(!PRV_GetConnectInfoFromRegistry(&ci))
  1024. {
  1025. LEAVE_DPLOBBY();
  1026. return DPERR_UNKNOWNAPPLICATION;
  1027. }
  1028. // Clear the PROCESS_INFORMATION structure since it's on the stack
  1029. memset(&pi, 0, sizeof(PROCESS_INFORMATION));
  1030. // Look to see if this game is already running AND is in wait mode
  1031. // waiting for new connection settings. If it is, we want to
  1032. // send the connection settings to it.
  1033. hr = PRV_FindRunningApp(&ci, &pi);
  1034. if(FAILED(hr))
  1035. {
  1036. // It isn't waiting, so create the game's process & suspend it
  1037. hr = PRV_CreateGameProcess(&ci, &pi);
  1038. if(FAILED(hr))
  1039. {
  1040. LEAVE_DPLOBBY();
  1041. return hr;
  1042. }
  1043. if(!(IsEqualGUID(&ci.guidIPC,&GUID_NULL))){
  1044. lpguidIPC=&ci.guidIPC;
  1045. }
  1046. // Set our created flag
  1047. bCreatedProcess = TRUE;
  1048. }
  1049. // Create a game node
  1050. hr = PRV_AddNewGameNode(this, &lpgn, pi.dwProcessId,
  1051. pi.hProcess, TRUE, lpguidIPC);
  1052. if(FAILED(hr))
  1053. {
  1054. DPF_ERR("Couldn't create new game node");
  1055. goto RUN_APP_ERROR_EXIT;
  1056. }
  1057. // If the ConnectionSettings are from a StartSession message (lobby launched),
  1058. // we need to set the flag
  1059. if(lpConn->lpSessionDesc->dwReserved1)
  1060. {
  1061. // Set the flag that says we were lobby client launched
  1062. lpgn->dwFlags |= GN_CLIENT_LAUNCHED;
  1063. }
  1064. // Write the connection settings in the shared memory buffer
  1065. hr = PRV_WriteConnectionSettings(lpgn, lpConn, TRUE);
  1066. if(FAILED(hr))
  1067. {
  1068. DPF_ERR("Unable to write the connection settings!");
  1069. goto RUN_APP_ERROR_EXIT;
  1070. }
  1071. // Send the app a message that the new connection settings are available
  1072. // but only if we've sent the settings to a running app
  1073. if(!bCreatedProcess)
  1074. PRV_SendStandardSystemMessage(lpDPL, DPLSYS_NEWCONNECTIONSETTINGS, pi.dwProcessId);
  1075. // Duplicate the Receive Event handle to use a signal to the
  1076. // lobby client that the game has sent game settings to it.
  1077. if(hReceiveEvent)
  1078. {
  1079. hDupReceiveEvent = PRV_DuplicateHandle(hReceiveEvent);
  1080. if(!hDupReceiveEvent)
  1081. {
  1082. DPF_ERR("Unable to duplicate ReceiveEvent handle");
  1083. hr = DPERR_OUTOFMEMORY;
  1084. goto RUN_APP_ERROR_EXIT;
  1085. }
  1086. }
  1087. lpgn->hDupReceiveEvent = hDupReceiveEvent;
  1088. // Create the kill thread event for the monitor thread
  1089. hKillTermThreadEvent = OS_CreateEvent(NULL, FALSE, FALSE, NULL);
  1090. if(!hKillTermThreadEvent)
  1091. {
  1092. DPF_ERR("Unable to create kill thread event");
  1093. hr = DPERR_OUTOFMEMORY;
  1094. goto RUN_APP_ERROR_EXIT;
  1095. }
  1096. lpgn->hKillTermThreadEvent = hKillTermThreadEvent;
  1097. // Spawn off a terminate monitor thread
  1098. hTerminateThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
  1099. PRV_ClientTerminateNotification, lpgn, 0, &dwThreadID);
  1100. if(!hTerminateThread)
  1101. {
  1102. DPF_ERR("Unable to create Terminate Monitor Thread!");
  1103. hr = DPERR_OUTOFMEMORY;
  1104. goto RUN_APP_ERROR_EXIT;
  1105. }
  1106. lpgn->hTerminateThread = hTerminateThread;
  1107. // Resume the game's process & let it run, then
  1108. // free the thread handle since we won't use it anymore
  1109. if(bCreatedProcess)
  1110. {
  1111. ResumeThread(pi.hThread);
  1112. CloseHandle(pi.hThread);
  1113. }
  1114. // Set the output pointer
  1115. *lpdwGameID = pi.dwProcessId;
  1116. // Free the strings in the connect info struct
  1117. PRV_FreeConnectInfo(&ci);
  1118. LEAVE_DPLOBBY();
  1119. return DP_OK;
  1120. RUN_APP_ERROR_EXIT:
  1121. if(pi.hThread && bCreatedProcess)
  1122. CloseHandle(pi.hThread);
  1123. if(bCreatedProcess && pi.hProcess)
  1124. TerminateProcess(pi.hProcess, 0L);
  1125. if(lpgn)
  1126. PRV_RemoveGameNodeFromList(lpgn);
  1127. PRV_FreeConnectInfo(&ci);
  1128. LEAVE_DPLOBBY();
  1129. return hr;
  1130. } // DPL_RunApplication