我有一些代码永远不会调用回调,即使我复制、更改或删除 C:\Temp 中的文件也是如此。我究竟做错了什么? 它似乎停留在 WaitForSingleObject 并且根本不调用 DirectoryChangeCallback。
StackOverflow 要求我添加更多细节,因为我的问题主要是代码,所以我在这里多写一些。该程序应该易于理解且完整,因此在您尝试时应该会运行。
#include <windows.h>
#include <wininet.h>
#include <shlwapi.h>
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "shlwapi.lib")
#include <string>
VOID CALLBACK DirectoryChangeCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
ASSERT(FALSE); // program never comes here
}
int main() {
std::wstring path = L"C:\\Temp";
// Set up a directory change notification
HANDLE hDirectory = CreateFileW(path.c_str()
, GENERIC_READ
, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
, NULL);
if(hDirectory == INVALID_HANDLE_VALUE) {
// Handle error
return 1;
}
BYTE buffer[4096]; // Buffer to receive notification information
DWORD dwBytesReturned;
OVERLAPPED overlapped= {};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(overlapped.hEvent == NULL) {
// Handle error
CloseHandle(hDirectory);
return 1;
}
// Start monitoring for changes
DWORD dwNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE /*FILE_NOTIFY_CHANGE_SECURITY| FILE_NOTIFY_CHANGE_ATTRIBUTES*/;
if(!ReadDirectoryChangesW(hDirectory, buffer, sizeof(buffer), TRUE/*subtree*/, dwNotifyFilter, NULL, &overlapped, DirectoryChangeCallback)) {
if(GetLastError() != ERROR_IO_PENDING) {
// Handle error
CloseHandle(overlapped.hEvent);
CloseHandle(hDirectory);
return 1;
}
}
// Wait for changes and process notifications in the callback function
wprintf(L"Wait for single object\n");
DWORD dwWaitResult = WaitForSingleObject(overlapped.hEvent, INFINITE); // *** STUCK HERE ***
wprintf(L"result %d\n", int(dwWaitResult));
// Clean up resources
CloseHandle(overlapped.hEvent);
CloseHandle(hDirectory);
return 0;
}
正如@RbMm所说,您对CreateFileW的使用与ReadDirectoryChangesW的使用不匹配。
ReadDirectoryChangesW函数中也提到了三种异步方式,但没有一种与代码相同。
- 使用 GetOverlappedResult 函数。要通过 GetOverlappedResult 接收通知,请不要在
中指定完成例程 lpCompletionRoutine 参数。一定要设置 hEvent 成员
OVERLAPPED 结构到一个独特的事件。- 使用 GetQueuedCompletionStatus 函数。要通过 GetQueuedCompletionStatus 接收通知,请不要指定 lpCompletionRoutine 中的完成例程。关联目录 通过调用
来处理带有完成端口的 hDirectory CreateIoCompletionPort 函数。- 使用完成例程。要通过完成例程接收通知,请不要将目录与完成相关联
港口。在 lpCompletionRoutine 中指定完成例程。这
每当操作完成或
当线程处于可警告等待状态时取消。事件
OVERLAPPED 结构的成员没有被系统使用,所以你
可以自己用。
异步示例:CloudMirror
同步示例:fileserviceservice