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.

731 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. Connect.cpp
  5. Abstract:
  6. Handles all outgoing interfaces
  7. Author:
  8. mquinton - 5/7/97
  9. Notes:
  10. optional-notes
  11. Revision History:
  12. --*/
  13. #include "stdafx.h"
  14. #include "uuids.h"
  15. extern IGlobalInterfaceTable * gpGIT;
  16. extern CRITICAL_SECTION gcsGlobalInterfaceTable;
  17. extern ULONG_PTR GenerateHandleAndAddToHashTable( ULONG_PTR Element);
  18. extern void RemoveHandleFromHashTable(ULONG_PTR dwHandle);
  19. extern CHashTable * gpHandleHashTable;
  20. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  21. //
  22. // CTAPIConnectionPoint - implementation of IConnectionPoint
  23. // for TAPI object (ITTAPIEventNotification outgoing interface).
  24. //
  25. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  26. HRESULT
  27. CTAPIConnectionPoint::Initialize(
  28. IConnectionPointContainer * pCPC,
  29. IID iid
  30. )
  31. {
  32. LOG((TL_TRACE, "Initialize enter"));
  33. #if DBG
  34. {
  35. WCHAR guidName[100];
  36. StringFromGUID2(iid, (LPOLESTR)&guidName, 100);
  37. LOG((TL_INFO, "Initialize - IID : %S", guidName));
  38. }
  39. #endif
  40. //
  41. // Create the unadvise event
  42. //
  43. m_hUnadviseEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  44. if (m_hUnadviseEvent == NULL)
  45. {
  46. LOG((TL_TRACE, "Initialize - out of memory"));
  47. return E_OUTOFMEMORY;
  48. }
  49. //
  50. // Addref the connection point container
  51. //
  52. pCPC->AddRef();
  53. //
  54. // Addref ourselves
  55. //
  56. this->AddRef();
  57. //
  58. // Save stuff
  59. //
  60. m_pCPC = pCPC;
  61. m_iid = iid;
  62. m_pConnectData = NULL;
  63. EnterCriticalSection( &gcsGlobalInterfaceTable );
  64. m_cThreadsInGet = 0;
  65. m_fMarkedForDelete = FALSE;
  66. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  67. m_bInitialized = TRUE;
  68. LOG((TL_TRACE, "Initialize exit"));
  69. return S_OK;
  70. }
  71. // IConnectionPoint methods
  72. HRESULT
  73. STDMETHODCALLTYPE
  74. CTAPIConnectionPoint::GetConnectionInterface(
  75. IID * pIID
  76. )
  77. {
  78. if ( TAPIIsBadWritePtr( pIID, sizeof (IID) ) )
  79. {
  80. LOG((TL_ERROR, "GetConnectionInterface - bad pointer"));
  81. return E_POINTER;
  82. }
  83. Lock();
  84. *pIID = m_iid;
  85. Unlock();
  86. return S_OK;
  87. }
  88. HRESULT
  89. STDMETHODCALLTYPE
  90. CTAPIConnectionPoint::GetConnectionPointContainer(
  91. IConnectionPointContainer ** ppCPC
  92. )
  93. {
  94. if ( TAPIIsBadWritePtr( ppCPC, sizeof( IConnectionPointContainer *) ) )
  95. {
  96. LOG((TL_ERROR, "GetCPC - bad pointer"));
  97. return E_POINTER;
  98. }
  99. Lock();
  100. *ppCPC = m_pCPC;
  101. (*ppCPC)->AddRef();
  102. Unlock();
  103. return S_OK;
  104. }
  105. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  106. // Advise
  107. //
  108. // the application calls this function when it wants to register an
  109. // outgoing interface
  110. //
  111. // this interface is used to register the ITTAPIEventNotification
  112. // interface which is used to get all TAPI call control events
  113. //
  114. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  115. HRESULT
  116. STDMETHODCALLTYPE
  117. CTAPIConnectionPoint::Advise(
  118. IUnknown * pUnk,
  119. DWORD * pdwCookie
  120. )
  121. {
  122. HRESULT hr = S_OK;
  123. CONNECTDATA * pCD;
  124. IID iid;
  125. LOG((TL_TRACE, "Advise[%p] called", this));
  126. if ( TAPIIsBadWritePtr( pdwCookie, sizeof (DWORD) ) )
  127. {
  128. LOG((TL_ERROR, "Advise - bad pointer"));
  129. return E_POINTER;
  130. }
  131. if ( IsBadReadPtr( pUnk, sizeof(IUnknown *) ) )
  132. {
  133. LOG((TL_ERROR, "Advise - bad IUnknown"));
  134. return E_POINTER;
  135. }
  136. Lock();
  137. if ( m_bInitialized == FALSE )
  138. {
  139. LOG((TL_ERROR, "Advise - not initialized"));
  140. Unlock();
  141. return TAPI_E_NOT_INITIALIZED;
  142. }
  143. //
  144. // We only allow one callback per connection point
  145. //
  146. if ( NULL != m_pConnectData )
  147. {
  148. LOG((TL_ERROR, "Advise - advise already called"));
  149. Unlock();
  150. return CONNECT_E_ADVISELIMIT;
  151. }
  152. //
  153. // Create a new connectdata struct
  154. //
  155. m_pConnectData = (CONNECTDATA *) ClientAlloc( sizeof CONNECTDATA );
  156. if (NULL == m_pConnectData)
  157. {
  158. LOG((TL_ERROR, "Advise failed - pCD == NULL"));
  159. Unlock();
  160. return E_OUTOFMEMORY;
  161. }
  162. //
  163. // Keep a reference to the callback
  164. //
  165. try
  166. {
  167. pUnk->AddRef();
  168. }
  169. catch(...)
  170. {
  171. LOG((TL_ERROR, "Advise - IUnknown bad"));
  172. ClientFree( m_pConnectData );
  173. m_pConnectData = NULL;
  174. Unlock();
  175. return E_POINTER;
  176. }
  177. //
  178. // Save the interface
  179. //
  180. m_pConnectData->pUnk = pUnk;
  181. ITTAPIEventNotification *pEventNotification;
  182. hr = pUnk->QueryInterface(IID_ITTAPIEventNotification,
  183. (void**)(&pEventNotification)
  184. );
  185. if (SUCCEEDED(hr) )
  186. {
  187. iid = IID_ITTAPIEventNotification;
  188. pEventNotification->Release();
  189. }
  190. else
  191. {
  192. iid = DIID_ITTAPIDispatchEventNotification;
  193. }
  194. m_iid = iid;
  195. m_pConnectData->dwCookie = CreateHandleTableEntry((ULONG_PTR)m_pConnectData);
  196. //
  197. // Return the cookie
  198. //
  199. *pdwCookie = m_pConnectData->dwCookie;
  200. //set it to FALSE if not already set.
  201. m_fMarkedForDelete = FALSE;
  202. Unlock();
  203. LOG((TL_TRACE, "Advise generated cookie [%lx]", *pdwCookie));
  204. //
  205. // Put the callback in the globalinterfacetable
  206. // so it can be accessed across threads
  207. //
  208. EnterCriticalSection( &gcsGlobalInterfaceTable );
  209. if ( NULL != gpGIT )
  210. {
  211. hr = gpGIT->RegisterInterfaceInGlobal(
  212. pUnk,
  213. iid,
  214. &m_dwCallbackCookie
  215. );
  216. }
  217. else
  218. {
  219. hr = E_FAIL;
  220. }
  221. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  222. if ( FAILED(hr) )
  223. {
  224. Lock();
  225. LOG((TL_ERROR, "Advise - RegisterInterfaceInGlobal failed - %lx", hr));
  226. DeleteHandleTableEntry(m_pConnectData->dwCookie);
  227. *pdwCookie = 0;
  228. ClientFree( m_pConnectData );
  229. m_pConnectData = NULL;
  230. m_fMarkedForDelete = TRUE;
  231. pUnk->Release();
  232. Unlock();
  233. }
  234. LOG((TL_TRACE, "Advise - exit"));
  235. return hr;
  236. }
  237. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  238. //
  239. // Unadvise
  240. //
  241. // Used to unregister an interface
  242. //
  243. // dwCookie - Cookie used to identify the interface registration, returned in
  244. // advise
  245. //
  246. // returns
  247. // S_OK
  248. // CONNECT_E_NOCONNECTION
  249. // dwCookie is not a valid connection
  250. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  251. HRESULT
  252. STDMETHODCALLTYPE
  253. CTAPIConnectionPoint::Unadvise(
  254. DWORD dwCookie
  255. )
  256. {
  257. HRESULT hr = S_OK;
  258. LOG((TL_TRACE, "Unadvise[%p] - enter. Cookie: [%lx]", this, dwCookie));
  259. Lock();
  260. //
  261. // Check connection point
  262. //
  263. if ( NULL != m_pConnectData )
  264. {
  265. //
  266. // Check cookie
  267. //
  268. if (m_pConnectData->dwCookie == dwCookie)
  269. {
  270. LOG((TL_INFO, "Unadvise - immediate "));
  271. //
  272. // Remove entry for this cookie from the handle table
  273. //
  274. DeleteHandleTableEntry(m_pConnectData->dwCookie);
  275. //
  276. // Free the connect data
  277. //
  278. m_pConnectData->dwCookie = 0;
  279. m_pConnectData->pUnk->Release();
  280. ClientFree( m_pConnectData );
  281. m_pConnectData = NULL;
  282. Unlock();
  283. EnterCriticalSection( &gcsGlobalInterfaceTable );
  284. //
  285. // Mark for delete
  286. //
  287. m_fMarkedForDelete = TRUE;
  288. if ( NULL != gpGIT )
  289. {
  290. //
  291. // If there are threads in get we must wait for them to complete so
  292. // we can call revoke
  293. //
  294. while ( m_cThreadsInGet != 0 )
  295. {
  296. LOG((TL_INFO, "Unadvise - %ld threads in get", m_cThreadsInGet));
  297. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  298. DWORD dwSignalled;
  299. CoWaitForMultipleHandles (
  300. 0,
  301. INFINITE,
  302. 1,
  303. &m_hUnadviseEvent,
  304. &dwSignalled
  305. );
  306. EnterCriticalSection( &gcsGlobalInterfaceTable );
  307. }
  308. //
  309. // We have guaranteed that no threads are in get. Do the revoke.
  310. //
  311. hr = gpGIT->RevokeInterfaceFromGlobal( m_dwCallbackCookie );
  312. if ( FAILED(hr) )
  313. {
  314. LOG((TL_ERROR, "Unadvise - RevokeInterfaceFromGlobal failed - hr = %lx", hr));
  315. }
  316. m_dwCallbackCookie = 0;
  317. }
  318. else
  319. {
  320. LOG((TL_ERROR, "Unadvise - no global interface table"));
  321. }
  322. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  323. }
  324. else
  325. {
  326. Unlock();
  327. LOG((TL_ERROR, "Unadvise - cp does not match "));
  328. hr = CONNECT_E_NOCONNECTION;
  329. }
  330. }
  331. else
  332. {
  333. Unlock();
  334. LOG((TL_ERROR, "Unadvise - cp not registered "));
  335. hr = CONNECT_E_NOCONNECTION;
  336. }
  337. LOG((TL_TRACE, hr, "Unadvise - exit"));
  338. return hr;
  339. }
  340. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  341. //
  342. // EnumConnections
  343. //
  344. // Used to enumerate connections already made on this connection point
  345. //
  346. // ppEnum
  347. // return enumerator in here
  348. //
  349. // returns
  350. // S_OK
  351. // E_POINTER
  352. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  353. HRESULT
  354. STDMETHODCALLTYPE
  355. CTAPIConnectionPoint::EnumConnections(
  356. IEnumConnections ** ppEnum
  357. )
  358. {
  359. HRESULT hr = S_OK;
  360. if ( TAPIIsBadWritePtr( ppEnum, sizeof( IEnumConnections *) ) )
  361. {
  362. LOG((TL_ERROR, "EnumConnections - bad pointer"));
  363. return E_POINTER;
  364. }
  365. //
  366. // Create enumerate object
  367. //
  368. CComObject< CTapiTypeEnum <IEnumConnections,
  369. CONNECTDATA,
  370. _Copy<CONNECTDATA>,
  371. &IID_IEnumConnections> > * p;
  372. hr = CComObject< CTapiTypeEnum <IEnumConnections,
  373. CONNECTDATA,
  374. _Copy<CONNECTDATA>,
  375. &IID_IEnumConnections> >::CreateInstance( &p );
  376. if (S_OK != hr)
  377. {
  378. return hr;
  379. }
  380. //
  381. // Initialize it
  382. //
  383. ConnectDataArray newarray;
  384. Lock();
  385. if ( NULL != m_pConnectData )
  386. {
  387. newarray.Add(*m_pConnectData);
  388. }
  389. Unlock();
  390. hr = p->Initialize( newarray );
  391. newarray.Shutdown();
  392. if (S_OK != hr)
  393. {
  394. return hr;
  395. }
  396. *ppEnum = p;
  397. return S_OK;
  398. }
  399. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  400. //
  401. // FinalRelease
  402. // release all CONNECTDATA structs
  403. //
  404. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  405. void
  406. CTAPIConnectionPoint::FinalRelease()
  407. {
  408. LOG((TL_TRACE, "FinalRelease - enter"));
  409. if (NULL != m_pConnectData)
  410. {
  411. //
  412. // The app didn't call unadvise. Let's do it now.
  413. //
  414. LOG((TL_INFO, "FinalRelease - calling unadvise"));
  415. Unadvise(m_pConnectData->dwCookie) ;
  416. }
  417. //
  418. // Release the connection point container
  419. //
  420. if (m_pCPC)
  421. {
  422. m_pCPC->Release();
  423. m_pCPC = NULL;
  424. }
  425. //
  426. // Close the unadvise event
  427. //
  428. if (m_hUnadviseEvent)
  429. {
  430. CloseHandle(m_hUnadviseEvent);
  431. m_hUnadviseEvent = NULL;
  432. }
  433. LOG((TL_TRACE, "FinalRelease - exit"));
  434. }
  435. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  436. //
  437. // the object calls this to get a marshaled event
  438. // pointer in the correct thread
  439. //
  440. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  441. ULONG_PTR
  442. CTAPIConnectionPoint::GrabEventCallback()
  443. {
  444. IUnknown * pReturn = NULL;
  445. HRESULT hr = E_FAIL;
  446. DWORD dwCallbackCookie;
  447. IID iid;
  448. Lock();
  449. //
  450. // If we're already released, don't try to send any events.
  451. //
  452. if ( NULL != m_pConnectData )
  453. {
  454. //
  455. // Copy member data
  456. //
  457. iid = m_iid;
  458. Unlock();
  459. EnterCriticalSection( &gcsGlobalInterfaceTable );
  460. if (m_fMarkedForDelete == FALSE)
  461. {
  462. //
  463. // Add to the count of threads in get.
  464. //
  465. m_cThreadsInGet++;
  466. //
  467. // Copy member data
  468. //
  469. dwCallbackCookie = m_dwCallbackCookie;
  470. if (gpGIT != NULL)
  471. {
  472. gpGIT->AddRef();
  473. //
  474. // Don't hold a critical section while getting
  475. //
  476. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  477. hr = gpGIT->GetInterfaceFromGlobal(
  478. dwCallbackCookie,
  479. iid,
  480. (void **)&pReturn
  481. );
  482. if ( SUCCEEDED(hr) )
  483. {
  484. LOG((TL_INFO, "GrabEventCallback - GetInterfaceFromGlobal suceeded [%p]", pReturn));
  485. }
  486. else
  487. {
  488. LOG((TL_ERROR, "GrabEventCallback - GetInterfaceFromGlobal failed - hr = %lx", hr));
  489. pReturn = NULL;
  490. }
  491. EnterCriticalSection( &gcsGlobalInterfaceTable );
  492. gpGIT->Release();
  493. }
  494. //
  495. // Done. Decrement the count of threads in get.
  496. //
  497. m_cThreadsInGet--;
  498. }
  499. else
  500. {
  501. LOG((TL_INFO, "GrabEventCallback - already marked for delete"));
  502. }
  503. LeaveCriticalSection( &gcsGlobalInterfaceTable );
  504. if ( m_fMarkedForDelete == TRUE )
  505. {
  506. //
  507. // Someone called unadvise while we were using the cookie.
  508. // Signal so they can do the revoke now.
  509. //
  510. if ( m_hUnadviseEvent )
  511. {
  512. SetEvent(m_hUnadviseEvent);
  513. }
  514. else
  515. {
  516. LOG((TL_ERROR, "GrabEventCallback - no event"));
  517. _ASSERTE(FALSE);
  518. }
  519. //
  520. // If we got a callback, no need to return it because
  521. // unadvise has been called.
  522. //
  523. if ( pReturn != NULL )
  524. {
  525. pReturn->Release();
  526. pReturn = NULL;
  527. }
  528. }
  529. }
  530. else
  531. {
  532. LOG((TL_ERROR, "GrabEventCallback - already released"));
  533. Unlock();
  534. }
  535. LOG((TL_TRACE, hr, "GrabEventCallback - exit"));
  536. return (ULONG_PTR)pReturn;
  537. }