Freigeben über


Erhalt von Benachrichtigungen zu Verzeichnisänderungen

Eine Anwendung kann den Inhalt eines Verzeichnisses und seiner Unterverzeichnisse mithilfe von Änderungsbenachrichtigungen überwachen. Das Warten auf eine Änderungsbenachrichtigung ist dem Warten auf einen ausstehenden Lesevorgang für ein Verzeichnis und dessen Unterverzeichnisse (wenn notwendig) ähnlich. Wenn etwas im überwachten Verzeichnis geändert wird, wird der Lesevorgang abgeschlossen. Beispielsweise kann eine Anwendung diese Funktionen verwenden, um eine Verzeichnisauflistung zu aktualisieren, wenn ein Dateiname innerhalb des überwachten Verzeichnisses geändert wird.

Eine Anwendung kann mittels der Funktion FindFirstChangeNotification eine Reihe von Bedingungen angeben, die eine Änderungsbenachrichtigung auslösen. Zu den Bedingungen gehören Änderungen für Dateinamen, Verzeichnisnamen, Attribute, Dateigrößen, Zeitpunkte der letzten Schreibvorgänge und Sicherheit. Diese Funktion gibt auch ein Handle zurück, auf das mittels der Wartefunktionen gewartet werden kann. Wenn die Wartebedingung erfüllt ist, kann FindNextChangeNotification verwendet werden, um ein Benachrichtigungshandle bereitzustellen und auf nachfolgende Änderungen zu warten. Diese Funktionen geben jedoch nicht die tatsächliche Änderung an, die die Wartebedingung erfüllt hat.

Sie können das Benachrichtigungs-Handle mittels FindCloseChangeNotification schließen.

Zum Abruf von Informationen zur spezifischen Änderung, die die Benachrichtigung ausgelöst hat, können Sie die Funktion ReadDirectoryChangesW verwenden. Mit dieser Funktion können Sie auch eine Abschlussroutine bereitstellen.

Hinweis

Die Funktionen FindFirstChangeNotification und ReadDirectoryChangesW schließen sich gegenseitig aus. Sie sollten jeweils nur eine Funktion verwenden, nicht beide.

Informationen zur Nachverfolgung von Änderungen auf einem Volume finden Sie unter Änderungsjournale.

Im folgenden Beispiel wird die Verzeichnisstruktur auf Änderungen von Verzeichnisnamen überwacht. Außerdem wird ein Verzeichnis auf Dateinamenänderungen überwacht. Im Beispiel wird die Funktion FindFirstChangeNotification verwendet, um zwei Benachrichtigungs-Handles zu erstellen, während die Funktion WaitForMultipleObjects verwendet wird, um auf die Handles zu warten. Wenn ein Verzeichnis in der Struktur erstellt oder gelöscht wird, sollte im Beispiel die gesamte Verzeichnisstruktur aktualisiert werden. Wenn eine Datei im Verzeichnis erstellt oder gelöscht wird, sollte im Beispiel das Verzeichnis aktualisiert werden.

Hinweis

In diesem einfachen Beispiel wird die Funktion ExitProcess zum Beenden und Bereinigen verwendet. Komplexere Anwendungen sollten jedoch stets eine ordnungsgemäße Ressourcenverwaltung wie FindCloseChangeNotification verwenden, wenn erforderlich.

 

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WatchDirectory(LPTSTR);

void _tmain(int argc, TCHAR *argv[])
{
    if(argc != 2)
    {
        _tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
        return;
    }

    WatchDirectory(argv[1]);
}

void WatchDirectory(LPTSTR lpDir)
{
   DWORD dwWaitStatus; 
   HANDLE dwChangeHandles[2]; 
   TCHAR lpDrive[4];
   TCHAR lpFile[_MAX_FNAME];
   TCHAR lpExt[_MAX_EXT];

   _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

   lpDrive[2] = (TCHAR)'\\';
   lpDrive[3] = (TCHAR)'\0';
 
// Watch the directory for file creation and deletion. 
 
   dwChangeHandles[0] = FindFirstChangeNotification( 
      lpDir,                         // directory to watch 
      FALSE,                         // do not watch subtree 
      FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes 
 
   if (dwChangeHandles[0] == INVALID_HANDLE_VALUE) 
   {
     printf("\n ERROR: FindFirstChangeNotification function failed.\n");
     ExitProcess(GetLastError()); 
   }
 
// Watch the subtree for directory creation and deletion. 
 
   dwChangeHandles[1] = FindFirstChangeNotification( 
      lpDrive,                       // directory to watch 
      TRUE,                          // watch the subtree 
      FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes 
 
   if (dwChangeHandles[1] == INVALID_HANDLE_VALUE) 
   {
     printf("\n ERROR: FindFirstChangeNotification function failed.\n");
     ExitProcess(GetLastError()); 
   }
 

// Make a final validation check on our handles.

   if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
   {
     printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
     ExitProcess(GetLastError()); 
   }

// Change notification is set. Now wait on both notification 
// handles and refresh accordingly. 
 
   while (TRUE) 
   { 
   // Wait for notification.
 
      printf("\nWaiting for notification...\n");

      dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles, 
         FALSE, INFINITE); 
 
      switch (dwWaitStatus) 
      { 
         case WAIT_OBJECT_0: 
 
         // A file was created, renamed, or deleted in the directory.
         // Refresh this directory and restart the notification.
 
             RefreshDirectory(lpDir); 
             if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
             {
               printf("\n ERROR: FindNextChangeNotification function failed.\n");
               ExitProcess(GetLastError()); 
             }
             break; 
 
         case WAIT_OBJECT_0 + 1: 
 
         // A directory was created, renamed, or deleted.
         // Refresh the tree and restart the notification.
 
             RefreshTree(lpDrive); 
             if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
             {
               printf("\n ERROR: FindNextChangeNotification function failed.\n");
               ExitProcess(GetLastError()); 
             }
             break; 
 
         case WAIT_TIMEOUT:

         // A timeout occurred, this would happen if some value other 
         // than INFINITE is used in the Wait call and no changes occur.
         // In a single-threaded environment you might not want an
         // INFINITE wait.
 
            printf("\nNo changes in the timeout period.\n");
            break;

         default: 
            printf("\n ERROR: Unhandled dwWaitStatus.\n");
            ExitProcess(GetLastError());
            break;
      }
   }
}

void RefreshDirectory(LPTSTR lpDir)
{
   // This is where you might place code to refresh your
   // directory listing, but not the subtree because it
   // would not be necessary.

   _tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}

void RefreshTree(LPTSTR lpDrive)
{
   // This is where you might place code to refresh your
   // directory listing, including the subtree.

   _tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
}