Win32API ディレクトリの変更を監視する ReadDirectoryChangesW
ディレクトリの変更を監視するの変更を監視するには、ReadDirectoryChangesW関数を用いる。.NET Frameworkでは、System.IO.FileSystemWatcherがこの関数の機能に相当する。
BOOL ReadDirectoryChangesW( HANDLE hDirectory, // 監視するディレクトリのハンドル LPVOID lpBuffer, // 読み取った結果を受け取る // バッファへのポインタ DWORD nBufferLength, // lpBuffer の長さ BOOL bWatchSubtree, // ディレクトリまたはディレクトリツリーを // 監視するためのフラグ DWORD dwNotifyFilter, // 監視に使うフィルタ条件 LPDWORD lpBytesReturned, // 返されたバイト数 LPOVERLAPPED lpOverlapped, // 重複 I/O 操作に必要な // 構造体へのポインタ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 完了ルーチンへのポインタ );
lpBufferには、FILE_NOTIFY_INFORMATION構造体オブジェクトが格納される。
typedef struct _FILE_NOTIFY_INFORMATION { DWORD NextEntryOffset; //次のレコードを取得するためにスキップすべきバイト数。0の場合は最後のレコードを意味する。 DWORD Action;//変更のタイプ DWORD FileNameLength;//ファイル名の長さ WCHAR FileName[1];//ファイル名 } FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
FILE_NOTIFY_CHANGE_FILE_NAME | ファイル名の変更(ファイル名の変更、ファイルの作成、削除)を監視する |
FILE_NOTIFY_CHANGE_DIR_NAME | ディレクトリ名の変更(ディレクトリの作成、削除)を監視する |
FILE_NOTIFY_CHANGE_ATTRIBUTES | 属性の変更を監視する |
FILE_NOTIFY_CHANGE_SIZE | ファイルサイズの変更を監視する |
FILE_NOTIFY_CHANGE_LAST_WRITE | ファイルの前回書き込み日時の変更を監視する |
FILE_NOTIFY_CHANGE_LAST_ACCESS | ファイルの前回アクセス日時の変更を監視する |
FILE_NOTIFY_CHANGE_CREATION | ファイルの作成日時を監視する |
FILE_NOTIFY_CHANGE_SECURITY | セキュリティ奇術師の変更を監視する |
FILE_ACTION_ADDED | ディレクトリにファイルが追加された |
FILE_ACTION_REMOVED | ディレクトリからファイルが削除された |
FILE_ACTION_MODIFIED | ファイルが修正された(ファイルのタイムスタンプまたは属性が変更されたことも含む)。 |
FILE_ACTION_RENAMED_OLD_NAME | ファイル名が変更され、これは古いファイル名である。 |
FILE_ACTION_RENAMED_NEW_NAME | ファイル名が変更され、これは新しいファイル名である。 |
1.ディレクトリのハンドルは、CreateFileでオープンするが、アクセス権の指定にFILE_LIST_DIRECTORYを指定する必要がある。また、ファイルの作成方法にFILE_FLAG_BACKUP_SEMANTICSを指定する必要がある。
例
HANDLE hDir = CreateFile("C:\\", FILE_LIST_DIRECTORY, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2.FILE_NOTIFY_INFORMATION構造体のNextEntryOffsetメンバは、自分の開発環境(Windows Vista, Visual Studio 2005)では実際の2倍の数値が格納されている様であったので、NextEntryOffsetの値を2で割った値を用いるようにした。
#include <windows.h> #include <stdio.h> #include <locale.h> int main() { //ワイド文字を文字化けさせずに出力するためにロケールを設定する setlocale(LC_ALL, setlocale(LC_CTYPE, "")); const wchar_t *BaseDirName = L"C:\\"; HANDLE hDir = CreateFileW(BaseDirName, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hDir == INVALID_HANDLE_VALUE) { wprintf(L"CreateFile failed."); return 1; } while (1) { wchar_t lpBuffer[1024] = {L'\0'}; DWORD dwBytesReturned; DWORD dwNotifyFilter; BOOL bRet; //監視に使うフィルタ条件 dwNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME | //ファイル名変更 FILE_NOTIFY_CHANGE_DIR_NAME | //ディレクトリ名変更 FILE_NOTIFY_CHANGE_ATTRIBUTES | //属性変更 FILE_NOTIFY_CHANGE_LAST_WRITE | //最終書き込み日時変更 FILE_NOTIFY_CHANGE_LAST_ACCESS | //最終アクセス日時変更 FILE_NOTIFY_CHANGE_CREATION; //作成日時変更 bRet = ReadDirectoryChangesW(hDir, //ディレクトリのハンドル lpBuffer, //FILE_NOTIFY_INFORMATION構造体へのポインタ sizeof(lpBuffer)/sizeof(lpBuffer[0]), //lpBufferのサイズ TRUE, //サブディレクトリを監視するためのフラグ dwNotifyFilter, //監視に使うフィルタ条件 &dwBytesReturned, //返されたバイト数 NULL, //重複I/O操作に必要な構造体へのポインタ NULL);//完了ルーチンへのポインタ if (!bRet) { wprintf(L"ReadDirectoryChangesW failed."); break; } int i = 0; while (1) { FILE_NOTIFY_INFORMATION *lpInfomation = (FILE_NOTIFY_INFORMATION *)&lpBuffer[i]; wchar_t filename[1024] = {L'\0'}; const size_t length = sizeof(filename)/sizeof(filename[0]); lpInfomation->FileName[lpInfomation->FileNameLength/sizeof(wchar_t)] = L'\0'; _snwprintf_s(filename, length, length, L"%s%s", BaseDirName, lpInfomation->FileName); switch (lpInfomation->Action) { case FILE_ACTION_ADDED: wprintf(L"FILE_ACTION_ADDED: %s\n", filename); break; case FILE_ACTION_REMOVED: wprintf(L"FILE_ACTION_REMOVED: %s\n", filename); break; case FILE_ACTION_MODIFIED: wprintf(L"FILE_ACTION_MODIFIED: %s\n", filename); break; case FILE_ACTION_RENAMED_OLD_NAME: wprintf(L"FILE_ACTION_RENAMED_OLD_NAME: %s\n", filename); break; case FILE_ACTION_RENAMED_NEW_NAME: wprintf(L"FILE_ACTION_RENAMED_NEW_NAME: %s\n", filename); break; default: wprintf(L"Unknown File Action: %s\n", filename); break; } if (lpInfomation->NextEntryOffset == 0) { break; } i += lpInfomation->NextEntryOffset / 2; } } CloseHandle(hDir); return 0; }
FILE_ACTION_MODIFIED: C:\WINDOWS\System32\config\SOFTWARE.LOG1 FILE_ACTION_MODIFIED: C:\WINDOWS\System32\config\SOFTWARE FILE_ACTION_MODIFIED: C:\WINDOWS\System32\config\SOFTWARE FILE_ACTION_ADDED: C:\Program Files\PostgreSQL\8.4\data\pg_stat_tmp\pgstat.tmp FILE_ACTION_MODIFIED: C:\Program Files\PostgreSQL\8.4\data\pg_stat_tmp FILE_ACTION_MODIFIED: C:\Program Files\PostgreSQL\8.4\data\pg_stat_tmp\pgstat.tmp FILE_ACTION_REMOVED: C:\Program Files\PostgreSQL\8.4\data\pg_stat_tmp\pgstat.tmp ....................................................
参考
http://msdn.microsoft.com/ja-jp/library/cc429676.aspx
http://support.microsoft.com/kb/245214/ja