2011-07-27 3 views
6

다음은 ReadDirectoryChangesW을 사용하는 최소 프로그램입니다. 내가 가지고있는 문제는 GetQueuedCompletionStatus에 대한 첫 번째 호출 만 반환한다는 것입니다. 루프를 통해 두 번째로 그것은 얼마나 많은 변경이 디렉토리에 만들어 지더라도 영원히 차단합니다.ReadDirectoryChangesW를 호출 할 때 첫 번째 호출 만 변경 사항을 반환합니다 (동기화 및 비동기 모두)

또한 동기식 버전을 사용하려고했는데 똑같은 문제가 있습니다.

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

} 

답변

5

몇 가지 문제가 있습니다.

먼저 멀티 바이트 문자열 리터럴을 wcout으로 출력하려고합니다.

두 번째로, FileNameLength 변수는 문자의 길이가 아니라 문자의 길이를 바이트 단위로 나타냅니다. 문자 수를 얻으려면 2로 나누어야합니다.

+0

고마워요. –

0

어떻게 컴파일하나요? Visual Studio를 사용하면 GetQueuedCompletionStatus의 세 번째 매개 변수가 잘못 입력되어 컴파일되지 않습니다. 매개 변수는 ULONG에 대한 포인터가 아닌 ULONG에 대한 포인터에 대한 포인터 여야합니다. "키"변수의 선언을

으로 변경했을 때

ULONG_PTR 키;

프로그램이 올바르게 작동합니다.

+0

VS2010을 사용하고 있습니다. 그 변화는 문제를 해결하지 못했습니다. –

0

fni-> FileNameLength가 문자가 아닌 바이트 단위이기 때문에 인쇄 논리로 인해 버퍼 오버런이 발생합니다. 무작위 메모리 손상은 왜 내가 다른 결과를 얻었는지 설명합니다.

수정이 간단하다 :

표준 : 파일명 wstring을 (fni-> 파일명 fni-> 파일 이름 + fni-> FileNameLength/sizoeof (fni-> 파일 이름 [0]));