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.

1218 lines
34 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: DPLCommon.cpp
  6. * Content: DirectPlay Lobby Common Functions
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 02/21/00 mjn Created
  12. * 04/13/00 rmt First pass param validation
  13. * 04/26/00 mjn Removed dwTimeOut from Send() API call
  14. * 05/01/00 rmt Bug #33108 -- Initialize returns DPNERR_NORESPONSE when not lobbied
  15. * 05/03/00 rmt Updated initialize so if lobby launched automatically establishes a
  16. * connection and makes self unavailable. (Also waits for connection).
  17. * 05/16/00 rmt Bug #34734 -- Init Client, Init App, Close App hangs --
  18. * both client and app were using 'C' prefix, should have been 'C' for
  19. * client and 'A' for app.
  20. * 06/14/00 rmt Fixed build break with new compiler (added ')''s).
  21. * 06/15/00 rmt Bug #33617 - Must provide method for providing automatic launch of DirectPlay instances
  22. * 06/28/00 rmt Prefix Bug #38082
  23. * 07/06/00 rmt Bug #38717 ASSERTION when sending data
  24. * 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched
  25. * rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns
  26. * rmt Bug #38755 - No way to specify player name in Connection Settings
  27. * rmt Bug #38758 - DPLOBBY8.H has incorrect comments
  28. * rmt Bug #38783 - pvUserApplicationContext is only partially implemented
  29. * rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs).
  30. * 07/13/2000 rmt Fixed memory leak
  31. * 07/14/2000 rmt Bug #39257 - LobbyClient::ReleaseApp returns E_OUTOFMEMORY when called when no one connected
  32. * 07/21/2000 rmt Removed assert which wasn't needed
  33. * 08/03/2000 rmt Removed assert which wasn't needed
  34. * 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  35. * 08/18/2000 rmt Bug #42751 - DPLOBBY8: Prohibit more than one lobby client or lobby app per process
  36. * 08/24/2000 rmt Bug #43317 - DP8LOBBY: Occasionally when closing Lobby App right after releasing handles, causes assertion.
  37. * 02/06/2001 rodtoll WINBUG #293871: DPLOBBY8: [IA64] Lobby launching a 64-bit
  38. * app from 64-bit lobby launcher crashes with unaligned memory error.
  39. *
  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. BOOL g_fAppStarted = FALSE;
  57. BOOL g_fClientStarted = FALSE;
  58. DNCRITICAL_SECTION g_csSingleTon;
  59. //**********************************************************************
  60. // Function prototypes
  61. //**********************************************************************
  62. //**********************************************************************
  63. // Function definitions
  64. //**********************************************************************
  65. // DPL_GetConnectionSettings
  66. //
  67. // Retrieves the pdplSessionInfo (if any) associated with the specified connection. This method
  68. // is shared between the client and app interfaces.
  69. //
  70. #undef DPF_MODNAME
  71. #define DPF_MODNAME "DPL_GetConnectionSettings"
  72. STDMETHODIMP DPL_GetConnectionSettings(LPVOID lpv,const DPNHANDLE hLobbyClient, DPL_CONNECTION_SETTINGS * const pdplSessionInfo, DWORD *pdwInfoSize, const DWORD dwFlags )
  73. {
  74. HRESULT hResultCode;
  75. DPL_CONNECTION *pdplConnection;
  76. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  77. DPFX(DPFPREP, 3,"Parameters: hTarget [0x%lx], pdplSessionInfo [0x%p], pdwInfoSize [%p], dwFlags [0x%lx]",
  78. hLobbyClient,pdplSessionInfo,pdwInfoSize,dwFlags);
  79. TRY
  80. {
  81. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(lpv));
  82. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  83. {
  84. if( FAILED( hResultCode = DPL_ValidateGetConnectionSettings( lpv, hLobbyClient, pdplSessionInfo, pdwInfoSize, dwFlags ) ) )
  85. {
  86. DPFX(DPFPREP, 0, "Error validating getconnectsettings params hr=[0x%lx]", hResultCode );
  87. DPF_RETURN( hResultCode );
  88. }
  89. }
  90. // Ensure we've been initialized
  91. if (pdpLobbyObject->pReceiveQueue == NULL)
  92. {
  93. DPFERR("Not initialized");
  94. DPF_RETURN(DPNERR_UNINITIALIZED);
  95. }
  96. }
  97. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  98. {
  99. DPFERR("Invalid object" );
  100. DPF_RETURN(DPNERR_INVALIDOBJECT);
  101. }
  102. // Attempt to retrieve connection settings.
  103. hResultCode = DPLConnectionGetConnectSettings( pdpLobbyObject, hLobbyClient, pdplSessionInfo, pdwInfoSize );
  104. DPF_RETURN( hResultCode );
  105. }
  106. // DPL_SetConnectionSettings
  107. //
  108. // Sets the pdplSessionInfo structure associated with the specified connection. This method
  109. // is shared between the client and app interfaces.
  110. //
  111. // This function will generate a DPL_MSGID_CONNECTION_SETTINGS message to be sent to the specified
  112. // connection.
  113. //
  114. #undef DPF_MODNAME
  115. #define DPF_MODNAME "DPL_SetConnectionSettings"
  116. STDMETHODIMP DPL_SetConnectionSettings(LPVOID lpv,const DPNHANDLE hLobbyClient, const DPL_CONNECTION_SETTINGS * const pdplSessionInfo, const DWORD dwFlags )
  117. {
  118. HRESULT hResultCode;
  119. DPL_CONNECTION *pdplConnection;
  120. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  121. DPNHANDLE *hTargets = NULL;
  122. DWORD dwNumTargets = 0;
  123. DWORD dwTargetIndex = 0;
  124. CConnectionSettings *pConnectionSettings = NULL;
  125. DPFX(DPFPREP, 3,"Parameters: hLobbyClient [0x%lx], pBuffer [0x%p], dwFlags [0x%lx]",
  126. hLobbyClient,pdplSessionInfo,dwFlags);
  127. TRY
  128. {
  129. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(lpv));
  130. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  131. {
  132. if( FAILED( hResultCode = DPL_ValidateSetConnectionSettings( lpv, hLobbyClient, pdplSessionInfo, dwFlags ) ) )
  133. {
  134. DPFX(DPFPREP, 0, "Error validating setconnectsettings params hr=[0x%lx]", hResultCode );
  135. DPF_RETURN( hResultCode );
  136. }
  137. }
  138. // Ensure we've been initialized
  139. if (pdpLobbyObject->pReceiveQueue == NULL)
  140. {
  141. DPFERR("Not initialized");
  142. DPF_RETURN(DPNERR_UNINITIALIZED);
  143. }
  144. }
  145. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  146. {
  147. DPFERR("Invalid object" );
  148. DPF_RETURN(DPNERR_INVALIDOBJECT);
  149. }
  150. if( hLobbyClient == DPLHANDLE_ALLCONNECTIONS )
  151. {
  152. dwNumTargets = 0;
  153. // We need loop so if someone adds a connection during our run
  154. // it gets added to our list
  155. //
  156. while( 1 )
  157. {
  158. hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
  159. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  160. {
  161. if( hTargets )
  162. {
  163. delete [] hTargets;
  164. }
  165. hTargets = new DPNHANDLE[dwNumTargets];
  166. if( hTargets == NULL )
  167. {
  168. DPFERR("Error allocating memory" );
  169. dwNumTargets = 0;
  170. hResultCode = DPNERR_OUTOFMEMORY;
  171. goto SETCONNECT_EXIT;
  172. }
  173. continue;
  174. }
  175. else if( FAILED( hResultCode ) )
  176. {
  177. DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode );
  178. break;
  179. }
  180. else
  181. {
  182. break;
  183. }
  184. }
  185. // Failed getting connection information
  186. if( FAILED( hResultCode ) )
  187. {
  188. if( hTargets )
  189. {
  190. delete [] hTargets;
  191. hTargets = NULL;
  192. }
  193. dwNumTargets = 0;
  194. goto SETCONNECT_EXIT;
  195. }
  196. }
  197. else
  198. {
  199. hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
  200. if( hTargets == NULL )
  201. {
  202. DPFERR("Error allocating memory" );
  203. dwNumTargets = 0;
  204. hResultCode = DPNERR_OUTOFMEMORY;
  205. goto SETCONNECT_EXIT;
  206. }
  207. dwNumTargets = 1;
  208. hTargets[0] = hLobbyClient;
  209. }
  210. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  211. {
  212. if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hTargets[dwTargetIndex],&pdplConnection,TRUE)) != DPN_OK)
  213. {
  214. DPFERR("Invalid send target");
  215. DisplayDNError(0,hResultCode);
  216. continue;
  217. }
  218. if( pdplSessionInfo )
  219. {
  220. pConnectionSettings = new CConnectionSettings();
  221. if( !pConnectionSettings )
  222. {
  223. DPFERR("Error allocating memory" );
  224. hResultCode = DPNERR_OUTOFMEMORY;
  225. goto SETCONNECT_EXIT;
  226. }
  227. hResultCode = pConnectionSettings->InitializeAndCopy( pdplSessionInfo );
  228. if( FAILED( hResultCode ) )
  229. {
  230. DPFX( DPFPREP, 0, "Error setting up connection settings hr [0x%x]", hResultCode );
  231. goto SETCONNECT_EXIT;
  232. }
  233. }
  234. // Attempt to set connection settings.
  235. hResultCode = DPLConnectionSetConnectSettings( pdpLobbyObject, hTargets[dwTargetIndex], pConnectionSettings );
  236. if( FAILED( hResultCode ) )
  237. {
  238. DPFX(DPFPREP, 0, "Error setting connct settings for 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  239. delete pConnectionSettings;
  240. }
  241. hResultCode = DPLSendConnectionSettings( pdpLobbyObject, hTargets[dwTargetIndex] );
  242. if( FAILED( hResultCode ) )
  243. {
  244. DPFX(DPFPREP, 0, "Error sending connection settings to client 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  245. }
  246. pConnectionSettings = NULL;
  247. }
  248. SETCONNECT_EXIT:
  249. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  250. {
  251. if( hTargets[dwTargetIndex] )
  252. DPLConnectionRelease(pdpLobbyObject,hTargets[dwTargetIndex]);
  253. }
  254. if( hTargets )
  255. delete [] hTargets;
  256. DPF_RETURN(hResultCode);
  257. }
  258. #undef DPF_MODNAME
  259. #define DPF_MODNAME "DPL_RegisterMessageHandlerClient"
  260. STDMETHODIMP DPL_RegisterMessageHandlerClient(PVOID pv,
  261. const PVOID pvUserContext,
  262. const PFNDPNMESSAGEHANDLER pfn,
  263. const DWORD dwFlags)
  264. {
  265. return DPL_RegisterMessageHandler( pv, pvUserContext, pfn, NULL, dwFlags );
  266. }
  267. // HRESULT DPL_RegisterMessageHandler
  268. // PVOID pv Interface pointer
  269. // PVOID pvUserContext User context
  270. // PFNDPNMESSAGEHANDLER pfn User supplied message handler
  271. // DWORD dwFlags Not Used
  272. //
  273. // Returns
  274. // DPN_OK If the message handler was registered without incident
  275. // DPNERR_INVALIDPARAM If there was an invalid parameter
  276. // DPNERR_GENERIC If there were any problems
  277. //
  278. // Notes
  279. // This function registers a user supplied message handler function. This function should
  280. // only be called once, even in cases where a game is being re-connected (i.e. after ending)
  281. //
  282. // This will set up the required message queues, handshake the lobby client's PID (if supplied on the
  283. // command line) and spawn the application's receive message queue thread.
  284. #undef DPF_MODNAME
  285. #define DPF_MODNAME "DPL_RegisterMessageHandler"
  286. STDMETHODIMP DPL_RegisterMessageHandler(PVOID pv,
  287. const PVOID pvUserContext,
  288. const PFNDPNMESSAGEHANDLER pfn,
  289. DPNHANDLE * const pdpnhConnection,
  290. const DWORD dwFlags)
  291. {
  292. HRESULT hResultCode = DPN_OK;
  293. DWORD dwCurrentPid;
  294. DWORD dwThreadId;
  295. PDIRECTPLAYLOBBYOBJECT pdpLobbyObject;
  296. char cSuffix;
  297. DPFX(DPFPREP, 3,"Parameters: pv [0x%p], pfn [0x%p], dwFlags [%lx]",pv,pfn,dwFlags);
  298. TRY
  299. {
  300. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  301. if( FAILED( hResultCode = DPL_ValidateRegisterMessageHandler( pv, pvUserContext, pfn, pdpnhConnection, dwFlags ) ) )
  302. {
  303. DPFX(DPFPREP, 0, "Error validating register message handler params hr=[0x%lx]", hResultCode );
  304. DPF_RETURN( hResultCode );
  305. }
  306. // Ensure we've been initialized
  307. if (pdpLobbyObject->pReceiveQueue != NULL)
  308. {
  309. DPFERR("Already initialized");
  310. DPF_RETURN(DPNERR_ALREADYINITIALIZED);
  311. }
  312. DNEnterCriticalSection( &g_csSingleTon );
  313. if (pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBIEDAPPLICATION )
  314. {
  315. if( g_fAppStarted )
  316. {
  317. DPFERR( "You can only start one lobbied application per process!" );
  318. DNLeaveCriticalSection( &g_csSingleTon );
  319. DPF_RETURN( DPNERR_NOTALLOWED );
  320. }
  321. g_fAppStarted = TRUE;
  322. }
  323. else if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBYCLIENT )
  324. {
  325. if( g_fClientStarted )
  326. {
  327. DPFERR( "You can only start one lobby client per process!" );
  328. DNLeaveCriticalSection( &g_csSingleTon );
  329. DPF_RETURN( DPNERR_NOTALLOWED );
  330. }
  331. g_fClientStarted = TRUE;
  332. }
  333. DNLeaveCriticalSection( &g_csSingleTon );
  334. }
  335. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  336. {
  337. DPFERR("Invalid object" );
  338. DPF_RETURN(DPNERR_INVALIDOBJECT);
  339. }
  340. // Disable parameter validation flag if DPNINITIALIZE_DISABLEPARAMVAL
  341. // is specified
  342. if( dwFlags & DPLINITIALIZE_DISABLEPARAMVAL )
  343. {
  344. pdpLobbyObject->dwFlags &= ~(DPL_OBJECT_FLAG_PARAMVALIDATION);
  345. }
  346. pdpLobbyObject->pfnMessageHandler = pfn;
  347. pdpLobbyObject->pvUserContext = pvUserContext;
  348. pdpLobbyObject->pReceiveQueue = new CMessageQueue;
  349. if( pdpLobbyObject->pReceiveQueue == NULL )
  350. {
  351. DPFX(DPFPREP, 0, "Error allocating receive queue" );
  352. hResultCode = DPNERR_OUTOFMEMORY;
  353. goto ERROR_DPL_RegisterMessageHandler;
  354. }
  355. pdpLobbyObject->pReceiveQueue->SetMessageHandler(static_cast<PVOID>(pdpLobbyObject),DPLMessageHandler);
  356. if (pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBIEDAPPLICATION)
  357. {
  358. cSuffix = DPL_MSGQ_OBJECT_SUFFIX_APPLICATION;
  359. }
  360. else
  361. {
  362. cSuffix = DPL_MSGQ_OBJECT_SUFFIX_CLIENT;
  363. }
  364. // Open application receive message queue
  365. dwCurrentPid = GetCurrentProcessId();
  366. if ((hResultCode = pdpLobbyObject->pReceiveQueue->Open(dwCurrentPid,
  367. cSuffix,DPL_MSGQ_SIZE,DPL_MSGQ_TIMEOUT_IDLE,0)) != DPN_OK)
  368. {
  369. DPFERR("Could not open App Rec Q");
  370. goto ERROR_DPL_RegisterMessageHandler;
  371. }
  372. if ((pdpLobbyObject->hReceiveThread =
  373. CreateThread(NULL,(DWORD)NULL,(LPTHREAD_START_ROUTINE)DPLProcessMessageQueue,
  374. static_cast<void*>(pdpLobbyObject->pReceiveQueue),(DWORD)NULL,&dwThreadId)) == NULL)
  375. {
  376. DPFERR("CreateThread() failed");
  377. hResultCode = DPNERR_GENERIC;
  378. pdpLobbyObject->pReceiveQueue->Close();
  379. goto ERROR_DPL_RegisterMessageHandler;
  380. }
  381. pdpLobbyObject->pReceiveQueue->WaitForReceiveThread(INFINITE);
  382. if (pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBIEDAPPLICATION)
  383. {
  384. DPFX(DPFPREP, 5,"Attempt lobby connection");
  385. hResultCode = DPLAttemptLobbyConnection(pdpLobbyObject);
  386. if ( hResultCode == DPN_OK)
  387. {
  388. if( pdpnhConnection )
  389. *pdpnhConnection = pdpLobbyObject->dpnhLaunchedConnection;
  390. DPFX(DPFPREP, 5,"Application was lobby launched");
  391. DPFX(DPFPREP, 5,"Waiting for true connect notification" );
  392. DWORD dwReturnValue = WaitForSingleObject( pdpLobbyObject->hConnectEvent, DPL_LOBBYLAUNCHED_CONNECT_TIMEOUT );
  393. DNASSERT( dwReturnValue == WAIT_OBJECT_0 );
  394. }
  395. else if( hResultCode != DPNERR_TIMEDOUT )
  396. {
  397. DPFX(DPFPREP, 5,"Application was not lobby launched");
  398. if( pdpnhConnection )
  399. *pdpnhConnection = NULL;
  400. // Need to reset return code to OK.. this is not an error
  401. hResultCode = DPN_OK;
  402. }
  403. else
  404. {
  405. DPFERR( "App was lobby launched but timed out establishing a connection" );
  406. if( pdpnhConnection )
  407. *pdpnhConnection = NULL;
  408. }
  409. }
  410. EXIT_DPL_RegisterMessageHandler:
  411. DPF_RETURN(hResultCode);
  412. ERROR_DPL_RegisterMessageHandler:
  413. DNEnterCriticalSection( &g_csSingleTon );
  414. if (pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBIEDAPPLICATION )
  415. {
  416. g_fAppStarted = FALSE;
  417. }
  418. else if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBYCLIENT )
  419. {
  420. g_fClientStarted = FALSE;
  421. }
  422. DNLeaveCriticalSection( &g_csSingleTon );
  423. goto EXIT_DPL_RegisterMessageHandler;
  424. }
  425. #undef DPF_MODNAME
  426. #define DPF_MODNAME "DPL_Close"
  427. HRESULT DPL_Close(PVOID pv, const DWORD dwFlags )
  428. {
  429. HRESULT hResultCode;
  430. DWORD dwNumHandles;
  431. DPNHANDLE *prgHandles;
  432. DWORD dw;
  433. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  434. DPL_CONNECTION *pConnection;
  435. DPFX(DPFPREP, 3,"Parameters: (none)");
  436. TRY
  437. {
  438. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  439. if( FAILED( hResultCode = DPL_ValidateClose( pv, dwFlags ) ) )
  440. {
  441. DPFX(DPFPREP, 0, "Error validating close params hr=[0x%lx]", hResultCode );
  442. return hResultCode;
  443. }
  444. // Ensure we've been initialized
  445. if (pdpLobbyObject->pReceiveQueue == NULL)
  446. {
  447. DPFERR("Already closed");
  448. return DPNERR_UNINITIALIZED;
  449. }
  450. }
  451. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  452. {
  453. DPFERR("Invalid object" );
  454. return DPNERR_INVALIDOBJECT;
  455. }
  456. // Shutdown the queue first to ensure that we don't end up shutting down a connection
  457. // twice! (E.g. disconnect comes in as we are disconnecting it).
  458. if (pdpLobbyObject->pReceiveQueue)
  459. {
  460. if (pdpLobbyObject->pReceiveQueue->IsOpen())
  461. {
  462. // Ask receive thread to terminate
  463. DPFX(DPFPREP, 5,"Terminate Receive Msg Thread");
  464. pdpLobbyObject->pReceiveQueue->Terminate();
  465. // Wait for termination to occur
  466. if (WaitForSingleObject(pdpLobbyObject->hReceiveThread,INFINITE) != WAIT_OBJECT_0)
  467. {
  468. hResultCode = DPNERR_GENERIC;
  469. DPFERR("WaitForSingleObject failed");
  470. }
  471. pdpLobbyObject->pReceiveQueue->Close();
  472. if (pdpLobbyObject->pReceiveQueue)
  473. {
  474. delete pdpLobbyObject->pReceiveQueue;
  475. pdpLobbyObject->pReceiveQueue = NULL;
  476. }
  477. CloseHandle(pdpLobbyObject->hReceiveThread);
  478. pdpLobbyObject->hReceiveThread = NULL;
  479. CloseHandle(pdpLobbyObject->hConnectEvent);
  480. pdpLobbyObject->hConnectEvent = NULL;
  481. CloseHandle(pdpLobbyObject->hLobbyLaunchConnectEvent);
  482. pdpLobbyObject->hLobbyLaunchConnectEvent = NULL;
  483. }
  484. }
  485. // Enumerate handles outstanding
  486. dwNumHandles = 0;
  487. prgHandles = NULL;
  488. hResultCode = DPLConnectionEnum(pdpLobbyObject,prgHandles,&dwNumHandles);
  489. while (hResultCode == DPNERR_BUFFERTOOSMALL)
  490. {
  491. if (prgHandles)
  492. DNFree(prgHandles);
  493. if ((prgHandles = static_cast<DPNHANDLE*>(DNMalloc(dwNumHandles*sizeof(DPNHANDLE)))) != NULL)
  494. {
  495. hResultCode = DPLConnectionEnum(pdpLobbyObject,prgHandles,&dwNumHandles);
  496. }
  497. else
  498. {
  499. DPFERR("Could not allocate space for handle array");
  500. hResultCode = DPNERR_OUTOFMEMORY;
  501. break;
  502. }
  503. }
  504. // Send DISCONNECTs to all attached msg queues, for which there are handles
  505. if (hResultCode == DPN_OK)
  506. {
  507. for (dw = 0 ; dw < dwNumHandles ; dw++)
  508. {
  509. hResultCode = DPLConnectionFind(pdpLobbyObject,prgHandles[dw],&pConnection,TRUE );
  510. if( SUCCEEDED( hResultCode ) )
  511. {
  512. hResultCode = DPLConnectionDisconnect(pdpLobbyObject,prgHandles[dw]);
  513. if( FAILED( hResultCode ) )
  514. {
  515. DPFX(DPFPREP, 0, "Error disconnecting connection 0x%x", hResultCode );
  516. }
  517. DPLConnectionRelease( pdpLobbyObject,prgHandles[dw]);
  518. }
  519. }
  520. // Errors above are irrelevant, it's quite possible after building the list of outstanding
  521. // connections that before we attempt to close the list one has gone away.
  522. //
  523. hResultCode = DPN_OK;
  524. }
  525. if (prgHandles)
  526. {
  527. DNFree(prgHandles);
  528. prgHandles = NULL;
  529. }
  530. DNEnterCriticalSection( &g_csSingleTon );
  531. if (pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBIEDAPPLICATION )
  532. {
  533. g_fAppStarted = FALSE;
  534. }
  535. else if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOBBYCLIENT )
  536. {
  537. g_fClientStarted = FALSE;
  538. }
  539. DNLeaveCriticalSection( &g_csSingleTon );
  540. DPF_RETURN( hResultCode );
  541. }
  542. #undef DPF_MODNAME
  543. #define DPF_MODNAME "DPL_Send"
  544. STDMETHODIMP DPL_Send(PVOID pv,
  545. const DPNHANDLE hTarget,
  546. BYTE *const pBuffer,
  547. const DWORD dwBufferSize,
  548. const DWORD dwFlags)
  549. {
  550. HRESULT hResultCode;
  551. DPL_CONNECTION *pdplConnection;
  552. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  553. DPNHANDLE *hTargets = NULL;
  554. DWORD dwNumTargets = 0;
  555. DWORD dwTargetIndex = 0;
  556. DPFX(DPFPREP, 3,"Parameters: hTarget [0x%lx], pBuffer [0x%p], dwBufferSize [%ld], dwFlags [0x%lx]",
  557. hTarget,pBuffer,dwBufferSize,dwFlags);
  558. TRY
  559. {
  560. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  561. if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_PARAMVALIDATION )
  562. {
  563. if( FAILED( hResultCode = DPL_ValidateSend( pv, hTarget, pBuffer, dwBufferSize, dwFlags ) ) )
  564. {
  565. DPFX(DPFPREP, 0, "Error validating send params hr=[0x%lx]", hResultCode );
  566. DPF_RETURN( hResultCode );
  567. }
  568. }
  569. // Ensure we've been initialized
  570. if (pdpLobbyObject->pReceiveQueue == NULL)
  571. {
  572. DPFERR("Not initialized");
  573. DPF_RETURN(DPNERR_UNINITIALIZED);
  574. }
  575. }
  576. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  577. {
  578. DPFERR("Invalid object" );
  579. DPF_RETURN(DPNERR_INVALIDOBJECT);
  580. }
  581. if( hTarget == DPLHANDLE_ALLCONNECTIONS )
  582. {
  583. dwNumTargets = 0;
  584. // We need loop so if someone adds a connection during our run
  585. // it gets added to our list
  586. //
  587. while( 1 )
  588. {
  589. hResultCode = DPLConnectionEnum( pdpLobbyObject, hTargets, &dwNumTargets );
  590. if( hResultCode == DPNERR_BUFFERTOOSMALL )
  591. {
  592. if( hTargets )
  593. {
  594. delete [] hTargets;
  595. }
  596. hTargets = new DPNHANDLE[dwNumTargets];
  597. if( hTargets == NULL )
  598. {
  599. DPFERR("Error allocating memory" );
  600. dwNumTargets = 0;
  601. hResultCode = DPNERR_OUTOFMEMORY;
  602. goto EXIT_AND_CLEANUP;
  603. }
  604. memset( hTargets, 0x00, sizeof(DPNHANDLE)*dwNumTargets);
  605. continue;
  606. }
  607. else if( FAILED( hResultCode ) )
  608. {
  609. DPFX(DPFPREP, 0, "Error getting list of connections hr=0x%x", hResultCode );
  610. break;
  611. }
  612. else
  613. {
  614. break;
  615. }
  616. }
  617. // Failed getting connection information
  618. if( FAILED( hResultCode ) )
  619. {
  620. if( hTargets )
  621. {
  622. delete [] hTargets;
  623. hTargets = NULL;
  624. }
  625. dwNumTargets = 0;
  626. goto EXIT_AND_CLEANUP;
  627. }
  628. }
  629. else
  630. {
  631. hTargets = new DPNHANDLE[1]; // We use array delete below so we need array new
  632. if( hTargets == NULL )
  633. {
  634. DPFERR("Error allocating memory" );
  635. dwNumTargets = 0;
  636. hResultCode = DPNERR_OUTOFMEMORY;
  637. goto EXIT_AND_CLEANUP;
  638. }
  639. dwNumTargets = 1;
  640. hTargets[0] = hTarget;
  641. }
  642. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  643. {
  644. if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hTargets[dwTargetIndex],&pdplConnection,TRUE)) != DPN_OK)
  645. {
  646. DPFERR("Invalid send target");
  647. DisplayDNError(0,hResultCode);
  648. hResultCode = DPNERR_INVALIDHANDLE;
  649. goto EXIT_AND_CLEANUP;
  650. }
  651. DNASSERT(pdplConnection->pSendQueue != NULL);
  652. if (!pdplConnection->pSendQueue->IsReceiving())
  653. {
  654. DPFERR("Other side is not listening");
  655. DPLConnectionRelease(pdpLobbyObject,hTarget);
  656. hResultCode = DPNERR_INVALIDHANDLE;
  657. goto EXIT_AND_CLEANUP;
  658. }
  659. hResultCode = pdplConnection->pSendQueue->Send(pBuffer,dwBufferSize,INFINITE,DPL_MSGQ_MSGFLAGS_USER2,0);
  660. if( FAILED( hResultCode ) )
  661. {
  662. DPFX(DPFPREP, 0, "Error sending to connection 0x%x hr=0x%x", hTargets[dwTargetIndex], hResultCode );
  663. }
  664. }
  665. EXIT_AND_CLEANUP:
  666. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  667. {
  668. if( hTargets[dwTargetIndex] )
  669. DPLConnectionRelease(pdpLobbyObject,hTargets[dwTargetIndex]);
  670. }
  671. if( hTargets )
  672. delete [] hTargets;
  673. DPF_RETURN(hResultCode);
  674. }
  675. #undef DPF_MODNAME
  676. #define DPF_MODNAME "DPLReceiveIdleTimeout"
  677. HRESULT DPLReceiveIdleTimeout(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  678. const DPNHANDLE hSender)
  679. {
  680. HRESULT hResultCode = DPNERR_BUFFERTOOSMALL;
  681. DWORD dwHandleIndex;
  682. DPL_CONNECTION *pConnection;
  683. HANDLE hProcess;
  684. DPFX(DPFPREP, 6, "Enumerating processes, checking for exit" );
  685. while( 1 )
  686. {
  687. hResultCode = H_Enum( &pdpLobbyObject->hsHandles, &pdpLobbyObject->dwHandleBufferSize,
  688. pdpLobbyObject->phHandleBuffer );
  689. if( hResultCode == E_POINTER )
  690. {
  691. if( pdpLobbyObject->phHandleBuffer )
  692. delete [] pdpLobbyObject->phHandleBuffer;
  693. pdpLobbyObject->phHandleBuffer = new DPNHANDLE[pdpLobbyObject->dwHandleBufferSize];
  694. if( pdpLobbyObject->phHandleBuffer == NULL )
  695. {
  696. DPFERR( "Out of memory" );
  697. return DPNERR_OUTOFMEMORY;
  698. }
  699. hResultCode = H_Enum( &pdpLobbyObject->hsHandles, &pdpLobbyObject->dwHandleBufferSize,
  700. pdpLobbyObject->phHandleBuffer );
  701. }
  702. else if( FAILED( hResultCode ) )
  703. {
  704. DPFERR( "Error getting handle list" );
  705. return hResultCode;
  706. }
  707. else
  708. {
  709. break;
  710. }
  711. }
  712. for( dwHandleIndex = 0; dwHandleIndex < pdpLobbyObject->dwHandleBufferSize; dwHandleIndex++ )
  713. {
  714. hResultCode = DPLConnectionFind( pdpLobbyObject, pdpLobbyObject->phHandleBuffer[dwHandleIndex],
  715. &pConnection, TRUE );
  716. if( hResultCode == DPN_OK )
  717. {
  718. hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pConnection->dwTargetPID );
  719. // We can close this handle.. after we're only just checking for existance.
  720. if( hProcess )
  721. CloseHandle( hProcess );
  722. // Process has exited..
  723. if( hProcess == NULL )
  724. {
  725. DPFX(DPFPREP, 6, "Process %d has exited", pConnection->dwTargetPID );
  726. DPLConnectionReceiveDisconnect( pdpLobbyObject, pdpLobbyObject->phHandleBuffer[dwHandleIndex], NULL, DPNERR_CONNECTIONLOST );
  727. }
  728. DPLConnectionRelease( pdpLobbyObject, pdpLobbyObject->phHandleBuffer[dwHandleIndex] );
  729. }
  730. }
  731. return DPN_OK;
  732. }
  733. #undef DPF_MODNAME
  734. #define DPF_MODNAME "DPLReceiveUserMessage"
  735. HRESULT DPLReceiveUserMessage(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  736. const DPNHANDLE hSender,
  737. BYTE *const pBuffer,
  738. const DWORD dwBufferSize)
  739. {
  740. HRESULT hResultCode;
  741. DPL_MESSAGE_RECEIVE Msg;
  742. Msg.dwSize = sizeof(DPL_MESSAGE_RECEIVE);
  743. Msg.pBuffer = pBuffer;
  744. Msg.dwBufferSize = dwBufferSize;
  745. Msg.hSender = hSender;
  746. hResultCode = DPLConnectionGetContext( pdpLobbyObject, hSender, &Msg.pvConnectionContext );
  747. // Failed to get the connection's context -- strange, but we're going to indicate anyhow.
  748. //
  749. if( FAILED( hResultCode ) )
  750. {
  751. DPFX(DPFPREP, 0, "Failed getting connection context hResultCode = 0x%x", hResultCode );
  752. }
  753. hResultCode = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
  754. DPL_MSGID_RECEIVE,
  755. reinterpret_cast<BYTE*>(&Msg));
  756. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  757. return(hResultCode);
  758. }
  759. #undef DPF_MODNAME
  760. #define DPF_MODNAME "DPLMessageHandler"
  761. HRESULT DPLMessageHandler(PVOID pvContext,
  762. const DPNHANDLE hSender,
  763. DWORD dwMessageFlags,
  764. BYTE *const pBuffer,
  765. const DWORD dwBufferSize)
  766. {
  767. DIRECTPLAYLOBBYOBJECT *pdpLobbyObject;
  768. HRESULT hResultCode;
  769. DWORD *pdwMsgId;
  770. // 7/17/2000(RichGr) - IA64: Use %p format specifier for 32/64-bit pointers and handles.
  771. DPFX(DPFPREP, 3,"Parameters: hSender [0x%x], pBuffer [0x%p], dwBufferSize [%ld]",
  772. hSender,pBuffer,dwBufferSize);
  773. DNASSERT(pBuffer != NULL);
  774. /*if (dwBufferSize < sizeof(DWORD))
  775. {
  776. DPFERR("Invalid message");
  777. return(DPNERR_GENERIC);
  778. }*/
  779. pdpLobbyObject = static_cast<DIRECTPLAYLOBBYOBJECT*>(pvContext);
  780. pdwMsgId = reinterpret_cast<DWORD*>(pBuffer);
  781. if( dwMessageFlags & DPL_MSGQ_MSGFLAGS_USER1 )
  782. {
  783. DPFX(DPFPREP, 5,"Received INTERNAL message");
  784. switch(*pdwMsgId)
  785. {
  786. case DPL_MSGID_INTERNAL_IDLE_TIMEOUT:
  787. {
  788. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_IDLE_TIMEOUT" );
  789. DPLReceiveIdleTimeout(pdpLobbyObject,hSender);
  790. break;
  791. }
  792. case DPL_MSGID_INTERNAL_DISCONNECT:
  793. {
  794. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_DISCONNECT");
  795. DPLConnectionReceiveDisconnect(pdpLobbyObject,hSender,pBuffer,DPN_OK);
  796. break;
  797. }
  798. case DPL_MSGID_INTERNAL_CONNECT_REQ:
  799. {
  800. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_CONNECT_REQ");
  801. DPLConnectionReceiveREQ(pdpLobbyObject,pBuffer);
  802. break;
  803. }
  804. case DPL_MSGID_INTERNAL_CONNECT_ACK:
  805. {
  806. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_CONNECT_ACK");
  807. DPLConnectionReceiveACK(pdpLobbyObject,hSender,pBuffer);
  808. break;
  809. }
  810. case DPL_MSGID_INTERNAL_UPDATE_STATUS:
  811. {
  812. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_UPDATE_STATUS");
  813. DPLUpdateAppStatus(pdpLobbyObject,hSender,pBuffer);
  814. break;
  815. }
  816. case DPL_MSGID_INTERNAL_CONNECTION_SETTINGS:
  817. {
  818. DPFX(DPFPREP, 5,"Received: DPL_MSGID_INTERNAL_CONNECTION_SETTINGS");
  819. DPLUpdateConnectionSettings(pdpLobbyObject,hSender,pBuffer);
  820. break;
  821. }
  822. default:
  823. {
  824. DPFX(DPFPREP, 5,"Received: Unknown message [0x%lx]",*pdwMsgId);
  825. DNASSERT(FALSE);
  826. break;
  827. }
  828. }
  829. }
  830. else if( dwMessageFlags & DPL_MSGQ_MSGFLAGS_USER2 )
  831. {
  832. DNASSERT( !(dwMessageFlags & DPL_MSGQ_MSGFLAGS_QUEUESYSTEM) );
  833. DPFX(DPFPREP, 5,"Received USER message");
  834. DPLReceiveUserMessage(pdpLobbyObject,hSender,pBuffer,dwBufferSize);
  835. }
  836. hResultCode = DPN_OK;
  837. DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
  838. return(hResultCode);
  839. }
  840. // DPLSendConnectionSettings
  841. //
  842. // This function is used to send a connection settings update message
  843. #undef DPF_MODNAME
  844. #define DPF_MODNAME "DPLSendConnectionSettings"
  845. HRESULT DPLSendConnectionSettings( DIRECTPLAYLOBBYOBJECT * const pdpLobbyObject,
  846. const DPNHANDLE hConnection )
  847. {
  848. BYTE *pbTransmitBuffer = NULL;
  849. DWORD dwTransmitBufferSize = 0;
  850. DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE *pdplMsgSettings = NULL;
  851. DPL_CONNECTION *pdplConnection = NULL;
  852. CPackedBuffer PackBuffer;
  853. HRESULT hResultCode = DPN_OK;
  854. hResultCode = DPLConnectionFind(pdpLobbyObject, hConnection, &pdplConnection, TRUE );
  855. if( FAILED( hResultCode ) )
  856. {
  857. DPFERR( "Unable to find specified connection" );
  858. return hResultCode;
  859. }
  860. // Grab lock to prevent other people from interfering
  861. DNEnterCriticalSection( &pdplConnection->csLock );
  862. PackBuffer.Initialize( NULL, 0 );
  863. PackBuffer.AddToFront( NULL, sizeof( DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE_HEADER ) );
  864. if( pdplConnection->pConnectionSettings )
  865. {
  866. pdplConnection->pConnectionSettings->BuildWireStruct( &PackBuffer );
  867. }
  868. dwTransmitBufferSize = PackBuffer.GetSizeRequired();
  869. pbTransmitBuffer = new BYTE[ dwTransmitBufferSize ];
  870. if( !pbTransmitBuffer )
  871. {
  872. DPFX( DPFPREP, 0, "Error allocating memory" );
  873. hResultCode = DPNERR_OUTOFMEMORY;
  874. goto DPLSENDCONNECTSETTINGS_DONE;
  875. }
  876. pdplMsgSettings = (DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE *) pbTransmitBuffer;
  877. PackBuffer.Initialize( pbTransmitBuffer, dwTransmitBufferSize );
  878. DNASSERT( pdplMsgSettings );
  879. hResultCode = PackBuffer.AddToFront( NULL, sizeof( DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE_HEADER ) );
  880. if( FAILED( hResultCode ) )
  881. {
  882. DPFX( DPFPREP, 0, "Error adding main struct hr [0x%x]", hResultCode );
  883. goto DPLSENDCONNECTSETTINGS_DONE;
  884. }
  885. if( pdplConnection->pConnectionSettings )
  886. {
  887. hResultCode = pdplConnection->pConnectionSettings->BuildWireStruct( &PackBuffer );
  888. if( FAILED( hResultCode ) )
  889. {
  890. DPFX( DPFPREP, 0, "Error adding connect struct hr [0x%x]", hResultCode );
  891. goto DPLSENDCONNECTSETTINGS_DONE;
  892. }
  893. pdplMsgSettings->dwConnectionSettingsSize = 1;
  894. }
  895. else
  896. {
  897. pdplMsgSettings->dwConnectionSettingsSize = 0;
  898. }
  899. pdplMsgSettings->dwMsgId = DPL_MSGID_INTERNAL_CONNECTION_SETTINGS;
  900. if (!pdplConnection->pSendQueue->IsReceiving())
  901. {
  902. DPFERR("Other side is not receiving");
  903. goto DPLSENDCONNECTSETTINGS_DONE;
  904. }
  905. hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(pdplMsgSettings),
  906. PackBuffer.GetSizeRequired(),
  907. INFINITE,
  908. DPL_MSGQ_MSGFLAGS_USER1,
  909. 0);
  910. if ( FAILED( hResultCode ) )
  911. {
  912. DPFX(DPFPREP, 0, "Could not send connect settings hr [0x%x]", hResultCode );
  913. goto DPLSENDCONNECTSETTINGS_DONE;
  914. }
  915. hResultCode = DPN_OK;
  916. DPLSENDCONNECTSETTINGS_DONE:
  917. if( pbTransmitBuffer )
  918. delete [] pbTransmitBuffer;
  919. DNLeaveCriticalSection( &pdplConnection->csLock );
  920. DPLConnectionRelease(pdpLobbyObject,hConnection);
  921. return hResultCode;
  922. }
  923. // DPLUpdateConnectionSettings
  924. //
  925. // This function is called when a connection settings update message has been received.
  926. //
  927. #undef DPF_MODNAME
  928. #define DPF_MODNAME "DPLUpdateConnectionSettings"
  929. HRESULT DPLUpdateConnectionSettings(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
  930. const DPNHANDLE hSender,
  931. BYTE *const pBuffer )
  932. {
  933. HRESULT hr;
  934. DPL_MESSAGE_CONNECTION_SETTINGS MsgConnectionSettings;
  935. DPL_CONNECTION_SETTINGS *pSettingsBuffer = NULL;
  936. DWORD dwSettingsBufferSize = 0;
  937. BOOL fAddressReferences = FALSE;
  938. CConnectionSettings *pConnectionSettings = NULL;
  939. DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE *pConnectionSettingsMsg = NULL;
  940. DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p]",pBuffer);
  941. DNASSERT(pdpLobbyObject != NULL);
  942. DNASSERT(pBuffer != NULL);
  943. pConnectionSettingsMsg = (DPL_INTERNAL_CONNECTION_SETTINGS_UPDATE *) pBuffer;
  944. if( pConnectionSettingsMsg->dwConnectionSettingsSize )
  945. {
  946. pConnectionSettings = new CConnectionSettings();
  947. if( !pConnectionSettings )
  948. {
  949. DPFX( DPFPREP, 0, "Error allocating connection settings" );
  950. hr = DPNERR_OUTOFMEMORY;
  951. goto UPDATESETTINGS_FAILURE;
  952. }
  953. hr = pConnectionSettings->Initialize( &pConnectionSettingsMsg->dplConnectionSettings, (UNALIGNED BYTE *) pConnectionSettingsMsg );
  954. if( FAILED( hr ) )
  955. {
  956. DPFX( DPFPREP, 0, "Error building structure from wire struct hr [0x%x]", hr );
  957. goto UPDATESETTINGS_FAILURE;
  958. }
  959. }
  960. // Set the connection settings on the object
  961. hr = DPLConnectionSetConnectSettings( pdpLobbyObject, hSender, pConnectionSettings );
  962. if( FAILED( hr ) )
  963. {
  964. DPFX(DPFPREP, 0, "Error setting connection settings hr = 0x%x", hr );
  965. goto UPDATESETTINGS_FAILURE;
  966. }
  967. // Setup message to indicate to user
  968. MsgConnectionSettings.dwSize = sizeof(DPL_MESSAGE_CONNECTION_SETTINGS);
  969. MsgConnectionSettings.hSender = hSender;
  970. if( pConnectionSettings )
  971. MsgConnectionSettings.pdplConnectionSettings = pConnectionSettings->GetConnectionSettings();
  972. else
  973. MsgConnectionSettings.pdplConnectionSettings = NULL;
  974. hr = DPLConnectionGetContext( pdpLobbyObject, hSender, &MsgConnectionSettings.pvConnectionContext );
  975. if( FAILED( hr ) )
  976. {
  977. DPFX(DPFPREP, 0, "Error getting connection's context value" );
  978. goto UPDATESETTINGS_FAILURE;
  979. }
  980. hr = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
  981. DPL_MSGID_CONNECTION_SETTINGS,
  982. reinterpret_cast<BYTE*>(&MsgConnectionSettings));
  983. if( FAILED( hr ) )
  984. {
  985. DPFX(DPFPREP, 1, "Error returned from user callback -- ignored hr [0x%x]", hr );
  986. }
  987. return DPN_OK;
  988. UPDATESETTINGS_FAILURE:
  989. if( pConnectionSettings )
  990. delete pConnectionSettings;
  991. return hr;
  992. }