1

I've managed to use ReadDirectoryChangesW synchronously, but when I attempt to use completion ports, ReadDirectoryChangesW always returns ERROR_INVALID_PARAMETER. I guess there should be some obvious error in my code, but I cannot figure it.

My code is based on How to use ReadDirectoryChangesW() method with completion routine?

   const wchar_t *directory = L"X:\\X";
   HANDLE h = CreateFile(
      directory,
      FILE_LIST_DIRECTORY,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_EXISTING, 
      FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL);

   if (h==INVALID_HANDLE_VALUE) return;

   HANDLE p = CreateIoCompletionPort(h,0,0,1);
   if (p==NULL) {CloseHandle(h); return;}

   DWORD *buffer =new DWORD[4096];
   DWORD bytesReturned;

   DWORD notifyFilter =  FILE_NOTIFY_CHANGE_FILE_NAME 
                      | FILE_NOTIFY_CHANGE_DIR_NAME 
                      | FILE_NOTIFY_CHANGE_SIZE 
                      | FILE_NOTIFY_CHANGE_LAST_WRITE;

   while (true) {

       OVERLAPPED overlapped;
       memset(&overlapped,0,sizeof(overlapped));

       BOOL success = ReadDirectoryChangesW(h,
            &buffer[0],            
            4096*sizeof(DWORD),
            FALSE, notifyFilter,
            NULL, //&bytesReturned,
            &overlapped,myFileIOCompletionRoutine);

       if (!success) {    
          //always ERROR_INVALID_PARAMETER       
          CloseHandle(h);
          CloseHandle(p);
          return;
       }       
    }
Community
  • 1
  • 1
Javier
  • 12,100
  • 5
  • 46
  • 57
  • You didn't show notifyFilter and myFileIOCompletionRoutine definitions. – Alex F Dec 17 '13 at 15:43
  • 1
    CreateIoCompletionPort returns NULL if fails, your test is incorrect. Maybe CreateIoCompletionPort fails? – Alex F Dec 17 '13 at 15:50
  • @AlexFarber, thanks for pointing out it, but CreateIoCompletionPort returns a valid handle. – Javier Dec 17 '13 at 15:55
  • @AlexFarber I added the declaration of notifyFilter. myFileIOCompletionRoutine currently does nothing, i.e. `{}` – Javier Dec 17 '13 at 15:58
  • 2
    Important note in the MSDN Library article: `To receive notification through a completion routine, do **not** associate the directory with a completion port.` You are helping to much, delete the CreateIoCompletionPort() call. – Hans Passant Dec 17 '13 at 16:54
  • @HansPassant thank you very much. It works now after I removed the CompletionRoutine. – Javier Dec 17 '13 at 18:10

1 Answers1

1

As Hans Passant kindly reminds, the documentation already says that a completion routine must not be used if the directory is associated to a completion port. In this case I solved the problem by waiting on the completion port, i.e. ReadDirectoryChangesW(...,&overlapped,0);

Complete code is below.

while (true) {
    OVERLAPPED overlapped;
    memset(&overlapped,0,sizeof(overlapped));
    BOOL success = ReadDirectoryChangesW(h,
            &buffer[0],
            4096*sizeof(DWORD),
            FALSE, notifyFilter, 0, &overlapped,0);

    if (!success) {
      if (GetLastError()==ERROR_INVALID_HANDLE) {
        //asynchronously closed by cancel
        CloseHandle(p); //close completion port
        return 0;
      } else {
        CloseHandle(h); //close directory handle
        CloseHandle(p); //close completion port
        return 1;
      }
    }

    DWORD di;
    LPOVERLAPPED lpOverlapped;
    if (!GetQueuedCompletionStatus(p,&bytesReturned,&di,&lpOverlapped,1000)) {
        int ret;
        if (GetLastError()==WAIT_TIMEOUT) {
            if (GetFileAttributes(directory)!=INVALID_FILE_ATTRIBUTES) {
                continue; //timeout
            } else {
                //directory has been deleted or renamed
                ret=0;
            }
        } else {
            //other failure
            ret=1;
        }
        CloseHandle(h); //close directory handle
        CloseHandle(p); //close completion port
        return ret;
    }

    char* ptr = (char*)&buffer[0];
    char* end = ptr+bytesReturned;
    while (ptr<end) {
      FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*) ptr;
      //process FILE_NOTIFY_INFORMATION
      ptr+=info->NextEntryOffset;
      if (!info->NextEntryOffset) break;
    }
  }
Javier
  • 12,100
  • 5
  • 46
  • 57