Share via


ディレクトリ変更通知の取得

アプリケーションは、変更通知を使用して、ディレクトリとそのサブディレクトリの内容を監視できます。 変更通知の待機は、ディレクトリとそのサブディレクトリに対して読み取り操作を保留中にしているのと似ています。 監視対象のディレクトリ内で何かが変更されると、読み取り操作が完了します。 たとえば、アプリケーションでは、監視対象のディレクトリ内のファイル名が変更されるたびに、これらの関数を使用してディレクトリの一覧を更新できます。

アプリケーションでは、 FindFirstChangeNotification 関数を使用して変更通知をトリガーする一連の条件を指定できます。 条件には、ファイル名、ディレクトリ名、属性、ファイル サイズ、最終書き込み時刻、セキュリティの変更が含まれます。 この関数は、 待機関数を使用して待機できるハンドルも返します。 待機条件が満たされた場合は、 FindNextChangeNotification を使用して、後続の変更を待機する通知ハンドルを提供できます。 ただし、これらの関数は、待機条件を満たす実際の変更を示すものではありません。

FindCloseChangeNotification を使用して通知ハンドルを閉じます。

通知の一部として特定の変更に関する情報を取得するには、 ReadDirectoryChangesW 関数を使用します。 この関数を使用すると、完了ルーチンを指定することもできます。

ボリュームの変更を追跡するには、「 変更履歴」を参照してください。

次の例では、ディレクトリ名の変更についてディレクトリ ツリーを監視します。 また、ディレクトリでファイル名の変更も監視します。 この例では、 FindFirstChangeNotification 関数を使用して 2 つの通知ハンドルを作成し、 WaitForMultipleObjects 関数を使用してハンドルを待機します。 ツリーでディレクトリが作成または削除されるたびに、この例ではディレクトリ ツリー全体を更新する必要があります。 ディレクトリでファイルが作成または削除されるたびに、この例ではディレクトリを更新する必要があります。

Note

この単純な例では、終了とクリーンアップに ExitProcess 関数を使用しますが、より複雑なアプリケーションでは、必要に応じて FindCloseChangeNotification などの適切なリソース管理を常に使用する必要があります。

 

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