Condividi tramite


Recupero delle notifiche di modifica della directory

Un'applicazione può monitorare il contenuto di una directory e le relative sottodirectory usando le notifiche di modifica. L'attesa di una notifica di modifica è simile alla presenza di un'operazione di lettura in sospeso su una directory e, se necessario, delle relative sottodirectory. Quando si modifica un elemento all'interno della directory da controllare, l'operazione di lettura viene completata. Ad esempio, un'applicazione può usare queste funzioni per aggiornare un elenco di directory ogni volta che viene modificato un nome file all'interno della directory monitorata.

Un'applicazione può specificare un set di condizioni che attivano una notifica di modifica usando la funzione FindFirstChangeNotification. Le condizioni includono modifiche ai nomi di file, ai nomi di directory, agli attributi, alle dimensioni dei file, all'ora dell'ultima scrittura e alla sicurezza. Questa funzione restituisce anche un handle che può essere aspettato usando le funzioni di attesa. Se la condizione di attesa è soddisfatta, è possibile usare FindNextChangeNotification per fornire un handle di notifica per attendere le modifiche successive. Tuttavia, queste funzioni non indicano la modifica effettiva che ha soddisfatto la condizione di attesa.

Usare FindCloseChangeNotification per chiudere l'handle di notifica.

Per recuperare informazioni sulla modifica specifica come parte della notifica, usare la funzione ReadDirectoryChangesW. Questa funzione consente inoltre di fornire una routine di completamento.

Nota

Le funzioni FindFirstChangeNotification e ReadDirectoryChangesW si escludono a vicenda. È consigliabile usare uno o l'altro, ma non entrambi.

Per tenere traccia delle modifiche in un volume, vedere Modificare i journal.

Nell'esempio seguente viene monitorato l'albero della directory per individuare le modifiche al nome della directory. Esegue inoltre il monitoraggio di una directory per le modifiche apportate al nome di file. Nell'esempio viene utilizzata la funzione FindFirstChangeNotification per creare due handle di notifica e la funzione WaitForMultipleObjects per attendere gli handle. Ogni volta che una directory viene creata o eliminata nell'albero, l'esempio deve aggiornare l'intero albero di directory. Ogni volta che un file viene creato o eliminato nella directory, l'esempio deve aggiornare la directory.

 

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