// // The MIT License // // Copyright (c) 2010 James E Beveridge // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW" // http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html // See ReadMe.txt for overview information. #pragma once #include "ThreadSafeQueue.h" typedef pair TDirectoryChangeNotification; namespace ReadDirectoryChangesPrivate { class CReadChangesServer; } /////////////////////////////////////////////////////////////////////////// /// /// Track changes to filesystem directories and report them /// to the caller via a thread-safe queue. /// /// /// /// This sample code is based on my blog entry titled, "Understanding ReadDirectoryChangesW" /// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html /// /// All functions in CReadDirectoryChangesServer run in /// the context of the calling thread. /// /// /// CReadDirectoryChanges changes; /// changes.AddDirectory(_T("C:\\"), false, dwNotificationFlags); /// /// const HANDLE handles[] = { hStopEvent, changes.GetWaitHandle() }; /// /// while (!bTerminate) /// { /// ::MsgWaitForMultipleObjectsEx( /// _countof(handles), /// handles, /// INFINITE, /// QS_ALLINPUT, /// MWMO_INPUTAVAILABLE | MWMO_ALERTABLE); /// switch (rc) /// { /// case WAIT_OBJECT_0 + 0: /// bTerminate = true; /// break; /// case WAIT_OBJECT_0 + 1: /// // We've received a notification in the queue. /// { /// DWORD dwAction; /// CStringW wstrFilename; /// changes.Pop(dwAction, wstrFilename); /// wprintf(L"%s %s\n", ExplainAction(dwAction), wstrFilename); /// } /// break; /// case WAIT_OBJECT_0 + _countof(handles): /// // Get and dispatch message /// break; /// case WAIT_IO_COMPLETION: /// // APC complete.No action needed. /// break; /// } /// } /// /// class CReadDirectoryChanges { public: CReadDirectoryChanges(int nMaxChanges=1000); ~CReadDirectoryChanges(); void Init(); void Terminate(); /// /// Add a new directory to be monitored. /// /// Directory to monitor. /// True to also monitor subdirectories. /// The types of file system events to monitor, such as FILE_NOTIFY_CHANGE_ATTRIBUTES. /// The size of the buffer used for overlapped I/O. /// /// /// This function will make an APC call to the worker thread to issue a new /// ReadDirectoryChangesW call for the given directory with the given flags. /// /// void AddDirectory( LPCTSTR wszDirectory, BOOL bWatchSubtree, DWORD dwNotifyFilter, DWORD dwBufferSize=16384 ); /// /// Return a handle for the Win32 Wait... functions that will be /// signaled when there is a queue entry. /// HANDLE GetWaitHandle() { return m_Notifications.GetWaitHandle(); } bool Pop(DWORD& dwAction, std::wstring& wstrFilename); // "Push" is for usage by ReadChangesRequest. Not intended for external usage. void Push(DWORD dwAction, std::wstring& wstrFilename); // Check if the queue overflowed. If so, clear it and return true. bool CheckOverflow(); unsigned int GetThreadId() { return m_dwThreadId; } protected: ReadDirectoryChangesPrivate::CReadChangesServer* m_pServer; HANDLE m_hThread; unsigned int m_dwThreadId; CThreadSafeQueue m_Notifications; };