VC++ 监控指定目录改变

转载:http://www.cnblogs.com/doublesnke/archive/2011/08/16/2141374.html

VC++实施文件监控:实例和详解

相关帮助: http://hi.baidu.com/jiahaosoft/blog/item/b441d1218eebece0d6cae274.html

我这里只介绍采用ReadDirectoryChangesW对文件目录实施监控

关键代码

CfgdsgDlg * dlg = (CfgdsgDlg*)lparam;
 
    HANDLE hDir;
    char notify[1024];
    DWORD cbBytes,i;
    char AnsiChar[3];
    wchar_t UnicodeChar[2];
    CString path;
 
    FILE_NOTIFY_INFORMATION *pnotify=(FILE_NOTIFY_INFORMATION *)notify;
    FILE_NOTIFY_INFORMATION *tmp;
 
    GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
    hDir = CreateFile( path, FILE_LIST_DIRECTORY,
        FILE_SHARE_READ |
        FILE_SHARE_WRITE |
        FILE_SHARE_DELETE, NULL,
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
        FILE_FLAG_OVERLAPPED, NULL);
    if (hDir == INVALID_HANDLE_VALUE)
    {
 
        dlg->m_edit.ReplaceSel("hDir:INVALID_HANDLE_VALUE ");
        return 0;
    }
 
    while (TRUE)
    {
        if(ReadDirectoryChangesW(hDir, &notify, sizeof(notify),
            FALSE, FILE_NOTIFY_CHANGE_FILE_NAME| FILE_NOTIFY_CHANGE_LAST_WRITE,
            &cbBytes, NULL, NULL))
        {
 
            tmp = pnotify;
 
            switch(tmp->Action)
            {
            case FILE_ACTION_ADDED:
 
                dlg->m_edit.ReplaceSel("Directory/File added (添加文件)- ");
                break;
            case FILE_ACTION_REMOVED:
                dlg->m_edit.ReplaceSel("Directory/File removed (删除文件)- ");
                break;
            case FILE_ACTION_MODIFIED:
                dlg->m_edit.ReplaceSel("Directory/File modified (修改文件内容)- ");
                break;
            case FILE_ACTION_RENAMED_OLD_NAME:
                dlg->m_edit.ReplaceSel("Directory/File old name (修改文件名字)- ");
                break;
            case FILE_ACTION_RENAMED_NEW_NAME:
                dlg->m_edit.ReplaceSel("Directory/File new name - ");
                break;
            default:
                break;
            }
        }
    }

  

FILE_NOTIFY_INFORMATION //可以确定是那个文件进行的修改

typedef struct _FILE_NOTIFY_INFORMATION {
  DWORD NextEntryOffset;
  DWORD Action;//动作
  DWORD FileNameLength;//文件名字的长度
  WCHAR FileName[1];//文件名字
} FILE_NOTIFY_INFORMATION, 
*PFILE_NOTIFY_INFORMATION;

ReadDirectoryChangesW 返回类型(见MSDN)

ValueMeaning

FILE_ACTION_ADDED
0x00000001

The file was added to the directory.

FILE_ACTION_REMOVED
0x00000002

The file was removed from the directory.

FILE_ACTION_MODIFIED
0x00000003

The file was modified. This can be a change in the time stamp or attributes.

FILE_ACTION_RENAMED_OLD_NAME
0x00000004

The file was renamed and this is the old name.

FILE_ACTION_RENAMED_NEW_NAME
0x00000005

The file was renamed and this is the new name.

效果如下:

不足的地方:

只能检测到指定目录和下一级目录,超过目录级数,该函数检测不到。

2. 转载:http://blog.csdn.net/visualeleven/article/details/7562014

 1 // .h文件
 2 #pragma once
 3 
 4 typedef void (*PFN_NotifyAction)(DWORD dwAction, LPWSTR szFile, DWORD dwLength);
 5 
 6 class CDirectoryWatch
 7 {
 8 public:
 9     CDirectoryWatch(void);
10     virtual ~CDirectoryWatch(void);
11 
12 public:
13     BOOL StartDirectoryWatch(LPCTSTR lpszDirectory, PFN_NotifyAction pFn_NotifyAction);
14     BOOL StopDirectoryWatch(void);
15 
16 private:
17     static UINT __cdecl ThreadProc(LPVOID lParam);
18     static UINT __cdecl DirectoryWatch(LPVOID lParam);
19 
20 private:
21     HANDLE m_hFile;
22     CWinThread* m_pThread;
23     TCHAR m_szDirectory[MAX_PATH];
24 };
  1 // .cpp文件
  2 #include "StdAfx.h"
  3 #include "DirectoryWatch.h"
  4 #include <strsafe.h>
  5 
  6 typedef enum
  7 {
  8     MSG_STARTWATCH = (WM_USER + 0x11),
  9     MSG_STOPWATCH,
 10     MSG_EXITTHREAD
 11 };
 12 
 13 #define MAX_BUFFER_SIZE    (1024)
 14 
 15 typedef struct _tagWATCHPARAMETERS
 16 {
 17     _tagWATCHPARAMETERS()
 18     {
 19         hFile = INVALID_HANDLE_VALUE;
 20         hEvent = NULL;
 21         memset(&ol, 0, sizeof(OVERLAPPED));
 22         pBuffer = NULL;
 23         dwBufferSize = 0;
 24         bExit = FALSE;
 25         pFn_NotifyAction = NULL;
 26     }
 27     HANDLE hFile;
 28     HANDLE hEvent;
 29     OVERLAPPED ol;
 30     BYTE* pBuffer;
 31     DWORD dwBufferSize;
 32     BOOL bExit;
 33     PFN_NotifyAction pFn_NotifyAction;
 34 }WATCH_PARAMETERS, *PWATCH_PARAMETERS;
 35 
 36 CDirectoryWatch::CDirectoryWatch() : m_hFile(INVALID_HANDLE_VALUE), m_pThread(NULL)
 37 {
 38     memset(m_szDirectory, 0, sizeof(m_szDirectory));
 39 
 40     m_pThread = AfxBeginThread(ThreadProc, NULL, 0, CREATE_SUSPENDED, 0, NULL);
 41     if(NULL == m_pThread)
 42     {
 43         TRACE("Error Code : %d
", GetLastError());
 44         return ;
 45     }
 46     m_pThread->m_bAutoDelete = FALSE;
 47     m_pThread->ResumeThread();
 48 }
 49 
 50 
 51 CDirectoryWatch::~CDirectoryWatch()
 52 {
 53     if(INVALID_HANDLE_VALUE != m_hFile)
 54     {
 55         CloseHandle(m_hFile);
 56         m_hFile = INVALID_HANDLE_VALUE;
 57     }
 58 
 59     if((NULL != m_pThread) && (NULL != m_pThread->m_hThread))
 60     {
 61 
 62         m_pThread->PostThreadMessage(MSG_EXITTHREAD, 0, 0);
 63         WaitForSingleObject(m_pThread->m_hThread, INFINITE);
 64         delete m_pThread;
 65         m_pThread = NULL;
 66     }
 67 }
 68 
 69 BOOL CDirectoryWatch::StartDirectoryWatch(LPCTSTR lpszDirectory, PFN_NotifyAction pFn_NotifyAction)
 70 {
 71     if(NULL == m_pThread)
 72     {
 73         return FALSE;
 74     }
 75 
 76     if(NULL == lpszDirectory)
 77     {
 78         return FALSE;
 79     }
 80 
 81     if(NULL == pFn_NotifyAction)
 82     {
 83         return FALSE;
 84     }
 85 
 86     if(!PathFileExists(lpszDirectory))
 87     {
 88         TRACE("Error Code : %d
", GetLastError());
 89         return FALSE;
 90     }
 91 
 92     if(!PathIsDirectory(lpszDirectory))
 93     {
 94         TRACE("Error Code : %d
", GetLastError());
 95         return FALSE;
 96     }
 97 
 98     if(0 == _tcslen(m_szDirectory))
 99     {
100         StringCchPrintf(m_szDirectory, _countof(m_szDirectory), _T("%s"), lpszDirectory);
101     }
102     else if(CSTR_EQUAL != CompareStringOrdinal(m_szDirectory, -1, lpszDirectory, -1, TRUE))
103     {
104         TRACE("Not Change Directory.
");
105         return FALSE;
106     }
107 
108     if(INVALID_HANDLE_VALUE == m_hFile)
109     {
110         m_hFile = CreateFile(lpszDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
111             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
112         if(INVALID_HANDLE_VALUE == m_hFile)
113         {
114             TRACE("Error Code : %d
", GetLastError());
115             return FALSE;
116         }
117     }
118 
119     return m_pThread->PostThreadMessage(MSG_STARTWATCH, (WPARAM)m_hFile, (LPARAM)pFn_NotifyAction);
120 }
121 
122 BOOL CDirectoryWatch::StopDirectoryWatch()
123 {
124     if(NULL != m_pThread)
125     {
126         return m_pThread->PostThreadMessage(MSG_STOPWATCH, 0, 0);
127     }
128 
129     return FALSE;
130 }
131 
132 UINT __cdecl CDirectoryWatch::DirectoryWatch(LPVOID lParam)
133 {
134     WATCH_PARAMETERS* pParam = (WATCH_PARAMETERS*)lParam;
135     if(NULL == pParam)
136     {
137         return 0;
138     }
139     HANDLE& hFile = pParam->hFile;
140     BYTE* pBuffer = pParam->pBuffer;
141     DWORD dwBufferSize = pParam->dwBufferSize;
142     OVERLAPPED& ol = pParam->ol;
143     HANDLE& hEvent = pParam->hEvent;
144     BOOL& bExit = pParam->bExit;
145     PFN_NotifyAction pFn_NotifyAction = pParam->pFn_NotifyAction;
146     DWORD dwBytesReturn = 0;
147     DWORD dwRet = WAIT_FAILED;
148     DWORD dwOffSet = 0;
149     TCHAR szFile[MAX_PATH] = {0};
150     while(TRUE)
151     {
152         if(WAIT_OBJECT_0 != WaitForSingleObject(hEvent, INFINITE))
153         {
154             TRACE("Error Code : %d
", GetLastError());
155             break;
156         }
157 
158         if(bExit)
159         {
160             break;
161         }
162     
163         if(!ReadDirectoryChangesW(hFile, pBuffer, dwBufferSize, TRUE, 
164             FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES
165             | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS
166             | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &dwBytesReturn, &ol, NULL))
167         {
168             TRACE("Error Code : %d
", GetLastError());
169             break;
170         }
171         if(!GetOverlappedResult(hFile, &ol, &dwBytesReturn, TRUE))
172         {
173             TRACE("Error Code : %d
", GetLastError());
174             break;
175         }
176         FILE_NOTIFY_INFORMATION* pFileNotify = (FILE_NOTIFY_INFORMATION*)pBuffer;
177         
178         do 
179         {
180             if(pFn_NotifyAction && (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0)))
181             {
182                 pFn_NotifyAction(pFileNotify->Action, pFileNotify->FileName, (pFileNotify->FileNameLength) / sizeof(WCHAR));
183             }
184 
185             dwOffSet = pFileNotify->NextEntryOffset;
186             pFileNotify = (FILE_NOTIFY_INFORMATION*)((BYTE*)pFileNotify + dwOffSet);
187         } while (dwOffSet);
188     }
189     TRACE0("DirectoryWatch Thread Exit ... 
");
190     return 0;
191 }
192 
193 UINT __cdecl CDirectoryWatch::ThreadProc(LPVOID lParam)
194 {
195     WATCH_PARAMETERS* pParam = new WATCH_PARAMETERS;
196 
197     if(NULL == pParam)
198     {
199         goto __CLEANUP__;
200     }
201 
202     BYTE* pBuffer = new BYTE[MAX_BUFFER_SIZE];
203     if(NULL == pBuffer)
204     {
205         goto __CLEANUP__;
206     }
207     memset(pBuffer, 0, MAX_BUFFER_SIZE);
208     pParam->pBuffer = pBuffer;
209     pParam->dwBufferSize = MAX_BUFFER_SIZE;
210     HANDLE hWatchEvent  = CreateEvent(NULL, TRUE, FALSE, NULL);
211     if(NULL == hWatchEvent)
212     {
213         goto __CLEANUP__;
214     }
215     pParam->ol.hEvent = hWatchEvent;
216     CWinThread* pThread = NULL;
217     HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
218     if(NULL == hEvent)
219     {
220         goto __CLEANUP__;
221     }
222     pParam->hEvent = hEvent;
223     MSG msg;
224     while(GetMessage(&msg, NULL, 0, 0))
225     {
226         switch(msg.message)
227         {
228         case MSG_STARTWATCH:
229             {
230                 HANDLE hFile = (HANDLE)(msg.wParam);
231                 PFN_NotifyAction pFn_NotifyAction = (PFN_NotifyAction)(msg.lParam);
232                 if((INVALID_HANDLE_VALUE == hFile) && (NULL == pFn_NotifyAction))
233                 {
234                     break;
235                 }
236                 if(NULL == pThread)
237                 {
238                     pParam->hFile = hFile;
239                     pParam->pFn_NotifyAction = pFn_NotifyAction;
240                     pThread = AfxBeginThread(DirectoryWatch, (LPVOID)pParam, 0, CREATE_SUSPENDED, NULL);
241                     if(NULL == pThread)
242                     {
243                         goto __CLEANUP__;
244                     }
245                     pThread->m_bAutoDelete = FALSE;
246                     pThread->ResumeThread();
247                 }                
248                 SetEvent(hEvent);
249             }
250             break;
251 
252         case MSG_STOPWATCH:
253             {
254                 ResetEvent(hEvent);
255             }
256             break;
257 
258         case MSG_EXITTHREAD:
259             {
260                 SetEvent(hEvent);
261                 pParam->bExit = FALSE;
262                 
263                 if((NULL != pThread) && (NULL != pThread->m_hThread))
264                 {
265                     WaitForSingleObject(pThread->m_hThread, INFINITE);
266                     delete pThread;
267                     pThread = NULL;
268                 }
269                 goto __CLEANUP__;
270             }
271             
272         default:
273             break;
274         }
275         TranslateMessage(&msg);
276         DispatchMessage(&msg);
277     }
278 
279 __CLEANUP__:
280     if(NULL != hWatchEvent)
281     {
282         CloseHandle(hWatchEvent);
283         hWatchEvent = NULL;
284     }
285     if(NULL != pBuffer)
286     {
287         delete[] pBuffer;
288         pBuffer = NULL;
289     }
290     if(NULL != pParam)
291     {
292         delete pParam;
293         pParam = NULL;
294     }
295     TRACE0("ThreadProc Thread Exit ...
");
296     return 0;
297 }
 1 // 测试代码
 2 
 3 #include "stdafx.h"
 4 
 5 #include "DirectoryWatch.h"
 6 
 7 void NotifyAction(DWORD dwAction, LPWSTR szFile, DWORD dwLength)
 8 {
 9     switch(dwAction)
10     {
11     case FILE_ACTION_ADDED:
12         wprintf(L"FILE_ACTION_ADDED: 
	");
13         break;
14 
15     case FILE_ACTION_REMOVED:
16         wprintf(L"FILE_ACTION_REMOVED: 
	");
17         break;
18 
19     case FILE_ACTION_MODIFIED:
20         wprintf(L"FILE_ACTION_MODIFIED: 
	");
21         break;
22 
23     case FILE_ACTION_RENAMED_OLD_NAME:
24         wprintf(L"FILE_ACTION_RENAMED_OLD_NAME: 
	");
25         break;
26 
27     case FILE_ACTION_RENAMED_NEW_NAME:
28         wprintf(L"FILE_ACTION_RENAMED_NEW_NAME: 
	");
29         break;
30 
31     default:
32         break;
33     }
34     WCHAR szPath[MAX_PATH] = {0};
35     wmemcpy(szPath, szFile, min(dwLength, MAX_PATH));
36     wprintf(L"%s
", szPath);
37 }
38 
39 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
40 {
41     CDirectoryWatch watch;
42     wprintf(L"Start Directory Watch ...
");
43     watch.StartDirectoryWatch(_T("F:\11"), NotifyAction);
44     Sleep(30 * 1000);    
45     watch.StopDirectoryWatch();
46     wprintf(L"Stop Directory Watch ...
");
47 
48     Sleep(10 * 1000);
49 
50     wprintf(L"Start Directory Watch ...
");
51     watch.StartDirectoryWatch(_T("F:\11"), NotifyAction);
52     Sleep(30 * 1000);    
53     watch.StopDirectoryWatch();
54     wprintf(L"Stop Directory Watch ...
");
55     Sleep(30 * 1000);
56     wprintf(L"Process Exit ...
");
57     return 0;
58 }

效果如下图所示:

[C++]使用ReadDirectoryChangesW API監控檔案系統的改變

[C++]使用ReadDirectoryChangesW API監控檔案系統的改變

在C++中若想要監控檔案系統改變有很多方法,可以用FindFirstChangeNotification取得檔案變更、或是Hook底層的API等方法來實現,這邊使用ReadDirectoryChangesW API來實現,該API使用前必須先加入Kernel32.lib。

image

並加入Windows.h的標頭檔

1 #include "Windows.h"

這些步驟做完後在程式中就可以看到ReadDirectoryChangesW API了,其函式原型如下:

 1 BOOL WINAPI ReadDirectoryChangesW(
 2   __in         HANDLE hDirectory,
 3   __out        LPVOID lpBuffer,
 4   __in         DWORD nBufferLength,
 5   __in         BOOL bWatchSubtree,
 6   __in         DWORD dwNotifyFilter,
 7   __out_opt    LPDWORD lpBytesReturned,
 8   __inout_opt  LPOVERLAPPED lpOverlapped,
 9   __in_opt     LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
10 );

該API必須帶入八個參數,hDirectory帶入的是要監控的目錄Handle、lpBuffer帶入的是用來回傳變動資料的空間、nBufferLength是lpBuffer空間的大小、bWatchSubtree是指定是否偵測子目錄、dwNotifyFilter是指定監控的目錄有哪些動作時需要通知、lpBytesReturned是用來回傳變動資料內含的長度、lpOverlapped可用來在非同步環境下使用重疊IO用、lpCompletionRoutine則是當監控完成或取消時所呼叫的回調函式。

其中dwNotifyFilter的值可設定的有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,詳細所代表的意義可參閱ReadDirectoryChangesW function

了解了函式原型後,就可以開始進入實際的使用。剛有提到說在ReadDirectoryChangesW API函式必須要帶入的第一個參數是要監控的目錄Handle,所以我們必須透過CreateFile API取得要監控的目錄Handle,像是下面這樣:

 1 HANDLE  hDirectoryHandle    = NULL;
 2 
 3 
 4 hDirectoryHandle = ::CreateFileA(
 5     file,                    
 6     FILE_LIST_DIRECTORY,                
 7     FILE_SHARE_READ                        
 8     | FILE_SHARE_WRITE
 9     | FILE_SHARE_DELETE,
10     NULL,                               
11     OPEN_EXISTING,                      
12     FILE_FLAG_BACKUP_SEMANTICS            
13     | FILE_FLAG_OVERLAPPED,
14     NULL);  
15 
16 if(hDirectoryHandle == INVALID_HANDLE_VALUE)
17     return;

取得監控的目錄Handle後,將其帶入ReadDirectoryChangesw API,順帶帶入像是回傳變動資料的Buffer空間、與要監控的變動類型等必要參數。像是下面這樣:

 1 int        nBufferSize            = 1024;
 2 char*    buffer                = new char[nBufferSize];
 3 DWORD dwBytes = 0;
 4 
 5 memset(buffer, 0, nBufferSize);
 6 
 7 if(!::ReadDirectoryChangesW(
 8     hDirectoryHandle,                        
 9     buffer,                                
10     nBufferSize,        
11     bIncludeSubdirectories,             
12     FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME,     
13     &dwBytes,                         
14     NULL,                    
15     NULL) || GetLastError() == ERROR_INVALID_HANDLE)
16 {
17     break;
18 }
19 
20 if(!dwBytes)
21 {
22     printf("Buffer overflow~~
");
23 }

這邊需注意到的是,若是變動的資料太多,提供的存儲空間不足以存放時,回傳的變動資料長度會是0,此時所有變動資料都會丟失。這樣的情況多半只會出在一瞬間大量的變動,可以增大存儲空間或是減少監控的變動類型,以減少回傳的資料量,避免溢位的發生。

若是運行沒發生問題,變動的資料會存放在當初塞進去的存儲空間,該空間的資料其實是FILE_NOTIFY_INFORMATION structure的型態存在,因此我們可將存儲空間的資料轉換成PFILE_NOTIFY_INFORMATION。裡面的Action是我們所關注的變動類型,FileName是變動的檔案名稱,檔案名稱的部分是沒有結尾符號的,必須要搭配FileNameLength去截取。另外變動的資料有時候不止一筆,因此我們必須在這邊用迴圈搭配NextEntryOffset去重覆運行處理流程,處理所有變動的資料。

 1 PFILE_NOTIFY_INFORMATION record = (PFILE_NOTIFY_INFORMATION)buffer;
 2 DWORD cbOffset = 0;
 3 
 4 do
 5 {    
 6     switch (record->Action)
 7     {
 8     case FILE_ACTION_ADDED:    
 9         printf("FILE_ACTION_ADDED:");
10         break;
11     case FILE_ACTION_REMOVED:
12         printf("FILE_ACTION_REMOVED:");
13         break;
14     case FILE_ACTION_MODIFIED:
15         printf("FILE_ACTION_MODIFIED:");
16         break;
17     case FILE_ACTION_RENAMED_OLD_NAME:
18         printf("FILE_ACTION_RENAMED_OLD_NAME:");                
19         break;
20 
21     case FILE_ACTION_RENAMED_NEW_NAME:
22         printf("FILE_ACTION_RENAMED_NEW_NAME:");
23         break;
24 
25     default:
26         break;
27     }        
28 
29     char fileBuffer[512];
30 
31     WideCharToMultiByte(CP_ACP, 0, record->FileName, record->FileNameLength, fileBuffer, record->FileNameLength, NULL, NULL);  
32     printf(fileBuffer);
33     printf("
");
34 
35     cbOffset = record->NextEntryOffset;
36     record = (PFILE_NOTIFY_INFORMATION)((LPBYTE) record + cbOffset);
37 }while(cbOffset);    
 

這邊示範一個簡易的使用範例,實際使用時最好還是搭配執行緒處理:

  1 // ConsoleApplication10.cpp : Defines the entry point for the console application.
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "Windows.h"
  6 
  7 void MonitorDir(char* file, bool bIncludeSubdirectories = false)
  8 {
  9     int        nBufferSize            = 1024;
 10     char*    buffer                = new char[nBufferSize];    
 11     HANDLE  hDirectoryHandle    = NULL;
 12 
 13 
 14     hDirectoryHandle = ::CreateFileA(
 15         file,                    
 16         FILE_LIST_DIRECTORY,                
 17         FILE_SHARE_READ                        
 18         | FILE_SHARE_WRITE
 19         | FILE_SHARE_DELETE,
 20         NULL,                               
 21         OPEN_EXISTING,                      
 22         FILE_FLAG_BACKUP_SEMANTICS            
 23         | FILE_FLAG_OVERLAPPED,
 24         NULL);  
 25 
 26     if(hDirectoryHandle == INVALID_HANDLE_VALUE)
 27         return;
 28 
 29     while(1)
 30     {
 31         DWORD dwBytes = 0;
 32 
 33         memset(buffer, 0, nBufferSize);
 34 
 35         if(!::ReadDirectoryChangesW(
 36             hDirectoryHandle,                        
 37             buffer,                                
 38             nBufferSize,        
 39             bIncludeSubdirectories,             
 40             FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME,     
 41             &dwBytes,                         
 42             NULL,                    
 43             NULL) || GetLastError() == ERROR_INVALID_HANDLE)
 44         {
 45             break;
 46         }
 47 
 48         if(!dwBytes)
 49         {
 50             printf("Buffer overflow~~
");
 51         }
 52         
 53         PFILE_NOTIFY_INFORMATION record = (PFILE_NOTIFY_INFORMATION)buffer;
 54         DWORD cbOffset = 0;
 55 
 56         do
 57         {    
 58             switch (record->Action)
 59             {
 60             case FILE_ACTION_ADDED:    
 61                 printf("FILE_ACTION_ADDED:");
 62                 break;
 63             case FILE_ACTION_REMOVED:
 64                 printf("FILE_ACTION_REMOVED:");
 65                 break;
 66             case FILE_ACTION_MODIFIED:
 67                 printf("FILE_ACTION_MODIFIED:");
 68                 break;
 69             case FILE_ACTION_RENAMED_OLD_NAME:
 70                 printf("FILE_ACTION_RENAMED_OLD_NAME:");                
 71                 break;
 72 
 73             case FILE_ACTION_RENAMED_NEW_NAME:
 74                 printf("FILE_ACTION_RENAMED_NEW_NAME:");
 75                 break;
 76 
 77             default:
 78                 break;
 79             }        
 80 
 81             char fileBuffer[512];
 82 
 83             WideCharToMultiByte(CP_ACP, 0, record->FileName, record->FileNameLength, fileBuffer, record->FileNameLength, NULL, NULL);  
 84             printf(fileBuffer);
 85             printf("
");
 86 
 87             cbOffset = record->NextEntryOffset;
 88             record = (PFILE_NOTIFY_INFORMATION)((LPBYTE) record + cbOffset);
 89         }while(cbOffset);        
 90     }
 91 
 92     delete buffer;
 93 
 94     if(hDirectoryHandle)
 95         CloseHandle(hDirectoryHandle);
 96 }
 97 
 98 int _tmain(int argc, _TCHAR* argv[])
 99 {
100     MonitorDir("C:\Users\larry\Desktop\新增資料夾");
 

運行後去對監控的目錄操作~可得到類似如下的結果:

image

原文地址:https://www.cnblogs.com/chechen/p/5288444.html