When calling ReadDirectoryChangesW, only the first call returns any changes (both synchronize and asynchronously)

The following is a minimal program that uses ReadDirectoryChangesW . The problem I am facing is that only the first call to GetQueuedCompletionStatus . The second time through the loop, it is blocked forever, regardless of how many changes are made to the directory.

I also tried using the synchronous version and have the same problem.

 #include <array> #include <cassert> #include <iostream> #include <Windows.h> int main() { // Open the directory to monitor. HANDLE dir = ::CreateFileA( "G:\\Program Files (x86)\\Steam\\steamapps\\common\\eve online" , FILE_LIST_DIRECTORY , FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , NULL , OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED , NULL ); if (dir == INVALID_HANDLE_VALUE) { std::cout << "Failed to open directory for change notifications!\n"; return 1; } // Setup IOCP. HANDLE iocp = ::CreateIoCompletionPort( dir , NULL , NULL , 1 ); // Monitor. while (true) { std::array<char, 1024 * 8> buf; DWORD bytes_read; OVERLAPPED overlapped; std::memset(&overlapped, 0, sizeof(overlapped)); BOOL result = ::ReadDirectoryChangesW( dir , &buf.front() , buf.size() , false , FILE_NOTIFY_CHANGE_FILE_NAME // Includes file creation. , &bytes_read , &overlapped , NULL ); if (result == FALSE) { DWORD error = ::GetLastError(); std::cout << "Call to ReadDirectoryChangesW failed! " << error << "\n"; return 1; } // Wait for completion. ULONG_PTR key; LPOVERLAPPED overlapped_result; result = ::GetQueuedCompletionStatus( iocp , &bytes_read , &key , &overlapped_result , INFINITE ); if (result == FALSE) { std::cout << "Call to GetQueuedCompletionStatus failed!\n"; return 1; } // Print results! for (FILE_NOTIFY_INFORMATION *fni = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(&buf.front()); ; fni = reinterpret_cast<FILE_NOTIFY_INFORMATION *>( reinterpret_cast<char *>(fni) + fni->NextEntryOffset)) { std::wstring filename(fni->FileName, fni->FileName + fni->FileNameLength); std::wcout << "Got change: " << filename.c_str() << "\n"; if (fni->NextEntryOffset == 0) break; } } } 
+6
source share
3 answers

A few problems.

First you try to output multibyte string literals to wcout . You have to turn them into wide strings by adding L.

Secondly, the FileNameLength variable represents the name length in bytes, not characters. You must divide it by 2 to get the number of characters.

+5
source

How do you compile this? Using Visual Studio cannot be compiled because the third parameter GetQueuedCompletionStatus was entered incorrectly. The parameter must be a pointer to a pointer to ULONG, not a pointer to ULONG. When I changed the declaration of the variable "key" to

ULONG_PTR key;

programs work correctly.

0
source

The problem is that your print logic causes a buffer overflow because fni-> FileNameLength is in bytes, not characters. Damage to random memory explains why I got different results than you.

The fix is ​​as follows:

std :: wstring filename (fni-> FileName, fni-> FileName + fni-> FileNameLength / sizoeof (fni-> FileName [0]));

0
source

Source: https://habr.com/ru/post/893721/


All Articles