Obtention des notifications de modification de répertoire

Une application peut surveiller le contenu d’un répertoire et de ses sous-répertoires via l’utilisation de notifications de modification. L’attente d’une notification de modification est similaire au fait d’avoir une opération de lecture en attente sur un répertoire et ses sous-répertoires, le cas échéant. Lorsqu’un changement intervient dans le répertoire surveillé, l’opération de lecture est terminée. Par exemple, une application peut utiliser ces fonctions pour mettre à jour une liste de répertoires à chaque fois qu’un nom de fichier dans le répertoire surveillé change.

Une application peut spécifier un ensemble de conditions qui déclenchent une notification de modification via la fonction FindFirstChangeNotification. Les conditions incluent les modifications apportées aux noms de fichiers, aux noms de répertoires, aux attributs, à la taille du fichier, à l’heure de la dernière écriture et à la sécurité. Cette fonction renvoie également un descripteur qui peut être attendu à l’aide des fonctions d’attente. Si la condition d’attente est satisfaite, FindNextChangeNotification peut être utilisé pour fournir un descripteur de notification pour attendre les modifications suivantes. Toutefois, ces fonctions n’indiquent pas la modification réelle qui satisfait la condition d’attente.

Utilisez FindCloseChangeNotification pour fermer le descripteur de notification.

Pour récupérer des informations sur la modification spécifique dans le cadre de la notification, veuillez utiliser la fonction ReadDirectoryChangesW. Cette fonction vous permet également de fournir une routine d’achèvement.

Remarque

Les fonctions FindFirstChangeNotification et ReadDirectoryChangesW s’excluent mutuellement. Vous pouvez utiliser l’une ou l’autre, mais pas les deux.

Pour suivre les modifications sur un volume, consultez Journaux de modifications.

L’exemple suivant surveille l’arborescence des répertoires pour détecter les changements de noms de répertoires. Il surveille également les changements de noms de fichiers dans un répertoire. Dans cet exemple, on utilise la fonction FindFirstChangeNotification pour créer deux descripteurs de notification et la fonction WaitForMultipleObjects pour attendre les descripteurs. Chaque fois qu’un répertoire est créé ou supprimé dans l’arborescence de répertoires, l’exemple doit mettre à jour l’ensemble de l’arborescence. Chaque fois qu’un fichier est créé ou supprimé dans le répertoire, l’exemple doit actualiser le répertoire.

Remarque

Cet exemple simple utilise la fonction ExitProcess pour l’arrêt et le nettoyage, mais les applications plus complexes doivent toujours utiliser une gestion des ressources appropriée, telle que FindCloseChangeNotification, le cas échéant.

 

#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);
}