⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 watcher.html.primary

📁 Windows API Tutorials, Windows API编程最好的手册.文档格式专门制作成为各个章节相互关联的html格式,大家可以像查阅msdn一样方便使用.各个章节的内容如下: Wi
💻 PRIMARY
字号:
<html>
<head>
<title>Directory Change Notification</title>
<meta  name="description" content="Reliable Software Win32 Tutorial: Directory Change Notification">
<meta name="keywords" content="FindFirstChangeNotification, WaitForSingleObject, win95, win32, cplusplus, source code, example, tutorial, thread, event, object oriented">
</head>

<body background="../images/grid.gif" bgcolor="white" text="black">


<table cellpadding=10 width="100%">
<tr>
   <td width=100 align=center valign=middle>
      <a href="../index.htm">
      <img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
      <br>Home</a>
   <td><font face="arial" color="#009966">
       <h1 align=center>When Folders Change</h1>
       </font>
</table>


<p>
<table width="100%">
<tr>
   <td width=80> <!-- Left margin -->
   <td> <!-- Middle column, there is also the right margin at the end -->

   <table cellpadding=10 cellspacing=0 width="100%">
   <tr>
   <td bgcolor="#ffffff">


<hr>
<font size="+1"><b>Have you ever wondered</b></font> 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.

<table cellpadding="5">
<tr>
<td width=40><a href="source/watcher.zip"><img src="images/brace.gif" width=16 height=16 border=0 alt="Download"></a>
<td bgcolor="#e0e080">Download the source of a sample application, <a href="source/watcher.zip">FolderWatcher</a> (zipped 11K).
<td width=40>
</table>


<p>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.
<hr>
<pre><font face="courier">
class <font color="#cc0066"><b>FolderWatcher</b></font> : public <font color="#cc0066"><b>ActiveObject</b></font>
{
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];
};

</font></pre>
<hr>
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.
<p>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.
<hr>
<pre><font face="courier">
UINT const WM_FOLDER_CHANGE = <font color="#009966">WM_USER</font>;

void <font color="#cc0066"><b>FolderWatcher::Loop</b></font> ()
{
    for (;;)
    {
        // Wait for change notification
        DWORD waitStatus = <font color="#cc0066"><b>WaitForSingleObject</b></font> (_notifySource, <font color="#009966">INFINITE</font>);
        if (<font color="#009966">WAIT_OBJECT_0</font> == waitStatus)
        {
            // If folder changed
            if (_isDying)
                return;

            <font color="#000099"><b>PostMessage</b></font> (_hwndNotifySink,
                          WM_FOLDER_CHANGE,
                          0,
                          (LPARAM) _folder);

            // Continue change notification
            if (!_notifySource.ContinueNotification ())
            {
                // Error: Continuation failed
                return;
            }
        }
        else
        {
            // Error: Wait failed
            return;
        }
    }
}

</font></pre>
<hr>
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.
<p>By the way, the Folder Watcher is just a part of the Controller.
<hr>
<pre><font face="courier">

    case WM_FOLDER_CHANGE:
        pCtrl-&gt;OnFolderChange (hwnd, (char const *) lParam);
        return 0;


void <font color="#cc0066"><b>Controller::OnFolderChange</b></font> (HWND hwnd, char const * folder)
{
    <font color="#000099"><b>MessageBox</b></font> (hwnd, "Change Detected, "Folder Watcher",
                 <font color="#009966">MB_SETFOREGROUND</font> | <font color="#009966">MB_ICONEXCLAMATION</font> | <font color="#009966">MB_OK</font>);
}

class <font color="#cc0066"><b>Controller</b></font>
{
public:
    Controller(HWND hwnd, <font color="#009966">CREATESTRUCT</font> * pCreate);
    ~Controller ();
    void    OnFolderChange (HWND hwnd, char const *folder);

private:
    FolderWatcher _folderWatcher;
};

</font></pre>
<hr>
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:
<ul>
<li>FILE_NOTIFY_CHANGE_FILE_NAME (renaming, creating, or deleting a file)
<li>FILE_NOTIFY_CHANGE_DIR_NAME	(creating or deleting a directory)
<li>FILE_NOTIFY_CHANGE_ATTRIBUTES
<li>FILE_NOTIFY_CHANGE_SIZE
<li>FILE_NOTIFY_CHANGE_LAST_WRITE (saving a file)
<li>FILE_NOTIFY_CHANGE_SECURITY
</ul>
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.
<hr>
<pre><font face="courier">

class <font color="#cc0066"><b>FileChangeEvent</b></font>
{
public:
    FileChangeEvent (char const * folder, BOOL recursive, DWORD notifyFlags)
    {
        _handle = <font color="#000099"><b>FindFirstChangeNotification</b></font> (folder, recursive, notifyFlags);
        if (<font color="#009966">INVALID_HANDLE_VALUE</font> == _handle)
            throw WinException ("Cannot create change notification handle");
    }
    ~FileChangeEvent ()
    {
        if (<font color="#009966">INVALID_HANDLE_VALUE</font> != _handle)
            <font color="#000099"><b>FindCloseChangeNotification</b></font> (_handle);
    }

    operator <font color="#009966">HANDLE</font> () const { return _handle; }
    BOOL ContinueNotification ()
    {
        return <font color="#000099"><b>FindNextChangeNotification</b></font> (_handle);
    }

private:
    <font color="#009966">HANDLE</font> _handle;
};

class <font color="#cc0066"><b>FolderChangeEvent</b></font> : public <font color="#cc0066"><b>FileChangeEvent</b></font>
{
public:
    FolderChangeEvent (char const * folder)
        : FileChangeEvent (folder, FALSE, <font color="#009966">FILE_NOTIFY_CHANGE_FILE_NAME</font>)
    {}
};

class <font color="#cc0066"><b>TreeChangeEvent</b></font> : public <font color="#cc0066"><b>FileChangeEvent</b></font>
{
public:
    TreeChangeEvent (char const * root)
        : FileChangeEvent (root, TRUE,
                           <font color="#009966">FILE_NOTIFY_CHANGE_FILE_NAME</font>
                         | <font color="#009966">FILE_NOTIFY_CHANGE_DIR_NAME</font>)
    {}
};


</font></pre>
<hr>
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.
<p>How about some OLE or COM programming <u>without MFC</u>? Go to the <a href="shell.html">next page</a>
<hr>
   </table>
   <td width=60>
</table>


</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -