Visual C++ has been one of most effective tool for the large industrial applications. This book is t

源代码在线查看: watcher.html

软件大小: 1662 K
上传用户: sun337146987
关键词: applications industrial effective Visual
下载地址: 免注册下载 普通下载 VIP

相关代码

				
				
				Directory Change Notification
				
				
				
				
				
				
				
				
				
				   
				      
				      
				      Home
				   
				       When Folders Change
				       
				
				
				
				
				
				
				    
				    
				
				   
				   
				   
				
				
				
				Have you ever wondered how the Explorer knows that it should update its display because a file has been added or removed from a folder by some external application? Wonder no more because, with the use of our Active Object, we can do the same and more. There are a few simple API calls that you can make to ask the file system to selectively notify you about changes to files and folders. Once you set up such a watch, your thread can go to sleep waiting on an event. The file system will set the event as soon as it detects the kind of change that you're watching for.
				
				
				
				
				Download the source of a sample application, FolderWatcher (zipped 11K).
				
				
				
				
				Without further ado, let's derive a FolderWatcher from ActiveObject. We'll give it a notification source&emdash;an event, and a notification sink&emdash;a handle to a window that will respond to the notification. The source event is set up in the constructor of FolderWatcher. It is also important to start the captive thread at the end of the constructor.
				
				
				class FolderWatcher : public ActiveObject
				{
				public:
				    FolderWatcher (char const * folder, HWND hwnd)
				        : _notifySource (folder),
				          _hwndNotifySink (hwnd)
				    {
				        strcpy (_folder, folder);
				        _thread.Resume ();
				    }
				    ~FolderWatcher ()
				    {
				        Kill ();
				    }
				
				private:
				    void InitThread () {}
				    void Loop ();
				    void FlushThread () {}
				
				    FolderChangeEvent _notifySource;
				    HWND _hwndNotifySink;
				    char _folder [MAX_PATH];
				};
				
				
				
				The action in the ActiveObject happens inside the Loop method. Here we set up an "infinite" loop in which we let the thread wait for the event. When the event happens, we check for the _isDying flag (as usual) and post a special message WM_FOLDER_CHANGE to the window that deals with notifications. This is not one of the predefined Windows messages, it's a message defined by us for the special purpose of passing folder notification information from one thread to another.
				Two thing happen now: the captive thread makes another API call to let the file system know that it wants more notifications. It then goes back to watchful sleep. Concurrently, Windows retrieves our WM_FOLDER_CHANGE message from the message queue and sends it to the Windows Procedure of the sink window. More about that in a moment.
				
				
				UINT const WM_FOLDER_CHANGE = WM_USER;
				
				void FolderWatcher::Loop ()
				{
				    for (;;)
				    {
				        // Wait for change notification
				        DWORD waitStatus = WaitForSingleObject (_notifySource, INFINITE);
				        if (WAIT_OBJECT_0 == waitStatus)
				        {
				            // If folder changed
				            if (_isDying)
				                return;
				
				            PostMessage (_hwndNotifySink,
				                          WM_FOLDER_CHANGE,
				                          0,
				                          (LPARAM) _folder);
				
				            // Continue change notification
				            if (!_notifySource.ContinueNotification ())
				            {
				                // Error: Continuation failed
				                return;
				            }
				        }
				        else
				        {
				            // Error: Wait failed
				            return;
				        }
				    }
				}
				
				
				
				So here what happens in the Windows Procedure in response to our special message: we call the Controller's method OnFolderChange. This method can do anything we want. In the Explorer it refreshes the display of the folder we are watching. In our example it just pops up a simple message box. Notice how we are passing the name of the changed folder as LPARAM. It is totally up to us to define what goes into WPARAM and LPARAM of a user-defined message.
				By the way, the Folder Watcher is just a part of the Controller.
				
				
				
				    case WM_FOLDER_CHANGE:
				        pCtrl->OnFolderChange (hwnd, (char const *) lParam);
				        return 0;
				
				
				void Controller::OnFolderChange (HWND hwnd, char const * folder)
				{
				    MessageBox (hwnd, "Change Detected, "Folder Watcher",
				                 MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
				}
				
				class Controller
				{
				public:
				    Controller(HWND hwnd, CREATESTRUCT * pCreate);
				    ~Controller ();
				    void    OnFolderChange (HWND hwnd, char const *folder);
				
				private:
				    FolderWatcher _folderWatcher;
				};
				
				
				
				Now that we know how to deal with notification, let's have a look at their sources, the File Change Events. An event object is created by the file system in response to FindFirstChangeNotification. A handle to that event is returned from the call. We remember this handle and use it later to either renew or abandon our interest in further notifications. Notice that we can set the watch to be recursive, i.e., watching a given folder and all its subfolders and sub-subfolders. We can also express interest in particular types of changes by passing a bitwise OR of any combination of the following flags:
				
				FILE_NOTIFY_CHANGE_FILE_NAME (renaming, creating, or deleting a file)
				FILE_NOTIFY_CHANGE_DIR_NAME	(creating or deleting a directory)
				FILE_NOTIFY_CHANGE_ATTRIBUTES
				FILE_NOTIFY_CHANGE_SIZE
				FILE_NOTIFY_CHANGE_LAST_WRITE (saving a file)
				FILE_NOTIFY_CHANGE_SECURITY
				
				For convenience we have defined a few subclasses of FileChangeEvent that correspond to some useful combinations of these flags. One of them is the FolderChangeEvent that we used in our FolderWatcher.
				
				
				
				class FileChangeEvent
				{
				public:
				    FileChangeEvent (char const * folder, BOOL recursive, DWORD notifyFlags)
				    {
				        _handle = FindFirstChangeNotification (folder, recursive, notifyFlags);
				        if (INVALID_HANDLE_VALUE == _handle)
				            throw WinException ("Cannot create change notification handle");
				    }
				    ~FileChangeEvent ()
				    {
				        if (INVALID_HANDLE_VALUE != _handle)
				            FindCloseChangeNotification (_handle);
				    }
				
				    operator HANDLE () const { return _handle; }
				    BOOL ContinueNotification ()
				    {
				        return FindNextChangeNotification (_handle);
				    }
				
				private:
				    HANDLE _handle;
				};
				
				class FolderChangeEvent : public FileChangeEvent
				{
				public:
				    FolderChangeEvent (char const * folder)
				        : FileChangeEvent (folder, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME)
				    {}
				};
				
				class TreeChangeEvent : public FileChangeEvent
				{
				public:
				    TreeChangeEvent (char const * root)
				        : FileChangeEvent (root, TRUE,
				                           FILE_NOTIFY_CHANGE_FILE_NAME
				                         | FILE_NOTIFY_CHANGE_DIR_NAME)
				    {}
				};
				
				
				
				
				It should be easy now to generalize this example to do some really useful work in your programs. Remember to look up the API's that we use in these tutorials in the online help that comes with your compiler.
				How about some OLE or COM programming without MFC? Go to the next page
				
				   
				   
				
				
				
				
				
							

相关资源