Использование readdirectorychangesw асинхронно в цикле
ВСТУПЛЕНИЕ:
Я пытаюсь использовать ReadDirectoryChangesW[^] асинхронно в цикле.
Ниже фрагмент иллюстрирует то, чего я пытаюсь достичь:
DWORD example() { DWORD error = 0; OVERLAPPED ovl = { 0 }; ovl.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == ovl.hEvent) return ::GetLastError(); char buffer[1024]; while(1) { foo(); error = ::ReadDirectoryChangesW( m_hDirectory, // I have added FILE_FLAG_OVERLAPPED in CreateFile buffer, sizeof(buffer), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl, NULL); // we have something, process it if(error) processBuffer(buffer); // continue with the loop so foo() can be executed else if(error == ERROR_IO_PENDING) continue; // RDCW error else return ::GetLastError(); } }
ПРОБЛЕМА:
Я не знаю, как справиться с этим случаем, когда
ReadDirectoryChangesW
возвращается FALSE
с GetLastError()
код бытия ERROR_IO_PENDING
.В этом случае я должен просто продолжить цикл и продолжать цикл до тех пор, пока
ReadDirectoryChangesW
возвращается buffer
Я могу это осмыслить.ВОПРОС:
Поскольку приведенный ниже MVCE очень хорошо иллюстрирует то, что я пытаюсь сделать (напечатать имена вновь добавленных файлов), не могли бы вы показать мне, что должно быть исправлено в цикле while, чтобы он работал?
Опять же, смысл состоит в том, чтобы использовать ReadDirectoryChangesW асинхронно, в цикле, как показано во фрагменте из введения.
Что я уже пробовал:
Я пробовал использовать
WaitForSingleObject(ovl.hEvent, 1000)
но он выходит из строя с ошибкой 1450 ERROR_NO_SYSTEM_RESOURCES
. Ниже приведен MVCE, который воспроизводит это поведение:
#include <iostream> #include <windows.h> DWORD processDirectoryChanges(const char *buffer) { DWORD offset = 0; char fileName[MAX_PATH] = ""; FILE_NOTIFY_INFORMATION *fni = NULL; do { fni = (FILE_NOTIFY_INFORMATION*)(&buffer[offset]); // since we do not use UNICODE, // we must convert fni->FileName from UNICODE to multibyte int ret = ::WideCharToMultiByte(CP_ACP, 0, fni->FileName, fni->FileNameLength / sizeof(WCHAR), fileName, sizeof(fileName), NULL, NULL); switch (fni->Action) { case FILE_ACTION_ADDED: { std::cout << fileName << std::endl; } break; default: break; } ::memset(fileName, '\0', sizeof(fileName)); offset += fni->NextEntryOffset; } while (fni->NextEntryOffset != 0); return 0; } int main() { HANDLE hDir = ::CreateFile("C:\\Users\\nenad.smiljkovic\\Desktop\\test", FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == hDir) return ::GetLastError(); OVERLAPPED ovl = { 0 }; ovl.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == ovl.hEvent) return ::GetLastError(); DWORD error = 0, br; char buffer[1024]; while (1) { error = ::ReadDirectoryChangesW(hDir, buffer, sizeof(buffer), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl, NULL); if (0 == error) { error = ::GetLastError(); if (ERROR_IO_PENDING != ::GetLastError()) { ::CloseHandle(ovl.hEvent); ::CloseHandle(hDir); return error; } } error = ::WaitForSingleObject(ovl.hEvent, 0); switch (error) { case WAIT_TIMEOUT: break; case WAIT_OBJECT_0: { error = processDirectoryChanges(buffer); if (error > 0) { ::CloseHandle(ovl.hEvent); ::CloseHandle(hDir); return error; } if (0 == ::ResetEvent(ovl.hEvent)) { error = ::GetLastError(); ::CloseHandle(ovl.hEvent); ::CloseHandle(hDir); return error; } } break; default: error = ::GetLastError(); ::CloseHandle(ovl.hEvent); ::CloseHandle(hDir); return error; break; } } return 0; }
Читая документацию, мне кажется, что мне нужно GetOverlappedResult[^] с последним параметром, установленным в
FALSE
но я не знаю, как правильно использовать этот API.