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.

699 lines
27 KiB

  1. /*****************************************************************************
  2. * (C) COPYRIGHT MICROSOFT CORPORATION, 2002
  3. *
  4. * AUTHOR: ByronC
  5. *
  6. * DATE: 3/30/2002
  7. *
  8. * @doc INTERNAL
  9. *
  10. * @module WiaEventReceiver.cpp - Declarations for <c WiaEventReceiver> |
  11. *
  12. * This file contains the implementation for the <c WiaEventReceiver> class.
  13. *
  14. *****************************************************************************/
  15. #include "cplusinc.h"
  16. #include "coredbg.h"
  17. /*****************************************************************************
  18. * @doc INTERNAL
  19. *
  20. * @mfunc | WiaEventReceiver | WiaEventReceiver |
  21. *
  22. * We initialize all member variables. In general, this sets the values to 0,
  23. * except:
  24. * <nl><md WiaEventReceiver::m_ulSig> is set to be WiaEventReceiver_UNINIT_SIG.
  25. * <nl><md WiaEventReceiver::m_cRef> is set to be 1.
  26. * <nl><md WiaEventReceiver::m_pClientEventTransport> is set to be <p pClientEventTransport>.
  27. *
  28. * @parm ClientEventTransport* | pClientEventTransport |
  29. * The transport class used to communicate with the WIA Service.
  30. *
  31. *****************************************************************************/
  32. WiaEventReceiver::WiaEventReceiver(
  33. ClientEventTransport *pClientEventTransport) :
  34. m_ulSig(WiaEventReceiver_UNINIT_SIG),
  35. m_cRef(1),
  36. m_pClientEventTransport(pClientEventTransport),
  37. m_hEventThread(NULL),
  38. m_bIsRunning(FALSE),
  39. m_dwEventThreadID(0)
  40. {
  41. }
  42. /*****************************************************************************
  43. * @doc INTERNAL
  44. *
  45. * @mfunc | WiaEventReceiver | ~WiaEventReceiver |
  46. *
  47. * Do any cleanup that is not already done.
  48. * <nl>- Call <mf WiaEventReceiver::Stop>
  49. * <nl>- Delete <mf WiaEventReceiver::m_pClientEventTransport>
  50. * <nl>- Call <mf WiaEventReceiver::DestroyRegistrationList>
  51. *
  52. * Also:
  53. * <nl><md WiaEventReceiver::m_ulSig> is set to be WiaEventReceiver_DEL_SIG.
  54. *
  55. *****************************************************************************/
  56. WiaEventReceiver::~WiaEventReceiver()
  57. {
  58. m_ulSig = WiaEventReceiver_DEL_SIG;
  59. m_cRef = 0;
  60. Stop();
  61. if (m_pClientEventTransport)
  62. {
  63. delete m_pClientEventTransport;
  64. m_pClientEventTransport = NULL;
  65. }
  66. DestroyRegistrationList();
  67. }
  68. /*****************************************************************************
  69. * @doc INTERNAL
  70. *
  71. * @mfunc HRESULT | WiaEventReceiver | Start |
  72. *
  73. * This method does any initialization steps needed to start receiving
  74. * notifications from the WIA Service. We:
  75. * <nl>- Open our connection to the server
  76. * <nl>- Open our notification channel
  77. * <nl>- Create our event thread
  78. *
  79. * This method is idempotent i.e. you can call <mf WiaEventReceiver::Start> multiple times safely
  80. * before calling <mf WiaEventReceiver::Stop>. Subsequent calls to <mf WiaEventReceiver::Start>
  81. * have no effect until <mf WiaEventReceiver::Stop> has been called.
  82. *
  83. * @rvalue S_OK |
  84. * This object initialized correctly.
  85. * @rvalue E_XXXXXXXXX |
  86. * This object could not be initialized correctly. It should be released
  87. * immediately.
  88. *****************************************************************************/
  89. HRESULT WiaEventReceiver::Start()
  90. {
  91. HRESULT hr = S_OK;
  92. if (m_csReceiverSync.IsInitialized())
  93. {
  94. TAKE_CRIT_SECT t(m_csReceiverSync);
  95. //
  96. // We put an exception handler around our code to ensure that the
  97. // crtitical section is exited properly.
  98. //
  99. _try
  100. {
  101. if (!m_bIsRunning)
  102. {
  103. if (m_pClientEventTransport)
  104. {
  105. hr = m_pClientEventTransport->Initialize();
  106. if (hr == S_OK)
  107. {
  108. hr = m_pClientEventTransport->OpenConnectionToServer();
  109. if (hr == S_OK)
  110. {
  111. hr = m_pClientEventTransport->OpenNotificationChannel();
  112. if (hr == S_OK)
  113. {
  114. //
  115. // Create our event thread with will wait for
  116. // notifications from the transport layer.
  117. //
  118. m_hEventThread = CreateThread(NULL,
  119. 0,
  120. WiaEventReceiver::EventThreadProc,
  121. this,
  122. 0,
  123. &m_dwEventThreadID);
  124. if (m_hEventThread)
  125. {
  126. DBG_TRC(("WiaEventReceiver Started..."));
  127. m_bIsRunning = TRUE;
  128. hr = S_OK;
  129. }
  130. else
  131. {
  132. hr = E_UNEXPECTED;
  133. }
  134. }
  135. else
  136. {
  137. hr = E_UNEXPECTED;
  138. }
  139. }
  140. else
  141. {
  142. hr = E_UNEXPECTED;
  143. }
  144. }
  145. else
  146. {
  147. DBG_ERR(("Runtime event Error: Could not initialize the transport for the WiaEventReceiver"));
  148. }
  149. }
  150. else
  151. {
  152. DBG_ERR(("Runtime event Error: The transport for the WiaEventReceiver is NULL"));
  153. hr = E_UNEXPECTED;
  154. }
  155. }
  156. else
  157. {
  158. hr = S_OK;
  159. }
  160. }
  161. _except(EXCEPTION_EXECUTE_HANDLER)
  162. {
  163. DBG_ERR(("Runtime event Error: We caught exception 0x%08X trying to sart receiving notifications", GetExceptionCode()));
  164. hr = E_UNEXPECTED;
  165. // TBD: Rethrow the exception?
  166. }
  167. }
  168. else
  169. {
  170. DBG_ERR(("Runtime event Error: The critical section for the WiaEventReceiver could not be initialized"));
  171. hr = E_UNEXPECTED;
  172. }
  173. if (FAILED(hr))
  174. {
  175. DBG_ERR(("Runtime event Error: Could not Start...calling Stop"));
  176. Stop();
  177. }
  178. return hr;
  179. }
  180. /*****************************************************************************
  181. * @doc INTERNAL
  182. *
  183. * @mfunc HRESULT | WiaEventReceiver | NotifyCallbacksOfEvent |
  184. *
  185. * Walks down the list of event registrations. For every event
  186. * registration that matches <p pWiaEventInfo>, we make the callback.
  187. * (See <mf EventRegistrationInfo::MatchesDeviceEvent> for information on what consitutes
  188. * a match). This is done synchronously.
  189. *
  190. * The callbacks are done in two steps:
  191. * <nl>1) Walk the list to find matching registrations. For each matching registration,
  192. * add it to a ListOfCallbacks (This is done holding the critical section)
  193. * <nl>2) Walk the ListOfCallbacks and make the callback (This is done without holding the critical
  194. * section to avoid deadlock)
  195. *
  196. * @parm WiaEventInfo* | pWiaEventInfo |
  197. * The actual event that occured.
  198. *
  199. * @rvalue S_OK |
  200. * The method succeeded.
  201. *****************************************************************************/
  202. HRESULT WiaEventReceiver::NotifyCallbacksOfEvent(
  203. WiaEventInfo *pWiaEventInfo)
  204. {
  205. CSimpleLinkedList<ClientEventRegistrationInfo*> ListOfCallbacksToNotify;
  206. HRESULT hr = S_OK;
  207. if (pWiaEventInfo)
  208. {
  209. TAKE_CRIT_SECT t(m_csReceiverSync);
  210. //
  211. // We put an exception handler around our code to ensure that the
  212. // crtitical section is exited properly.
  213. //
  214. _try
  215. {
  216. //
  217. // Walk the list and see if we can find it
  218. //
  219. ClientEventRegistrationInfo *pEventRegistrationInfo = NULL;
  220. CSimpleLinkedList<ClientEventRegistrationInfo*>::Iterator iter;
  221. for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter)
  222. {
  223. pEventRegistrationInfo = *iter;
  224. if (pEventRegistrationInfo)
  225. {
  226. //
  227. // Check whether a given registration matches the event. If it does, it means
  228. // we have to ad it to the list of callbacks to notify.
  229. //
  230. if (pEventRegistrationInfo->MatchesDeviceEvent(pWiaEventInfo->getDeviceID(),
  231. pWiaEventInfo->getEventGuid()))
  232. {
  233. //
  234. // AddRef the EventRegistrationInfo because we're keeping it in another list.
  235. // It will be released once the callback is made.
  236. //
  237. ListOfCallbacksToNotify.Append(pEventRegistrationInfo);
  238. pEventRegistrationInfo->AddRef();
  239. }
  240. }
  241. else
  242. {
  243. //
  244. // Log Error
  245. // pEventRegistrationInfo should never be NULL
  246. DBG_ERR(("Runtime event Error: While searching for a matching registration, we hit a NULL pEventRegistrationInfo!"));
  247. }
  248. }
  249. }
  250. _except(EXCEPTION_EXECUTE_HANDLER)
  251. {
  252. DBG_ERR(("Runtime event Error: We caught exception 0x%08X trying to notify callbacks of event", GetExceptionCode()));
  253. hr = E_UNEXPECTED;
  254. }
  255. }
  256. else
  257. {
  258. DBG_ERR(("Runtime event Error: Cannot process NULL event info"));
  259. hr = E_POINTER;
  260. }
  261. //
  262. // We now have a list of callbacks we need to notify of the event. We do this here
  263. // now that we are not holding the Critical Section (m_csReceiver) anymore.
  264. //
  265. if (SUCCEEDED(hr) && pWiaEventInfo)
  266. {
  267. //
  268. // Walk the ListOfCallbacksToNotify and make the callbacks
  269. //
  270. ClientEventRegistrationInfo *pEventRegistrationInfo = NULL;
  271. CSimpleLinkedList<ClientEventRegistrationInfo*>::Iterator iter;
  272. for (iter = ListOfCallbacksToNotify.Begin(); iter != ListOfCallbacksToNotify.End(); ++iter)
  273. {
  274. pEventRegistrationInfo = *iter;
  275. if (pEventRegistrationInfo)
  276. {
  277. //
  278. // Put an exception handler around the actual callback attempt
  279. //
  280. _try
  281. {
  282. GUID guidEvent = pWiaEventInfo->getEventGuid();
  283. ULONG ulEventType = pWiaEventInfo->getEventType();
  284. IWiaEventCallback *pIWiaEventCallback = pEventRegistrationInfo->getCallbackInterface();
  285. if (pIWiaEventCallback)
  286. {
  287. HRESULT hres = pIWiaEventCallback->ImageEventCallback(
  288. &guidEvent,
  289. pWiaEventInfo->getEventDescription(),
  290. pWiaEventInfo->getDeviceID(),
  291. pWiaEventInfo->getDeviceDescription(),
  292. pWiaEventInfo->getDeviceType(),
  293. pWiaEventInfo->getFullItemName(),
  294. &ulEventType,
  295. 0);
  296. pIWiaEventCallback->Release();
  297. }
  298. else
  299. {
  300. DBG_WRN(("Cannot notify a NULL IWiaEventCallback"));
  301. }
  302. }
  303. _finally
  304. {
  305. //
  306. // Always release the pEventRegistrationInfo since we AddRef'd it putting it in the list
  307. //
  308. pEventRegistrationInfo->Release();
  309. }
  310. }
  311. }
  312. }
  313. return hr;
  314. }
  315. /*****************************************************************************
  316. * @doc INTERNAL
  317. *
  318. * @mfunc HRESULT | WiaEventReceiver | SendRegisterUnregisterInfo |
  319. *
  320. * This method will add/remove the relevant event registration, then send
  321. * the info off to the WIA Service.
  322. *
  323. * To insert into our list, we grab the <md WiaEventReceiver::m_csReceiverSync>,
  324. * then create a new <c ClientEventRegistrationInfo> class (if this is a registration),
  325. * or we find the registration in the list and remove it (if this is an
  326. * unregister). The sync is released after this.
  327. *
  328. * Only once this is done, do we notify the service.
  329. *
  330. * This method will automatically ensure we are started by calling <mf WiaEventReceiver::Start>.
  331. * If at the end of this method, there are no registrations, it will call
  332. * <mf WiaEventReceiver::Stop>. (Because, if the client
  333. * is not registered for anything, we do not need our event thread or an active channel
  334. * to the server).
  335. *
  336. * @parm ClientEventRegistrationInfo* | pEventRegistrationInfo |
  337. * Pointer to a class containing the registration data to add/remove.
  338. *
  339. * @rvalue S_OK |
  340. * The method succeeded.
  341. * @rvalue E_XXXXXXX |
  342. * We could not send the register/unregister info.
  343. *****************************************************************************/
  344. HRESULT WiaEventReceiver::SendRegisterUnregisterInfo(
  345. ClientEventRegistrationInfo *pEventRegistrationInfo)
  346. {
  347. HRESULT hr = S_OK;
  348. if (pEventRegistrationInfo)
  349. {
  350. //
  351. // Ensure we have a channel open to the server and then send the registration info.
  352. //
  353. Start();
  354. hr = m_pClientEventTransport->SendRegisterUnregisterInfo(pEventRegistrationInfo);
  355. }
  356. else
  357. {
  358. hr = E_UNEXPECTED;
  359. }
  360. //
  361. // Ensure we take the sync for the rest of this function
  362. //
  363. if (SUCCEEDED(hr))
  364. {
  365. TAKE_CRIT_SECT t(m_csReceiverSync);
  366. //
  367. // We put an exception handler around our code to ensure that the
  368. // crtitical section is exited properly.
  369. //
  370. _try
  371. {
  372. //
  373. // Check whether this is registration or unregistration.
  374. // NOTE: Since unregistration is typically done via the RegistrationCookie,
  375. // our hueristic for this is that if it is not specifically an UnRegistration,
  376. // then it is considered a registration.
  377. //
  378. if (pEventRegistrationInfo->getFlags() & WIA_UNREGISTER_EVENT_CALLBACK)
  379. {
  380. ClientEventRegistrationInfo *pExistingReg = FindEqualEventRegistration(pEventRegistrationInfo);
  381. if (pExistingReg != NULL)
  382. {
  383. //
  384. // Release it and remove it from our list.
  385. //
  386. m_ListOfEventRegistrations.Remove(pExistingReg);
  387. pExistingReg->Release();
  388. DBG_TRC(("Removed registration:"));
  389. pExistingReg->Dump();
  390. }
  391. else
  392. {
  393. DBG_ERR(("Runtime event Error: Attempting to unregister when you have not first registered"));
  394. hr = E_INVALIDARG;
  395. }
  396. //
  397. // We need to release pExistingReg due to the AddRef from the lookup.
  398. //
  399. if (pExistingReg)
  400. {
  401. pExistingReg->Release();
  402. pExistingReg = NULL;
  403. }
  404. }
  405. else
  406. {
  407. //
  408. // Add it to our list. We AddRef it here since we're keeping a reference to it.
  409. //
  410. m_ListOfEventRegistrations.Prepend(pEventRegistrationInfo);
  411. pEventRegistrationInfo->AddRef();
  412. DBG_TRC(("Added new registration:"));
  413. pEventRegistrationInfo->Dump();
  414. }
  415. //
  416. // If no registrations exit in the list, then we should stop.
  417. // If we have at least one registration in the list, then we should start.
  418. //
  419. if (m_ListOfEventRegistrations.Empty())
  420. {
  421. Stop();
  422. }
  423. }
  424. _except(EXCEPTION_EXECUTE_HANDLER)
  425. {
  426. DBG_ERR(("Runtime event Error: We caught exception 0x%08X trying to register/unregister for event", GetExceptionCode()));
  427. hr = E_UNEXPECTED;
  428. }
  429. }
  430. //*/
  431. return hr;
  432. }
  433. /*****************************************************************************
  434. * @doc INTERNAL
  435. *
  436. * @mfunc VOID | WiaEventReceiver | Stop |
  437. *
  438. * Calls transport object to:
  439. * <nl>- Close our notification channel. See <mf ClientEventTransport::CloseNotificationChannel>
  440. * <nl>- Close our connection to the server. See <mf ClientEventTransport::CloseConnectionToServer>
  441. * <nl>- Close our event thread handle.
  442. * <nl>- Set <md WiaEventReceiver::m_bIsRunning> to FALSE.
  443. *
  444. *****************************************************************************/
  445. VOID WiaEventReceiver::Stop()
  446. {
  447. if (m_csReceiverSync.IsInitialized())
  448. {
  449. TAKE_CRIT_SECT t(m_csReceiverSync);
  450. //
  451. // We put an exception handler around our code to ensure that the
  452. // crtitical section is exited properly.
  453. //
  454. _try
  455. {
  456. if (m_bIsRunning)
  457. {
  458. DBG_TRC(("...WiaEventReceiver is Stopping..."));
  459. m_bIsRunning = FALSE;
  460. m_dwEventThreadID = 0;
  461. if (m_pClientEventTransport)
  462. {
  463. m_pClientEventTransport->CloseNotificationChannel();
  464. m_pClientEventTransport->CloseConnectionToServer();
  465. }
  466. if (m_hEventThread)
  467. {
  468. CloseHandle(m_hEventThread);
  469. m_hEventThread = NULL;
  470. }
  471. }
  472. }
  473. _except(EXCEPTION_EXECUTE_HANDLER)
  474. {
  475. DBG_ERR(("Runtime event Error: We caught exception 0x%08X trying to Stop", GetExceptionCode()));
  476. }
  477. }
  478. }
  479. /*****************************************************************************
  480. * @doc INTERNAL
  481. *
  482. * @mfunc VOID | WiaEventReceiver | DestroyRegistrationList |
  483. *
  484. * Removes any remaining event registration objects and destroys the list.
  485. *
  486. *****************************************************************************/
  487. VOID WiaEventReceiver::DestroyRegistrationList()
  488. {
  489. TAKE_CRIT_SECT t(m_csReceiverSync);
  490. //
  491. // We put an exception handler around our code to ensure that the
  492. // crtitical section is exited properly.
  493. //
  494. _try
  495. {
  496. //
  497. // Walk the list of registrations release all elements. Then destroy the list.
  498. //
  499. ClientEventRegistrationInfo *pElem = NULL;
  500. CSimpleLinkedList<ClientEventRegistrationInfo*>::Iterator iter;
  501. for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter)
  502. {
  503. pElem = *iter;
  504. if (pElem)
  505. {
  506. pElem->Release();
  507. }
  508. }
  509. m_ListOfEventRegistrations.Destroy();
  510. }
  511. _except(EXCEPTION_EXECUTE_HANDLER)
  512. {
  513. DBG_ERR(("Runtime event Error: We caught exception 0x%08X trying to destroy the registration list", GetExceptionCode()));
  514. }
  515. }
  516. /*****************************************************************************
  517. * @doc INTERNAL
  518. *
  519. * @mfunc ClientEventRegistrationInfo* | WiaEventReceiver | FindEqualEventRegistration |
  520. *
  521. * Checks whether a semantically equal <c ClientEventRegistrationInfo> is in the list.
  522. * If it is, we retrieve it. Note that caller must Release it.
  523. *
  524. * @parm ClientEventRegistrationInfo | pEventRegistrationInfo |
  525. * Specifies a <c ClientEventRegistrationInfo> we're looking for in our list.
  526. *
  527. * @rvalue NULL |
  528. * We could not find it.
  529. * @rvalue non-NULL |
  530. * The equivalent <c ClientEventRegistrationInfo> exists. Caller must Release.
  531. *****************************************************************************/
  532. ClientEventRegistrationInfo* WiaEventReceiver::FindEqualEventRegistration(
  533. ClientEventRegistrationInfo *pEventRegistrationInfo)
  534. {
  535. ClientEventRegistrationInfo *pRet = NULL;
  536. if (pEventRegistrationInfo)
  537. {
  538. TAKE_CRIT_SECT t(m_csReceiverSync);
  539. //
  540. // We put an exception handler around our code to ensure that the
  541. // crtitical section is exited properly.
  542. //
  543. _try
  544. {
  545. //
  546. // Walk the list and see if we can find it
  547. //
  548. ClientEventRegistrationInfo *pElem = NULL;
  549. CSimpleLinkedList<ClientEventRegistrationInfo*>::Iterator iter;
  550. for (iter = m_ListOfEventRegistrations.Begin(); iter != m_ListOfEventRegistrations.End(); ++iter)
  551. {
  552. pElem = *iter;
  553. if (pElem)
  554. {
  555. if (pElem->Equals(pEventRegistrationInfo))
  556. {
  557. //
  558. // We found it, so AddRef it and set the return
  559. //
  560. pElem->AddRef();
  561. pRet = pElem;
  562. break;
  563. }
  564. }
  565. else
  566. {
  567. //
  568. // Log Error
  569. // pEventRegistrationInfo should never be NULL
  570. DBG_ERR(("Runtime event Error: While searching for an equal registration, we hit a NULL pEventRegistrationInfo!"));
  571. }
  572. }
  573. }
  574. _except(EXCEPTION_EXECUTE_HANDLER)
  575. {
  576. DBG_ERR(("Runtime event Error: The WiaEventReceiver caught an exception (0x%08X) trying to find an equal event registration", GetExceptionCode()));
  577. }
  578. }
  579. return pRet;
  580. }
  581. /*****************************************************************************
  582. * @doc INTERNAL
  583. *
  584. * @mfunc DWORD WINAPI | WiaEventReceiver | EventThreadProc |
  585. *
  586. * This method waits on the handle returned by <mf ClientEventTransport::getNotificationHandle>.
  587. * When this event is signalled, it means we either have a notification, or we are
  588. * being asked to exit.
  589. *
  590. * Before processing the event, we check whether we are being asked to exit by
  591. * checking the <md WiaEventReceiver::m_dwEventThreadID> member. If it is not
  592. * equal to our thread ID, then we must exit this thread.
  593. *
  594. * @parm LPVOID | lpParameter |
  595. * This is actually a pointer to the instance of <c WiaEventReceiver>.
  596. *
  597. * @rvalue S_OK |
  598. * The method succeeded.
  599. *****************************************************************************/
  600. DWORD WINAPI WiaEventReceiver::EventThreadProc(
  601. LPVOID lpParameter)
  602. {
  603. WiaEventReceiver *pThis = (WiaEventReceiver*)lpParameter;
  604. BOOL bRunning = TRUE;
  605. if (pThis)
  606. {
  607. //
  608. // Call CoInitializeEx here. We prefer multithreaded but we will
  609. // work with any aprtment model.
  610. //
  611. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  612. if (pThis->m_pClientEventTransport)
  613. {
  614. HANDLE hEvent = pThis->m_pClientEventTransport->getNotificationHandle();
  615. RPC_STATUS rpcStatus = RPC_S_OK;
  616. while (bRunning)
  617. {
  618. DWORD dwWait = WaitForSingleObject(hEvent, INFINITE);
  619. if (dwWait == WAIT_OBJECT_0)
  620. {
  621. //
  622. // Check whether we are still supposed to be running.
  623. // We are supposed to be running if our thread id matches the
  624. // one in the event receiver. If not, then we must exit.
  625. //
  626. if (pThis->m_dwEventThreadID == GetCurrentThreadId())
  627. {
  628. DBG_TRC(("...We got the event. Retriving data"));
  629. WiaEventInfo wEventInfo;
  630. rpcStatus = pThis->m_pClientEventTransport->FillEventData(&wEventInfo);
  631. if (rpcStatus == RPC_S_OK)
  632. {
  633. HRESULT hrRes = pThis->NotifyCallbacksOfEvent(&wEventInfo);
  634. }
  635. else
  636. {
  637. DBG_WRN(("We got an error 0x%08X trying to fill the event data.", rpcStatus));
  638. //
  639. // TBD: Should we reset our connection to the server?
  640. // Let's try to reconnect... If that fails, then just stop.
  641. //
  642. DBG_WRN(("Resetting connection to server"));
  643. pThis->Stop();
  644. rpcStatus = pThis->Start();
  645. if (rpcStatus != RPC_S_OK)
  646. {
  647. DBG_WRN(("Resetting connection to server failed with 0x%08X, closing our connection", rpcStatus));
  648. pThis->Stop();
  649. }
  650. break;
  651. }
  652. }
  653. else
  654. {
  655. DBG_TRC(("!Received notification to Shutdown event thread!"));
  656. bRunning = FALSE;
  657. }
  658. }
  659. }
  660. }
  661. else
  662. {
  663. DBG_ERR(("Cannot work with a NULL event transport"));
  664. }
  665. }
  666. else
  667. {
  668. DBG_ERR(("Cannot work with a NULL WiaEventReceiver"));
  669. }
  670. CoUninitialize();
  671. DBG_TRC(("\nEvent Thread 0x%08X is now shutdown\n", GetCurrentThreadId()));
  672. return 0;
  673. }