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.

682 lines
24 KiB

  1. /*****************************************************************************
  2. * (C) COPYRIGHT MICROSOFT CORPORATION, 2002
  3. *
  4. * AUTHOR: ByronC
  5. *
  6. * DATE: 3/24/2002
  7. *
  8. * @doc INTERNAL
  9. *
  10. * @module WiaEventNotifier.cpp - Implementation file for <c WiaEventNotifier> |
  11. *
  12. * This file contains the implementation for the <c WiaEventNotifier> class.
  13. *
  14. *****************************************************************************/
  15. #include "precomp.h"
  16. /*****************************************************************************
  17. * @doc INTERNAL
  18. *
  19. * @mfunc | WiaEventNotifier | WiaEventNotifier |
  20. *
  21. * We initialize all member variables. In general, this sets the values to 0,
  22. * except:
  23. * <nl><md WiaEventNotifier::m_ulSig> is set to be WiaEventNotifier_UNINIT_SIG.
  24. * <nl><md WiaEventNotifier::m_cRef> is set to be 1.
  25. *
  26. *****************************************************************************/
  27. WiaEventNotifier::WiaEventNotifier() :
  28. m_ulSig(WiaEventNotifier_UNINIT_SIG),
  29. m_cRef(1)
  30. {
  31. DBG_FN(WiaEventNotifier constructor);
  32. }
  33. /*****************************************************************************
  34. * @doc INTERNAL
  35. *
  36. * @mfunc | WiaEventNotifier | ~WiaEventNotifier |
  37. *
  38. * Do any cleanup that is not already done.
  39. *
  40. * Also:
  41. * <nl><md WiaEventNotifier::m_ulSig> is set to be WiaEventNotifier_DEL_SIG.
  42. *
  43. *****************************************************************************/
  44. WiaEventNotifier::~WiaEventNotifier()
  45. {
  46. DBG_FN(~WiaEventNotifier destructor);
  47. m_ulSig = WiaEventNotifier_DEL_SIG;
  48. m_cRef = 0;
  49. DestroyClientList();
  50. }
  51. /*****************************************************************************
  52. * @doc INTERNAL
  53. *
  54. * @mfunc ULONG | WiaEventNotifier | AddRef |
  55. *
  56. * Increments this object's ref count. We should always AddRef when handing
  57. * out a pointer to this object.
  58. *
  59. * @rvalue Count |
  60. * The reference count after the count has been incremented.
  61. *****************************************************************************/
  62. ULONG __stdcall WiaEventNotifier::AddRef()
  63. {
  64. InterlockedIncrement((long*) &m_cRef);
  65. return m_cRef;
  66. }
  67. /*****************************************************************************
  68. * @doc INTERNAL
  69. *
  70. * @mfunc ULONG | WiaEventNotifier | Release |
  71. *
  72. * Decrement this object's ref count. We should always Release when finished
  73. * with a pointer to this object.
  74. *
  75. * @rvalue Count |
  76. * The reference count after the count has been decremented.
  77. *****************************************************************************/
  78. ULONG __stdcall WiaEventNotifier::Release()
  79. {
  80. ULONG ulRefCount = m_cRef - 1;
  81. if (InterlockedDecrement((long*) &m_cRef) == 0) {
  82. delete this;
  83. return 0;
  84. }
  85. return ulRefCount;
  86. }
  87. /*****************************************************************************
  88. * @doc INTERNAL
  89. *
  90. * @mfunc HRESULT | WiaEventNotifier | Initialize |
  91. *
  92. * Create and initialize any dependant objects/resources. Specifically:
  93. * <nl>- Check that <md WiaEventNotifier::m_csClientListSync> is initialized
  94. * correctly.
  95. *
  96. * If this method fails, the object should not be used - it should be
  97. * destroyed immediately.
  98. *
  99. * @rvalue S_OK |
  100. * The method succeeded.
  101. * @rvalue E_UNEXPECTED |
  102. * The object could not be intialized sucessfully.
  103. *****************************************************************************/
  104. HRESULT WiaEventNotifier::Initialize()
  105. {
  106. HRESULT hr = S_OK;
  107. if (!m_csClientListSync.IsInitialized())
  108. {
  109. DBG_ERR(("Runtime event Error: WiaEventNotifier's sync primitive could not be created"));
  110. hr = E_UNEXPECTED;
  111. }
  112. if (SUCCEEDED(hr))
  113. {
  114. m_ulSig = WiaEventNotifier_INIT_SIG;
  115. }
  116. return hr;
  117. }
  118. /*****************************************************************************
  119. * @doc INTERNAL
  120. *
  121. * @mfunc HRESULT | WiaEventNotifier | AddClient |
  122. *
  123. * Adds a new client to the list of registered clients.
  124. *
  125. * If this method successfully adds the WiaEventClient, <p pWiaEventClient>
  126. * is AddRef'd.
  127. *
  128. * @parm WiaEventClient | pWiaEventClient |
  129. * The address of a caller allocated object representing the client.
  130. *
  131. * @rvalue S_OK |
  132. * The method succeeded.
  133. * @rvalue S_FALSE |
  134. * The client already exists.
  135. * @rvalue E_UNEXPECTED |
  136. * An exception was thrown trying to add a client.
  137. * @rvalue E_POINTER |
  138. * <p pWiaEventClient> is an invalid pointer.
  139. *****************************************************************************/
  140. HRESULT WiaEventNotifier::AddClient(
  141. WiaEventClient *pWiaEventClient)
  142. {
  143. HRESULT hr = S_OK;
  144. TAKE_CRIT_SECT t(m_csClientListSync);
  145. //
  146. // Do parameter check
  147. //
  148. if (!pWiaEventClient)
  149. {
  150. return E_POINTER;
  151. }
  152. //
  153. // We put an exception handler around our code to ensure that the
  154. // crtitical section is exited properly.
  155. //
  156. _try
  157. {
  158. if (!isRegisteredClient(pWiaEventClient->getClientContext()))
  159. {
  160. DBG_TRC(("=> Added client %p to WiaEventNotifier", pWiaEventClient->getClientContext()));
  161. m_ListOfClients.Prepend(pWiaEventClient);
  162. pWiaEventClient->AddRef();
  163. }
  164. else
  165. {
  166. // TBD: Check whether this should be ignored, or indicates a logic error
  167. DBG_WRN(("Warning: Attempting to add client %p to WiaEventNotifier when it already exists in the list", pWiaEventClient->getClientContext()));
  168. hr = S_FALSE;
  169. }
  170. }
  171. _except(EXCEPTION_EXECUTE_HANDLER)
  172. {
  173. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to add a new client", GetExceptionCode()));
  174. hr = E_UNEXPECTED;
  175. // TBD: Should we re-throw the exception?
  176. }
  177. return hr;
  178. }
  179. /*****************************************************************************
  180. * @doc INTERNAL
  181. *
  182. * @mfunc HRESULT | WiaEventNotifier | RemoveClient |
  183. *
  184. * Removes the <c WiaEventClient> identified by <p ClientContext> from the list.
  185. * The <c WiaEventClient> is also Release'd.
  186. *
  187. * @parm STI_CLIENT_CONTEXT | ClientContext |
  188. * Identifies the client to remove.
  189. *
  190. * @rvalue S_OK |
  191. * The method succeeded.
  192. * @rvalue S_FALSE |
  193. * The client didn't exist in the list.
  194. * @rvalue E_UNEXPECTED |
  195. * An exception was thrown trying to remove a client.
  196. *****************************************************************************/
  197. HRESULT WiaEventNotifier::RemoveClient(
  198. STI_CLIENT_CONTEXT ClientContext)
  199. {
  200. HRESULT hr = S_FALSE;
  201. TAKE_CRIT_SECT t(m_csClientListSync);
  202. //
  203. // We put an exception handler around our code to ensure that the
  204. // crtitical section is exited properly.
  205. //
  206. _try
  207. {
  208. //
  209. // Walk the list of client's and compare the client contexts.
  210. // When we find the relevant one, remove it from the list.
  211. //
  212. WiaEventClient *pWiaEventClient = NULL;
  213. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  214. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  215. {
  216. pWiaEventClient = *iter;
  217. if (pWiaEventClient)
  218. {
  219. if (pWiaEventClient->getClientContext() == ClientContext)
  220. {
  221. //
  222. // We found it, so remove it from the list and set the return.
  223. // There's no need to continue the iteration, so break out of the
  224. // loop.
  225. //
  226. DBG_TRC(("<= Removed client %p from WiaEventNotifier", ClientContext));
  227. m_ListOfClients.Remove(pWiaEventClient);
  228. pWiaEventClient->Release();
  229. hr = S_OK;
  230. break;
  231. }
  232. }
  233. else
  234. {
  235. //
  236. // Log Error
  237. // pWiaEventClient should never be NULL
  238. DBG_ERR(("Runtime event Error: While searching for a client to remove, we hit a NULL WiaEventClient!"));
  239. }
  240. }
  241. }
  242. _except(EXCEPTION_EXECUTE_HANDLER)
  243. {
  244. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to remove a client", GetExceptionCode()));
  245. hr = E_UNEXPECTED;
  246. // TBD: Should we re-throw the exception?
  247. }
  248. return hr;
  249. }
  250. /*****************************************************************************
  251. * @doc INTERNAL
  252. *
  253. * @mfunc HRESULT | WiaEventNotifier | GetClientFromContext |
  254. *
  255. * Returns the <c WiaEventClient> corresponding to the given client
  256. * context.
  257. *
  258. * @parm STI_CLIENT_CONTEXT | ClientContext |
  259. * Identifies the client to return.
  260. *
  261. * @rvalue NULL |
  262. * The client could not be found.
  263. * @rvalue non-NULL |
  264. * The client was found. Caller must Release when done.
  265. *****************************************************************************/
  266. WiaEventClient* WiaEventNotifier::GetClientFromContext(
  267. STI_CLIENT_CONTEXT ClientContext)
  268. {
  269. WiaEventClient *pRet = NULL;
  270. TAKE_CRIT_SECT t(m_csClientListSync);
  271. //
  272. // We put an exception handler around our code to ensure that the
  273. // crtitical section is exited properly.
  274. //
  275. _try
  276. {
  277. //
  278. // Walk the list of client's and compare the client contexts
  279. //
  280. WiaEventClient *pWiaEventClient = NULL;
  281. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  282. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  283. {
  284. pWiaEventClient = *iter;
  285. if (pWiaEventClient)
  286. {
  287. if (pWiaEventClient->getClientContext() == ClientContext)
  288. {
  289. //
  290. // We found it, so set the return and break out of the loop
  291. //
  292. pRet = pWiaEventClient;
  293. pRet->AddRef();
  294. break;
  295. }
  296. }
  297. else
  298. {
  299. //
  300. // Log Error
  301. // pWiaEventClient should never be NULL
  302. DBG_ERR(("Runtime event Error: While searching for a client from its context, we hit a NULL WiaEventClient!"));
  303. }
  304. }
  305. }
  306. _except(EXCEPTION_EXECUTE_HANDLER)
  307. {
  308. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to return client %p", GetExceptionCode(), ClientContext));
  309. // TBD: Should we re-throw the exception?
  310. }
  311. return pRet;
  312. }
  313. /*****************************************************************************
  314. * @doc INTERNAL
  315. *
  316. * @mfunc VOID | WiaEventNotifier | NotifyClients |
  317. *
  318. * This method walks the list of clients and adds this event to the pending event
  319. * queue of any clients that are suitably registered for this event occurrence.
  320. *
  321. * Afterwards, it runs cleanup on the client list (see <mf WiaEventNotifier::CleanupClientList>)
  322. *
  323. * @parm WiaEventInfo | pWiaEventInfo |
  324. * Contains the relevant event notification data.
  325. *
  326. *****************************************************************************/
  327. VOID WiaEventNotifier::NotifyClients(
  328. WiaEventInfo *pWiaEventInfo)
  329. {
  330. if (pWiaEventInfo)
  331. {
  332. TAKE_CRIT_SECT t(m_csClientListSync);
  333. //
  334. // We put an exception handler around our code to ensure that the
  335. // crtitical section is exited properly.
  336. //
  337. _try
  338. {
  339. DBG_WRN(("(NotifyClients) # of clients: %d", m_ListOfClients.Count()));
  340. //
  341. // Walk the list of client's and compare the client contexts
  342. //
  343. WiaEventClient *pWiaEventClient = NULL;
  344. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  345. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  346. {
  347. pWiaEventClient = *iter;
  348. if (pWiaEventClient)
  349. {
  350. //
  351. // Check whether the client is registered to receive this
  352. // type of event notification. If it is, add it to the client's
  353. // pending event list.
  354. //
  355. if (pWiaEventClient->IsRegisteredForEvent(pWiaEventInfo))
  356. {
  357. pWiaEventClient->AddPendingEventNotification(pWiaEventInfo);
  358. }
  359. }
  360. else
  361. {
  362. //
  363. // Log Error
  364. // pWiaEventClient should never be NULL
  365. DBG_ERR(("Runtime event Error: While destroying the client list, we hit a NULL WiaEventClient!"));
  366. }
  367. }
  368. //
  369. // Remove any dead clients from the list
  370. //
  371. CleanupClientList();
  372. }
  373. _except(EXCEPTION_EXECUTE_HANDLER)
  374. {
  375. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to notify clients of an event", GetExceptionCode()));
  376. // TBD: Should we re-throw the exception?
  377. }
  378. }
  379. else
  380. {
  381. DBG_ERR(("Runtime event Error: The WIA Event notifier cannot notify clients of a NULL event"));
  382. }
  383. }
  384. /*****************************************************************************
  385. * @doc INTERNAL
  386. *
  387. * @mfunc BOOL | WiaEventNotifier | isRegisteredClient |
  388. *
  389. * Checks whether the client identified by <p ClientContext> is
  390. * in the client list.
  391. *
  392. * @parm STI_CLIENT_CONTEXT | ClientContext |
  393. * Identifies the client.
  394. *
  395. * @rvalue S_OK |
  396. * The method succeeded.
  397. *****************************************************************************/
  398. BOOL WiaEventNotifier::isRegisteredClient(
  399. STI_CLIENT_CONTEXT ClientContext)
  400. {
  401. BOOL bIsInList = FALSE;
  402. TAKE_CRIT_SECT t(m_csClientListSync);
  403. //
  404. // We put an exception handler around our code to ensure that the
  405. // crtitical section is exited properly.
  406. //
  407. _try
  408. {
  409. //
  410. // Walk the list of client's and compare the client contexts
  411. //
  412. WiaEventClient *pWiaEventClient = NULL;
  413. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  414. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  415. {
  416. pWiaEventClient = *iter;
  417. if (pWiaEventClient)
  418. {
  419. if (pWiaEventClient->getClientContext() == ClientContext)
  420. {
  421. //
  422. // We found it, so set the return to TRUE and break from the loop
  423. //
  424. bIsInList = TRUE;
  425. break;
  426. }
  427. }
  428. else
  429. {
  430. //
  431. // Log Error
  432. // pWiaEventClient should never be NULL
  433. DBG_ERR(("Runtime event Error: While searching for a client context, we hit a NULL WiaEventClient!"));
  434. }
  435. }
  436. }
  437. _except(EXCEPTION_EXECUTE_HANDLER)
  438. {
  439. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to check whether client %p is registered", GetExceptionCode(), ClientContext));
  440. // TBD: Should we re-throw the exception?
  441. }
  442. return bIsInList;
  443. }
  444. /*****************************************************************************
  445. * @doc INTERNAL
  446. *
  447. * @mfunc VOID | WiaEventNotifier | DestroyClientList |
  448. *
  449. * This method is called to free resources associated with the clien list.
  450. * It walks the list of clients and releases each one. It then frees
  451. * up the memory for the links in the list by destorying the list itsself.
  452. *
  453. *****************************************************************************/
  454. VOID WiaEventNotifier::DestroyClientList()
  455. {
  456. TAKE_CRIT_SECT t(m_csClientListSync);
  457. //
  458. // We put an exception handler around our code to ensure that the
  459. // crtitical section is exited properly.
  460. //
  461. _try
  462. {
  463. //
  464. // Walk the list of client's and compare the client contexts
  465. //
  466. WiaEventClient *pWiaEventClient = NULL;
  467. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  468. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  469. {
  470. pWiaEventClient = *iter;
  471. if (pWiaEventClient)
  472. {
  473. pWiaEventClient->Release();
  474. }
  475. else
  476. {
  477. //
  478. // Log Error
  479. // pWiaEventClient should never be NULL
  480. DBG_ERR(("Runtime event Error: While destroying the client list, we hit a NULL WiaEventClient!"));
  481. }
  482. }
  483. m_ListOfClients.Destroy();
  484. }
  485. _except(EXCEPTION_EXECUTE_HANDLER)
  486. {
  487. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to destroy the client list", GetExceptionCode()));
  488. // TBD: Should we re-throw the exception?
  489. }
  490. }
  491. /*****************************************************************************
  492. * @doc INTERNAL
  493. *
  494. * @mfunc VOID | WiaEventNotifier | MarkClientForRemoval |
  495. *
  496. * Marks the appropriate client for later removal. We simply mark it here - the
  497. * actual removal will be done at a later time when it is safer and more
  498. * convenient to do so.
  499. *
  500. * @parm STI_CLIENT_CONTEXT | ClientContext |
  501. * Identifies the client.
  502. *****************************************************************************/
  503. VOID WiaEventNotifier::MarkClientForRemoval(
  504. STI_CLIENT_CONTEXT ClientContext)
  505. {
  506. TAKE_CRIT_SECT t(m_csClientListSync);
  507. //
  508. // We put an exception handler around our code to ensure that the
  509. // crtitical section is exited properly.
  510. //
  511. _try
  512. {
  513. //
  514. // Walk the list of client's and compare the client contexts
  515. //
  516. WiaEventClient *pWiaEventClient = NULL;
  517. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  518. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  519. {
  520. pWiaEventClient = *iter;
  521. if (pWiaEventClient)
  522. {
  523. if (pWiaEventClient->getClientContext() == ClientContext)
  524. {
  525. //
  526. // We found it, so mark this one for removal and break
  527. //
  528. pWiaEventClient->MarkForRemoval();
  529. break;
  530. }
  531. }
  532. else
  533. {
  534. //
  535. // Log Error
  536. // pWiaEventClient should never be NULL
  537. DBG_ERR(("Runtime event Error: While searching for a client context, we hit a NULL WiaEventClient!"));
  538. }
  539. }
  540. }
  541. _except(EXCEPTION_EXECUTE_HANDLER)
  542. {
  543. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to check whether client %p is registered", GetExceptionCode(), ClientContext));
  544. // TBD: Should we re-throw the exception?
  545. }
  546. }
  547. /*****************************************************************************
  548. * @doc INTERNAL
  549. *
  550. * @mfunc VOID | WiaEventNotifier | CleanupClientList |
  551. *
  552. * Walks the client list and removes any that are marked for removal.
  553. * In order to do this safely, we need to make a copy of the list. We
  554. * then traverse the copy, and remove and release any relevant clients
  555. * from the original.
  556. *
  557. *****************************************************************************/
  558. VOID WiaEventNotifier::CleanupClientList()
  559. {
  560. TAKE_CRIT_SECT t(m_csClientListSync);
  561. HRESULT hr = S_OK;
  562. //
  563. // We put an exception handler around our code to ensure that the
  564. // crtitical section is exited properly.
  565. //
  566. _try
  567. {
  568. //
  569. // Make our copy of the client list
  570. //
  571. CSimpleLinkedList<WiaEventClient*> CopyOfClientList;
  572. hr = CopyClientListNoAddRef(CopyOfClientList);
  573. if (SUCCEEDED(hr))
  574. {
  575. //
  576. // Walk the copied list of client's and check which are marked for removal
  577. //
  578. WiaEventClient *pWiaEventClient = NULL;
  579. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  580. for (iter = CopyOfClientList.Begin(); iter != CopyOfClientList.End(); ++iter)
  581. {
  582. pWiaEventClient = *iter;
  583. if (pWiaEventClient)
  584. {
  585. if (pWiaEventClient->isMarkedForRemoval())
  586. {
  587. //
  588. // We found that is marked for removal, so release and remove this from the original
  589. //
  590. m_ListOfClients.Remove(pWiaEventClient);
  591. pWiaEventClient->Release();
  592. }
  593. }
  594. }
  595. }
  596. }
  597. _except(EXCEPTION_EXECUTE_HANDLER)
  598. {
  599. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to remove old clients", GetExceptionCode()));
  600. // TBD: Should we re-throw the exception?
  601. }
  602. }
  603. /*****************************************************************************
  604. * @doc INTERNAL
  605. *
  606. * @mfunc HRESULT | WiaEventNotifier | CopyClientListNoAddRef |
  607. *
  608. * This method produces a copy of the client list. It walks the list of clients,
  609. * and adds each client to the new list. The client object is NOT AddRef'd.
  610. *
  611. * This is primarily uses during removal: the copy of the list can be safely
  612. * traversed while we release and remove relevant elemnts from the original.
  613. *
  614. * @parm CSimpleLinkedList<lt>USDWrapper*<gt>& | ReturnedDeviceListCopy |
  615. * This parameter is passed by reference. On return from this method, it
  616. * will contain all <c WiaEventClient>s in
  617. * <md WiaEventNotifier::m_ListOfClients>.
  618. *
  619. * @rvalue S_OK |
  620. * The method succeeded.
  621. * @rvalue E_XXXXXXXX |
  622. * We could not make a copy of the list.
  623. *****************************************************************************/
  624. HRESULT WiaEventNotifier::CopyClientListNoAddRef(
  625. CSimpleLinkedList<WiaEventClient*> &newList)
  626. {
  627. HRESULT hr = S_OK;
  628. TAKE_CRIT_SECT t(m_csClientListSync);
  629. //
  630. // We put an exception handler around our code to ensure that the
  631. // crtitical section is exited properly.
  632. //
  633. _try
  634. {
  635. WiaEventClient *pWiaEventClient = NULL;
  636. CSimpleLinkedList<WiaEventClient*>::Iterator iter;
  637. for (iter = m_ListOfClients.Begin(); iter != m_ListOfClients.End(); ++iter)
  638. {
  639. pWiaEventClient = *iter;
  640. if (pWiaEventClient)
  641. {
  642. newList.Prepend(pWiaEventClient);
  643. }
  644. }
  645. }
  646. _except(EXCEPTION_EXECUTE_HANDLER)
  647. {
  648. DBG_ERR(("Runtime event Error: The WiaEventNotifier caught an exception (0x%08X) trying to make a copy of the client list", GetExceptionCode()));
  649. hr = E_UNEXPECTED;
  650. // TBD: Should we re-throw the exception?
  651. }
  652. return hr;
  653. }