Я понимаю, что публикация стен кода, как правило, считается ужасной, но вот как я это сделал:
Новые структуры:
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
хранилища. По причинам, которые я не до конца понимаю, это работает. Редактировать см. этот ответ . Я считаю, что область данных здесь действует как перекрывающийся буфер.
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. Я думаю , что это значит, что мы не должны касаться буфера с 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);
Итак, теперь мы вызвали эти функции, мы затем проверяем, что они оба вернули 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 событий, проверить, что дерево файлов это то, что вы думаете, используя этот метод. Однако бесконечно лучшее решение для постоянного перечисления потенциально большого дерева.