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.

788 lines
22 KiB

  1. //
  2. // MODULE: DirMonitor.cpp
  3. //
  4. // PURPOSE: Monitor changes to LST, DSC, HTI, BES files.
  5. //
  6. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  7. //
  8. // AUTHOR: Joe Mabel
  9. //
  10. // ORIGINAL DATE: 9-17-98
  11. //
  12. // NOTES:
  13. //
  14. // Version Date By Comments
  15. //--------------------------------------------------------------------
  16. // V3.0 09-17-98 JM
  17. //
  18. #pragma warning(disable:4786)
  19. #include "stdafx.h"
  20. #include <algorithm>
  21. #include "DirMonitor.h"
  22. #include "event.h"
  23. #include "apiwraps.h"
  24. #include "CharConv.h"
  25. #ifdef LOCAL_TROUBLESHOOTER
  26. #include "LocalLSTReader.h"
  27. #include "CHMFileReader.h"
  28. #endif
  29. #include "apgts.h" // Need for Local-Online macros.
  30. const DWORD k_secsDefaultReloadDelay = 40; // In practice, this default should not matter,
  31. // because SetReloadDelay() should be called before
  32. // SetResourceDirectory(). However, 40 is a typical
  33. // reasonable value for m_secsReloadDelay.
  34. /////////////////////////////////////////////////////////////////////
  35. // CTopicFileTracker
  36. /////////////////////////////////////////////////////////////////////
  37. CTopicFileTracker::CTopicFileTracker() :
  38. CFileTracker()
  39. {
  40. }
  41. CTopicFileTracker::~CTopicFileTracker()
  42. {
  43. }
  44. void CTopicFileTracker::AddTopicInfo(const CTopicInfo & topicinfo)
  45. {
  46. m_topicinfo = topicinfo;
  47. // set CFileTracker member variables accordingly for files that are present.
  48. // If they are not present i.e. empty strings then adding them here results in
  49. // unnecessary event log entries.
  50. AddFile(topicinfo.GetDscFilePath());
  51. CString strHTI = topicinfo.GetHtiFilePath();
  52. if (!strHTI.IsEmpty())
  53. AddFile(strHTI);
  54. CString strBES = topicinfo.GetBesFilePath();
  55. if (!strBES.IsEmpty())
  56. AddFile(strBES);
  57. }
  58. const CTopicInfo & CTopicFileTracker::GetTopicInfo() const
  59. {
  60. return m_topicinfo;
  61. }
  62. /////////////////////////////////////////////////////////////////////
  63. // CTemplateFileTracker
  64. /////////////////////////////////////////////////////////////////////
  65. CTemplateFileTracker::CTemplateFileTracker() :
  66. CFileTracker()
  67. {
  68. }
  69. CTemplateFileTracker::~CTemplateFileTracker()
  70. {
  71. }
  72. void CTemplateFileTracker::AddTemplateName( const CString& strTemplateName )
  73. {
  74. m_strTemplateName= strTemplateName;
  75. AddFile( strTemplateName );
  76. }
  77. const CString& CTemplateFileTracker::GetTemplateName() const
  78. {
  79. return m_strTemplateName;
  80. }
  81. //////////////////////////////////////////////////////////////////////
  82. // CDirectoryMonitor::ThreadStatus
  83. //////////////////////////////////////////////////////////////////////
  84. /* static */ CString CDirectoryMonitor::ThreadStatusText(ThreadStatus ts)
  85. {
  86. switch(ts)
  87. {
  88. case eBeforeInit: return _T("Before Init");
  89. case eFail: return _T("Fail");
  90. case eWaitDirPath: return _T("Wait For Dir Path");
  91. case eWaitChange: return _T("Wait for Change");
  92. case eWaitSettle: return _T("Wait to Settle");
  93. case eRun: return _T("Run");
  94. case eBeforeWaitChange: return _T("Before Wait Change");
  95. case eExiting: return _T("Exiting");
  96. default: return _T("");
  97. }
  98. }
  99. /////////////////////////////////////////////////////////////////////
  100. // CDirectoryMonitor
  101. // This class does the bulk of its work on a separate thread.
  102. // The thread is created in the constructor by starting static function
  103. // CDirectoryMonitor::DirectoryMonitorTask
  104. // That function, in turn does its work by calling private members of this class that
  105. // are specific to use on the DirectoryMonitorTask thread.
  106. // When this goes out of scope, its own destructor calls ShutDown to stop the thread,
  107. // waits for the thread to shut.
  108. // The following methods are available for other threads communicating with that thread:
  109. // CDirectoryMonitor::SetReloadDelay
  110. // CDirectoryMonitor::SetResourceDirectory
  111. /////////////////////////////////////////////////////////////////////
  112. CDirectoryMonitor::CDirectoryMonitor(CTopicShop & TopicShop, const CString& strTopicName) :
  113. m_strTopicName(strTopicName),
  114. m_TopicShop(TopicShop),
  115. m_pErrorTemplate(NULL),
  116. m_strDirPath(_T("")), // Essential that this starts blank. Getting a different
  117. // value is how we start the DirectoryMonitorTask thread.
  118. m_bDirPathChanged(false),
  119. m_bShuttingDown(false),
  120. m_secsReloadDelay(k_secsDefaultReloadDelay),
  121. m_pTrackLst( NULL ),
  122. m_pTrackErrorTemplate( NULL ),
  123. m_pLst( NULL ),
  124. m_dwErr(0),
  125. m_ThreadStatus(eBeforeInit),
  126. m_time(0)
  127. {
  128. enum {eHevMon, eHevShut, eThread, eOK} Progress = eHevMon;
  129. SetThreadStatus(eBeforeInit);
  130. m_hevMonitorRequested = ::CreateEvent(
  131. NULL,
  132. FALSE, // release one thread (the DirectoryMonitorTask) on signal
  133. FALSE, // initially non-signalled
  134. NULL);
  135. if (m_hevMonitorRequested)
  136. {
  137. Progress = eHevShut;
  138. m_hevThreadIsShut = ::CreateEvent(
  139. NULL,
  140. FALSE, // release one thread (this one) on signal
  141. FALSE, // initially non-signalled
  142. NULL);
  143. if (m_hevThreadIsShut)
  144. {
  145. Progress = eThread;
  146. DWORD dwThreadID; // No need to hold onto dwThreadID in member variable.
  147. // All Win32 functions take the handle m_hThread instead.
  148. // The one reason you'd ever want to know this ID is for
  149. // debugging
  150. // Note that there is no corresponding ::CloseHandle(m_hThread).
  151. // That is because the thread goes out of existence on the implicit
  152. // ::ExitThread() when DirectoryMonitorTask returns. See documentation of
  153. // ::CreateThread for further details JM 10/22/98
  154. m_hThread = ::CreateThread( NULL,
  155. 0,
  156. (LPTHREAD_START_ROUTINE)DirectoryMonitorTask,
  157. this,
  158. 0,
  159. &dwThreadID);
  160. if (m_hThread)
  161. Progress = eOK;
  162. }
  163. }
  164. if (Progress != eOK)
  165. {
  166. m_dwErr = GetLastError();
  167. CString str;
  168. str.Format(_T("%d"), m_dwErr);
  169. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  170. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  171. SrcLoc.GetSrcFileLineStr(),
  172. (Progress == eHevMon) ? _T("Can't create monitor event")
  173. : (Progress == eHevShut) ? _T("Can't create \"shut\" event")
  174. : _T("Can't create thread"),
  175. str,
  176. EV_GTS_ERROR_DIRMONITORTHREAD );
  177. SetThreadStatus(eFail);
  178. if (m_hevMonitorRequested)
  179. ::CloseHandle(m_hevMonitorRequested);
  180. if (m_hevThreadIsShut)
  181. ::CloseHandle(m_hevThreadIsShut);
  182. }
  183. }
  184. CDirectoryMonitor::~CDirectoryMonitor()
  185. {
  186. ShutDown();
  187. if (m_hevMonitorRequested)
  188. ::CloseHandle(m_hevMonitorRequested);
  189. if (m_hevThreadIsShut)
  190. ::CloseHandle(m_hevThreadIsShut);
  191. if (m_pErrorTemplate)
  192. delete m_pErrorTemplate;
  193. if (m_pTrackLst)
  194. delete m_pTrackLst;
  195. if (m_pTrackErrorTemplate)
  196. delete m_pTrackErrorTemplate;
  197. }
  198. void CDirectoryMonitor::SetThreadStatus(ThreadStatus ts)
  199. {
  200. LOCKOBJECT();
  201. m_ThreadStatus = ts;
  202. time(&m_time);
  203. UNLOCKOBJECT();
  204. }
  205. DWORD CDirectoryMonitor::GetStatus(ThreadStatus &ts, DWORD & seconds) const
  206. {
  207. time_t timeNow;
  208. LOCKOBJECT();
  209. ts = m_ThreadStatus;
  210. time(&timeNow);
  211. seconds = timeNow - m_time;
  212. UNLOCKOBJECT();
  213. return m_dwErr;
  214. }
  215. // Only for use by this class's own destructor.
  216. void CDirectoryMonitor::ShutDown()
  217. {
  218. LOCKOBJECT();
  219. m_bShuttingDown = true;
  220. if (m_hThread)
  221. {
  222. ::SetEvent(m_hevMonitorRequested);
  223. UNLOCKOBJECT();
  224. // Wait for a set period, if failure then log error msg and wait infinite.
  225. WAIT_INFINITE( m_hevThreadIsShut );
  226. }
  227. else
  228. UNLOCKOBJECT();
  229. }
  230. // For use by the DirectoryMonitorTask thread.
  231. // Read LST file and add any topics that are not already in previously read LST file contents
  232. void CDirectoryMonitor::LstFileDrivesTopics()
  233. {
  234. // previous LST file contents, saved for comparison.
  235. CAPGTSLSTReader *pLstOld = m_pLst;
  236. if (! m_strLstPath.IsEmpty() )
  237. {
  238. try
  239. {
  240. #ifdef LOCAL_TROUBLESHOOTER
  241. m_pLst = new CLocalLSTReader( CPhysicalFileReader::makeReader( m_strLstPath ), m_strTopicName);
  242. #else
  243. m_pLst = new CAPGTSLSTReader( dynamic_cast<CPhysicalFileReader*>(new CNormalFileReader(m_strLstPath)) );
  244. #endif
  245. }
  246. catch (bad_alloc&)
  247. {
  248. // Restore old LST contents.
  249. m_pLst = pLstOld;
  250. // Rethrow exception, logging handled upstream.
  251. throw;
  252. }
  253. if (! m_pLst->Read())
  254. {
  255. // Restore old LST contents and log error.
  256. delete m_pLst;
  257. m_pLst = pLstOld;
  258. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  259. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  260. SrcLoc.GetSrcFileLineStr(),
  261. _T(""),
  262. _T(""),
  263. EV_GTS_ERROR_LST_FILE_READ );
  264. }
  265. else
  266. {
  267. CTopicInfoVector arrNewTopicInfo;
  268. m_pLst->GetDifference(pLstOld, arrNewTopicInfo);
  269. if (pLstOld)
  270. delete pLstOld;
  271. for (CTopicInfoVector::iterator itNewTopicInfo = arrNewTopicInfo.begin();
  272. itNewTopicInfo != arrNewTopicInfo.end();
  273. itNewTopicInfo++
  274. )
  275. {
  276. // Let the Topic Shop know about the new topic
  277. m_TopicShop.AddTopic(*itNewTopicInfo);
  278. // add it to our list of files to track for changes
  279. CTopicFileTracker TopicFileTracker;
  280. TopicFileTracker.AddTopicInfo(*itNewTopicInfo);
  281. LOCKOBJECT();
  282. try
  283. {
  284. m_arrTrackTopic.push_back(TopicFileTracker);
  285. }
  286. catch (exception& x)
  287. {
  288. CString str;
  289. // Note STL exception in event log.
  290. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  291. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  292. SrcLoc.GetSrcFileLineStr(),
  293. CCharConversion::ConvertACharToString(x.what(), str),
  294. _T(""),
  295. EV_GTS_STL_EXCEPTION );
  296. }
  297. UNLOCKOBJECT();
  298. }
  299. }
  300. }
  301. // if topic shop not already open, open it
  302. m_TopicShop.OpenShop();
  303. }
  304. // Called by the topic shop to add alternate templates to track.
  305. void CDirectoryMonitor::AddTemplateToTrack( const CString& strTemplateName )
  306. {
  307. LOCKOBJECT();
  308. try
  309. {
  310. CTemplateFileTracker TemplateFileTracker;
  311. TemplateFileTracker.AddTemplateName( strTemplateName );
  312. m_arrTrackTemplate.push_back( TemplateFileTracker );
  313. }
  314. catch (exception& x)
  315. {
  316. CString str;
  317. // Note STL exception in event log.
  318. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  319. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  320. SrcLoc.GetSrcFileLineStr(),
  321. CCharConversion::ConvertACharToString(x.what(), str),
  322. _T(""),
  323. EV_GTS_STL_EXCEPTION );
  324. }
  325. UNLOCKOBJECT();
  326. }
  327. // For use by the DirectoryMonitorTask thread.
  328. void CDirectoryMonitor::ReadErrorTemplate()
  329. {
  330. LOCKOBJECT();
  331. if (m_pErrorTemplate)
  332. delete m_pErrorTemplate;
  333. CString str = k_strDefaultErrorTemplateBefore;
  334. str += k_strErrorTemplateKey;
  335. str += k_strDefaultErrorTemplateAfter;
  336. try
  337. {
  338. m_pErrorTemplate = new CSimpleTemplate( CPhysicalFileReader::makeReader( m_strErrorTemplatePath ), str );
  339. }
  340. catch (bad_alloc&)
  341. {
  342. UNLOCKOBJECT();
  343. // Rethrow the exception.
  344. throw;
  345. }
  346. m_pErrorTemplate->Read();
  347. UNLOCKOBJECT();
  348. }
  349. // For use by any thread. In this class because CDirectoryMonitor needs to own
  350. // ErrorTemplate, since it can change during run of system.
  351. void CDirectoryMonitor::CreateErrorPage(const CString & strError, CString& out) const
  352. {
  353. LOCKOBJECT();
  354. if (m_pErrorTemplate)
  355. {
  356. vector<CTemplateInfo> arrTemplateInfo;
  357. CTemplateInfo info(k_strErrorTemplateKey, strError);
  358. try
  359. {
  360. arrTemplateInfo.push_back(info);
  361. m_pErrorTemplate->CreatePage( arrTemplateInfo, out );
  362. }
  363. catch (exception& x)
  364. {
  365. CString str;
  366. // Note STL exception in event log.
  367. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  368. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  369. SrcLoc.GetSrcFileLineStr(),
  370. CCharConversion::ConvertACharToString(x.what(), str),
  371. _T(""),
  372. EV_GTS_STL_EXCEPTION );
  373. // Generate the default error page to be safe.
  374. out = k_strDefaultErrorTemplateBefore + strError + k_strDefaultErrorTemplateAfter;
  375. }
  376. }
  377. else
  378. out = k_strDefaultErrorTemplateBefore + strError + k_strDefaultErrorTemplateAfter;
  379. UNLOCKOBJECT();
  380. }
  381. // Must be called on DirectoryMonitorTask thread.
  382. // Handles all work of monitoring the directory. Loops till shutdown.
  383. void CDirectoryMonitor::Monitor()
  384. {
  385. enum {
  386. #ifndef LOCAL_TROUBLESHOOTER
  387. eDirChange, // file in directory changed
  388. #endif
  389. eHev, // shutdown or change what directory
  390. eNumHandles };
  391. // array of handles we use when waiting for multiple events.
  392. // Initialize first entry to default bad value.
  393. HANDLE hList[eNumHandles]= { INVALID_HANDLE_VALUE };
  394. if (m_strDirPath.GetLength() == 0)
  395. {
  396. SetThreadStatus(eWaitDirPath);
  397. // Block this thread until notification that the directory path has been set.
  398. ::WaitForSingleObject( m_hevMonitorRequested, INFINITE);
  399. }
  400. SetThreadStatus(eRun);
  401. try
  402. {
  403. if (RUNNING_ONLINE_TS())
  404. {
  405. // The DirPathChanged flag should be set here, enforce it if not.
  406. ASSERT( m_bDirPathChanged );
  407. if (!m_bDirPathChanged)
  408. m_bDirPathChanged= true;
  409. }
  410. // Wait for an explicit wakeup.
  411. hList[eHev] = m_hevMonitorRequested;
  412. while (true)
  413. {
  414. LOCKOBJECT();
  415. if (m_bShuttingDown)
  416. {
  417. UNLOCKOBJECT();
  418. break;
  419. }
  420. if (m_bDirPathChanged)
  421. {
  422. #ifndef LOCAL_TROUBLESHOOTER
  423. // Set the directory to be monitored.
  424. if (hList[eDirChange] != INVALID_HANDLE_VALUE)
  425. ::FindCloseChangeNotification( hList[eDirChange] );
  426. while (true)
  427. {
  428. // handle to monitor for change in the resource directory
  429. hList[eDirChange] = ::FindFirstChangeNotification(m_strDirPath,
  430. TRUE, // monitor subdirectories (for multilingual)
  431. FILE_NOTIFY_CHANGE_LAST_WRITE
  432. );
  433. if (hList[eDirChange] == INVALID_HANDLE_VALUE)
  434. {
  435. // resource directoty does not exist.
  436. // Track creation of directories in upper directory
  437. // - it might be resource directory
  438. bool bFail = false;
  439. CString strUpperDir = m_strDirPath; // directory above resource directory (m_strDirPath)
  440. if ( strUpperDir[strUpperDir.GetLength()-1] == _T('\\')
  441. || strUpperDir[strUpperDir.GetLength()-1] == _T('/'))
  442. {
  443. strUpperDir = strUpperDir.Left(strUpperDir.GetLength() ? strUpperDir.GetLength()-1 : 0);
  444. }
  445. int slash_last = max(strUpperDir.ReverseFind(_T('\\')),
  446. strUpperDir.ReverseFind(_T('/')));
  447. if (-1 != slash_last)
  448. {
  449. strUpperDir = strUpperDir.Left(slash_last);
  450. hList[eDirChange] = ::FindFirstChangeNotification(strUpperDir,
  451. TRUE, // monitor subdirectories (for multilingual)
  452. FILE_NOTIFY_CHANGE_DIR_NAME
  453. );
  454. if (hList[eDirChange] == INVALID_HANDLE_VALUE)
  455. bFail = true;
  456. }
  457. else
  458. bFail = true;
  459. if (!bFail)
  460. {
  461. // We have a valid handle, exit this loop.
  462. SetThreadStatus(eRun);
  463. break;
  464. }
  465. else
  466. {
  467. // typically would mean none of resource directory or its upper
  468. // directory is valid, log this.
  469. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  470. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  471. SrcLoc.GetSrcFileLineStr(),
  472. m_strDirPath, _T(""),
  473. EV_GTS_ERROR_CANT_FILE_NOTIFY );
  474. SetThreadStatus(eWaitDirPath);
  475. // Block this thread until notification that the directory path
  476. // has been correctly set. Unlock the object so that the event
  477. // can be set.
  478. UNLOCKOBJECT();
  479. ::WaitForSingleObject( m_hevMonitorRequested, INFINITE);
  480. LOCKOBJECT();
  481. }
  482. }
  483. else
  484. {
  485. // We have a valid handle, exit this loop.
  486. SetThreadStatus(eRun);
  487. break;
  488. }
  489. }
  490. #endif
  491. m_bDirPathChanged = false;
  492. if (m_pTrackLst)
  493. delete m_pTrackLst;
  494. m_pTrackLst = new CFileTracker;
  495. if (RUNNING_ONLINE_TS())
  496. m_pTrackLst->AddFile(m_strLstPath);
  497. if (m_pTrackErrorTemplate)
  498. delete m_pTrackErrorTemplate;
  499. m_pTrackErrorTemplate = new CFileTracker;
  500. if (RUNNING_ONLINE_TS())
  501. m_pTrackErrorTemplate->AddFile(m_strErrorTemplatePath);
  502. UNLOCKOBJECT();
  503. ReadErrorTemplate();
  504. LstFileDrivesTopics();
  505. }
  506. else
  507. {
  508. UNLOCKOBJECT();
  509. if (m_pTrackLst && m_pTrackLst->Changed())
  510. LstFileDrivesTopics();
  511. if (m_pTrackErrorTemplate && m_pTrackErrorTemplate->Changed( false ))
  512. ReadErrorTemplate();
  513. }
  514. LOCKOBJECT();
  515. for (vector<CTopicFileTracker>::iterator itTopicFiles = m_arrTrackTopic.begin();
  516. itTopicFiles != m_arrTrackTopic.end();
  517. itTopicFiles ++
  518. )
  519. {
  520. #ifdef LOCAL_TROUBLESHOOTER
  521. if (m_bDirPathChanged)
  522. #else
  523. if (itTopicFiles->Changed())
  524. #endif
  525. m_TopicShop.BuildTopic(itTopicFiles->GetTopicInfo().GetNetworkName());
  526. if (m_bShuttingDown)
  527. break;
  528. }
  529. if (RUNNING_ONLINE_TS())
  530. {
  531. // Check if any of the alternate template files need to be reloaded.
  532. for (vector<CTemplateFileTracker>::iterator itTemplateFiles = m_arrTrackTemplate.begin();
  533. itTemplateFiles != m_arrTrackTemplate.end();
  534. itTemplateFiles ++
  535. )
  536. {
  537. if (itTemplateFiles->Changed())
  538. m_TopicShop.BuildTemplate( itTemplateFiles->GetTemplateName() );
  539. if (m_bShuttingDown)
  540. break;
  541. }
  542. }
  543. ::ResetEvent(m_hevMonitorRequested);
  544. SetThreadStatus(eWaitChange);
  545. UNLOCKOBJECT();
  546. DWORD dwNotifyObj = WaitForMultipleObjects (
  547. eNumHandles,
  548. hList,
  549. FALSE, // only need one object, not all
  550. INFINITE);
  551. SetThreadStatus(eBeforeWaitChange);
  552. // Ideally we would update files here.
  553. // Unfortunately, we get a notification that someone has _started_
  554. // writing to a file, not that they've finished, so we have to put in
  555. // an artificial delay.
  556. // We must let the system "settle down".
  557. while (
  558. #ifndef LOCAL_TROUBLESHOOTER
  559. dwNotifyObj == WAIT_OBJECT_0+eDirChange &&
  560. #endif
  561. !m_bShuttingDown)
  562. {
  563. #ifndef LOCAL_TROUBLESHOOTER
  564. // wait for the next change
  565. if (FindNextChangeNotification( hList[eDirChange] ) == FALSE)
  566. {
  567. // 1) we don't believe this will ever occur
  568. // 2) After a moderate amount of research, we have no idea how
  569. // to recover from it if it does occur.
  570. // SO: unless we ever actually see this, we're not going to waste
  571. // more time researching a recovery strategy. Just throw an exception,
  572. // effectively terminating this thread.
  573. throw CGenSysException( __FILE__, __LINE__, m_strDirPath,
  574. EV_GTS_ERROR_WAIT_NEXT_NFT );
  575. }
  576. #endif
  577. SetThreadStatus(eWaitSettle);
  578. dwNotifyObj = WaitForMultipleObjects (
  579. eNumHandles,
  580. hList,
  581. FALSE, // only need one object, not all
  582. m_secsReloadDelay * 1000); // convert to milliseconds
  583. }
  584. if (dwNotifyObj == WAIT_FAILED)
  585. {
  586. // 1) we don't believe this will ever occur
  587. // 2) After a moderate amount of research, we have no idea how
  588. // to recover from it if it does occur.
  589. // SO: unless we ever actually see this, we're not going to waste
  590. // more time researching a recovery strategy. Just throw an exception,
  591. // effectively terminating this thread.
  592. throw CGenSysException( __FILE__, __LINE__, _T("Unexpected Return State"),
  593. EV_GTS_DEBUG );
  594. }
  595. SetThreadStatus(eRun);
  596. }
  597. }
  598. catch (CGenSysException& x)
  599. {
  600. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  601. CEvent::ReportWFEvent( x.GetSrcFileLineStr(),
  602. SrcLoc.GetSrcFileLineStr(),
  603. x.GetErrorMsg(), x.GetSystemErrStr(),
  604. x.GetErrorCode() );
  605. }
  606. catch (CGeneralException& x)
  607. {
  608. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  609. CEvent::ReportWFEvent( x.GetSrcFileLineStr(),
  610. SrcLoc.GetSrcFileLineStr(),
  611. x.GetErrorMsg(), _T("General exception"),
  612. x.GetErrorCode() );
  613. }
  614. catch (bad_alloc&)
  615. {
  616. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  617. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  618. SrcLoc.GetSrcFileLineStr(),
  619. _T(""), _T(""), EV_GTS_CANT_ALLOC );
  620. }
  621. catch (exception& x)
  622. {
  623. // Catch any STL exceptions thrown so that Terminate() is not called.
  624. CString str;
  625. CString ErrStr;
  626. // Attempt to pull any system error code.
  627. ErrStr.Format( _T("%ld"), ::GetLastError() );
  628. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  629. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  630. SrcLoc.GetSrcFileLineStr(),
  631. CCharConversion::ConvertACharToString(x.what(), str),
  632. ErrStr,
  633. EV_GTS_GENERIC_PROBLEM );
  634. }
  635. catch (...)
  636. {
  637. // Catch any other exception thrown.
  638. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  639. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  640. SrcLoc.GetSrcFileLineStr(),
  641. _T(""), _T(""),
  642. EV_GTS_GEN_EXCEPTION );
  643. }
  644. #ifndef LOCAL_TROUBLESHOOTER
  645. if (hList[eDirChange] != INVALID_HANDLE_VALUE)
  646. ::FindCloseChangeNotification( hList[eDirChange] );
  647. #endif
  648. SetThreadStatus(eExiting);
  649. }
  650. // For general use (not part of DirectoryMonitorTask thread)
  651. // Typically, first call to this comes _before_ first call to SetResourceDirectory;
  652. // This allows caller to set reload delay before triggering any action on
  653. // DirectoryMonitorTask thread.
  654. void CDirectoryMonitor::SetReloadDelay(DWORD secsReloadDelay)
  655. {
  656. LOCKOBJECT();
  657. m_secsReloadDelay = secsReloadDelay;
  658. UNLOCKOBJECT();
  659. }
  660. // For general use (not part of DirectoryMonitorTask thread)
  661. // Allows indicating that the resource directory has changed
  662. // Until this is called, the DirectoryMonitorTask thread really won't do anything
  663. void CDirectoryMonitor::SetResourceDirectory(const CString & strDirPath)
  664. {
  665. LOCKOBJECT();
  666. if (strDirPath != m_strDirPath)
  667. {
  668. m_strDirPath = strDirPath;
  669. m_strLstPath = strDirPath + LSTFILENAME;
  670. m_strErrorTemplatePath = strDirPath + k_strErrorTemplateFileName;
  671. m_bDirPathChanged = true;
  672. ::SetEvent(m_hevMonitorRequested);
  673. }
  674. UNLOCKOBJECT();
  675. }
  676. // Must be called on DirectoryMonitorTask thread.
  677. void CDirectoryMonitor::AckShutDown()
  678. {
  679. LOCKOBJECT();
  680. ::SetEvent(m_hevThreadIsShut);
  681. UNLOCKOBJECT();
  682. }
  683. // Main routine of a thread responsible for monitoring the directory.
  684. // INPUT lpParams
  685. // Always returns 0.
  686. /* static */ UINT WINAPI CDirectoryMonitor::DirectoryMonitorTask(LPVOID lpParams)
  687. {
  688. reinterpret_cast<CDirectoryMonitor*>(lpParams)->Monitor();
  689. reinterpret_cast<CDirectoryMonitor*>(lpParams)->AckShutDown();
  690. return 0;
  691. }