6

以下は、 を使用する最小限のプログラムReadDirectoryChangesWです。私が抱えている問題は、最初の呼び出しだけがGetQueuedCompletionStatus返されることです。2 回目のループでは、ディレクトリに何回変更が加えられても、永久にブロックされます。

私も同期バージョンを使用しようとしましたが、まったく同じ問題があります。

#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;
    }
  }

}
4

3 に答える 3

5

いくつかの問題。

まず、マルチバイト文字列リテラルを に出力しようとしていますwcout。L を先頭に追加して、幅の広い文字列に変換する必要があります。

次に、FileNameLength変数は名前の長さを文字数ではなくバイト数で表します。文字数を得るには、これを 2 で割る必要があります。

于 2011-07-27T22:34:10.083 に答える
0

これをどのようにコンパイルしていますか?GetQueuedCompletionStatus の 3 番目のパラメーターが正しく入力されていないため、Visual Studio を使用するとコンパイルに失敗します。このパラメーターは、ULONG へのポインターではなく、ULONG へのポインターへのポインターである必要があります。「キー」変数の宣言を

ULONG_PTR キー;

プログラムは正しく動作します。

于 2011-07-27T21:47:16.987 に答える
0

問題は、fni->FileNameLength が文字単位ではなくバイト単位であるため、印刷ロジックがバッファ オーバーランを引き起こしていることです。ランダムなメモリ破損は、私があなたとは異なる結果を得た理由を説明します.

修正はこれだけです:

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

于 2011-07-27T23:26:32.260 に答える