我意识到发布代码墙通常被认为是可怕的,但这是我如何实现这一点的:
新结构:
BOOL runthread;
typedef struct overlapped_struct
{
OVERLAPPED overlapped;
wchar_t* buffer;
} overlapped_t;
typedef struct dirinfo_struct
{
HANDLE hDirOPPort;
HANDLE hDirFH;
overlapped_t* o;
int len_buffer;
wchar_t* buffer;
wchar_t* directory_name;
ULONG_PTR CompletionKey;
} dirinfo_t;
int somekey = 1;
分配方式:
void dirinfo_init(dirinfo_t* t)
{
t->buffer = malloc(16777216*sizeof(wchar_t));
t->len_buffer = 16777216;
t->o = calloc(1, sizeof(overlapped_t));
t->o->buffer = calloc(16777216, sizeof(wchar_t));
memset(t->o->buffer, 0, 16777216);
memset(t->o, 0, sizeof(OVERLAPPED));
}
void dirinfo_free(dirinfo_t* t)
{
free(t->buffer);
free(t->o->buffer);
free(t->o);
free(t);
}
重要的东西来自main()
做这个:
dirinfo_t* d = malloc(1*sizeof(dirinfo_t));
d->CompletionKey = (ULONG_PTR)&somekey;
dirinfo_init(d);
/* set up */
runthread = TRUE;
d->hDirFH = CreateFile(L"C:\\hydratest",
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
d->hDirOPPort = CreateIoCompletionPort(d->hDirFH, NULL,
(ULONG_PTR)d->CompletionKey, 1);
最后是我的等待线程。关键是:我没有传递重叠的结构。我传递的结构包含OVERLAPPED
加上相当数量的wchar_t
基于存储。由于我不完全理解的原因,这有效。Edit see 这个答案。我相信这里的数据区域充当重叠缓冲区。
DWORD WINAPI WaitingThread(void* args)
{
DWORD errorcode = 0; // an error code
BOOL bResultQ = FALSE; // obvios=us
BOOL bResultR = FALSE;
DWORD NumBytes = 0;
FILE_NOTIFY_INFORMATION* pInfo = NULL; // the data incoming is a pointer
// to this struct.
int i = 0;
dirinfo_t* d = (dirinfo_t*) args; // rescue struct from thread arg.
然后我们进入主线程本身。试验和错误表明您应该同时调用 ReadDirectoryW 和 GetQueueCompletionStatus。I think这意味着我们不应该接触缓冲区ReadDirectoryChangeW
**除非*我们被告知我们可以GetQueue
。不过,欢迎对该假设进行更正。
while ( runthread )
{
bResultR = ReadDirectoryChangesW(d->hDirFH, (void*)d->buffer,
16777216, TRUE,
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,
NULL,
&d->o->overlapped,
NULL );
bResultQ = GetQueuedCompletionStatus(d->hDirOPPort,
&NumBytes, &(d->CompletionKey),
(LPOVERLAPPED*)(d->o), 1000);
所以,现在我们已经调用了这些函数,我们then测试它们都返回 true。丑陋的大警告如果你的参数设置正确bResultR
总是返回 true,至少在我看来是这样。bResultQ
然而,根据端口上是否有新数据而有所不同。
if ( bResultQ && bResultR )
{
所以在这里我们从ReadDirectoryChangesW
并从结构中访问信息。
wprintf(L"\n");
pInfo = (FILE_NOTIFY_INFORMATION*) d->buffer;
wprintf(L"File %s", pInfo->FileName);
wprintf(L" changes %d\n", pInfo->Action);
memset(d->buffer, 0, 16777216);
}
否则,并且感谢托尼,您可以安全地忽略 WAIT_TIMEOUT 错误,但其他任何情况都可能意味着您遇到了麻烦。
else
{
errorcode = GetLastError();
if ( errorcode == WAIT_TIMEOUT )
{
printf("GetQueuedCompletionStatus(): Timeout\n");
}
else
{
printf("GetQueuedCompletionStatus(): Failed\n");
printf("Error Code %d\n", errorcode);
}
Sleep(500);
}
}
return 0;
}
这完成了我认为是一个有效的示例。
一些注意事项:
- 我已将缓冲区大小设置得很大。我注意到复制了 100 个文件左右,导致缓冲区空间不足,设置为
8192
并到处漏掉一两件事。所以我不指望这总是能解决所有问题。我的解决方案是每 100 个事件,验证文件树是否是您认为使用此方法时的情况。然而,一个无限更好的解决方案是不断枚举潜在的大树。