Obtaining Directory Change Notifications
Obtaining Directory Change Notifications
About APIs, you can go to this link: http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx
Note following items extracted from MSDN:
1. The wait functions can monitor the specified directory or subtree by using the handle returned by the FindFirstChangeNotification function. A wait is satisfied when one of the filter conditions occurs in the monitored directory or subtree.
2. After the wait has been satisfied, the application can respond to this condition and continue monitoring the directory by calling the FindNextChangeNotification function and the appropriate wait function. When the handle is no longer needed, it can be closed by using the FindCloseChangeNotification function.
3. This function does not indicate the change that satisfied the wait condition. To retrieve information about the specific change as part of the notification, use the ReadDirectoryChangesW function.
To read the changes, we can use a WIN32_FIND_DATA list to keep the old attributes of the directory.
1. Adding the specified folder to monitor queue
void CFileMonitor::Add(const _bstr_t &file) { CFileMonitor *pThis = new CFileMonitor(file); //Reading files in the directory pThis->RefreshDirectory(FALSE); pThis->SetChange(::FindFirstChangeNotification( path, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE )); if (pThis->GetChange() == INVALID_HANDLE_VALUE) { delete pThis; return; } DWORD ThreadId; HANDLE ht = ::CreateThread( NULL, 0, CFileMonitor::ThreadAdd, pThis, 0, &ThreadId); if (ht == NULL) delete pThis; else ::CloseHandle(ht); } |
2. In thread Add, wait and capture the change notification
DWORD WINAPI CFileMonitor::ThreadAdd(LPVOID lpParameter) { CFileMonitor *pThis = (CFileMonitor *)lpParameter; DWORD rc; do { //TODO: I should have a timeout value rc = ::WaitForSingleObject(pThis->GetChange(), INFINITE); // take new snap shot of directory and get notification of changes pThis->RefreshDirectory(); } while(!pThis->IsAdded() && rc == WAIT_OBJECT_0); // cleanup delete pThis; return 0; } |
3. Compare the items
void CFileMonitor::RefreshDirectory(BOOL bNotify /* default is TRUE */) { if (m_path.length() == 0) return; // find all the files that match the path spec int count = 0; WIN32_FIND_DATA *pFindArray = NULL; WIN32_FIND_DATA FindFileData; HANDLE hFind = ::FindFirstFile(m_path, &FindFileData); BOOL more = hFind != INVALID_HANDLE_VALUE; while(more) { if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) // skip directories { // allocate a new entry in this snap shot (pFinDArray) count++; pFindArray = (WIN32_FIND_DATA *)realloc(pFindArray, count * sizeof(*pFindArray)); // add this file to the new snap shot memcpy(pFindArray + count - 1, &FindFileData, sizeof(*pFindArray)); if (bNotify) { DWORD fcs = GetFileStatus(m_pFindArray, m_count, FindFileData); if (fcs != FILE_CHANGE_NONE) OnFileChange(FindFileData, fcs); } } more = ::FindNextFile(hFind, &FindFileData); } if (m_pFindArray) free(m_pFindArray); m_pFindArray = pFindArray; m_count = count; } |