Uzyskiwanie powiadomień o zmianie katalogu
Aplikacja może monitorować zawartość katalogu i jego podkatalogów przy użyciu powiadomień o zmianie. Oczekiwanie na powiadomienie o zmianie jest podobne do oczekiwania na wykonanie operacji odczytu odnośnie katalogu i, jeśli to konieczne, jego podkatalogów. Gdy coś zmieni się w obserwowanym katalogu, operacja odczytu zostanie ukończona. Na przykład aplikacja może używać tych funkcji do aktualizowania listy katalogów za każdym razem, gdy nazwa pliku w monitorowanym katalogu ulegnie zmianie.
Aplikacja może określić zestaw warunków wyzwalających powiadomienie o zmianie przy użyciu funkcji FindFirstChangeNotification. Warunki obejmują zmiany nazw plików, nazw katalogów, atrybutów, rozmiaru pliku, czasu ostatniego zapisu i zabezpieczeń. Ta funkcja zwraca również uchwyt, na który można czekać przy użyciu funkcji oczekiwania . Jeśli warunek oczekiwania jest spełniony, FindNextChangeNotification może służyć do zapewnienia dojścia powiadomień do oczekiwania na kolejne zmiany. Jednak te funkcje nie wskazują rzeczywistej zmiany, która spełnia warunek oczekiwania.
Użyj FindCloseChangeNotification aby zamknąć uchwyt powiadomień.
Aby pobrać informacje o określonej zmianie w ramach powiadomienia, użyj funkcji ReadDirectoryChangesW. Ta funkcja umożliwia również zdefiniowanie rutyny zakończenia.
Notatka
Funkcje FindFirstChangeNotification i ReadDirectoryChangesW wzajemnie się wykluczają. Należy użyć jednej lub drugiej, ale nie obu.
Aby monitorować zmiany na woluminie, zobacz dzienniki zmian.
Poniższy przykład monitoruje drzewo katalogów pod kątem zmian nazwy katalogu. Monitoruje również katalog pod kątem zmian nazwy pliku. W tym przykładzie używana jest funkcja FindFirstChangeNotification, aby utworzyć dwa dojścia powiadomień, oraz funkcja WaitForMultipleObjects, żeby czekać na te dojścia. Za każdym razem, gdy katalog zostanie utworzony lub usunięty w drzewie, przykład powinien zaktualizować całe drzewo katalogów. Za każdym razem, gdy plik zostanie utworzony lub usunięty w katalogu, aplikacja powinna odświeżyć katalog.
Notatka
W tym uproszczonym przykładzie użyto funkcji ExitProcess w celu zakończenia i czyszczenia, ale bardziej złożone aplikacje powinny zawsze używać odpowiedniego zarządzania zasobami, takich jak FindCloseChangeNotification tam, gdzie jest to konieczne.
#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);
}