ReadDirectoryChangesW拒绝CreateIoCompletionPort接受的HANDLE

时间:2016-10-22 14:42:40

标签: c++ winapi

我正在为我的(基于Qt的)应用程序添加功能,以便在我的Windows系统上监视任何活动的任意文件夹(Qt变体QFileSystemWatcher缺少的东西)。使用 CreatFileW()打开文件夹后,我创建一个完成端口以接收重叠的I / O,然后使用 ReadDirectoryChangesW()对读取进行排队。

我已将所有这些放在下面的“简单”Win32控制台应用程序中进行演示(请注意,“stdafx.h”标题已被修改为包含“windows.h”,但在其他方面是Visual Studio 2013 IDE生成它):

#include "stdafx.h"

#define MAX_BUFFER 4096

struct ThreadData
{;
    DWORD           winerr;
    HANDLE          handle;
    unsigned int    flags;
    int             recursive;
    HANDLE          completion_port;
    CHAR            buffer[MAX_BUFFER];
    DWORD           buffer_len;
    OVERLAPPED      overlapped;
};

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD winerr;
    ThreadData td;

    td.flags = FILE_NOTIFY_CHANGE_FILE_NAME|
               FILE_NOTIFY_CHANGE_DIR_NAME|
               FILE_NOTIFY_CHANGE_ATTRIBUTES|
               FILE_NOTIFY_CHANGE_SIZE|
               FILE_NOTIFY_CHANGE_LAST_WRITE|
               FILE_NOTIFY_CHANGE_LAST_ACCESS|
               FILE_NOTIFY_CHANGE_CREATION|
               FILE_NOTIFY_CHANGE_SECURITY;
    td.recursive = 1;
    td.completion_port = INVALID_HANDLE_VALUE;
    td.handle = INVALID_HANDLE_VALUE;

    td.handle = CreateFileW(L"J:\\Font",         // arbitrary folder
                            FILE_LIST_DIRECTORY, // required
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            NULL,
                            OPEN_EXISTING,
                            // Use FILE_FLAG_OVERLAPPED for asynchronous operation with ReadDirectoryChangesW.
                            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                            NULL);

    if(td.handle == INVALID_HANDLE_VALUE)
    {
        winerr = GetLastError();
        CloseHandle(td->handle);
        return 0;
    }

    td.completion_port = CreateIoCompletionPort(td.handle,
                                                td.completion_port,
                                                (ULONG_PTR)td,
                                                0);    // max num processors
    if(td.completion_port == INVALID_HANDLE_VALUE)
    {
        winerr = GetLastError();
        CloseHandle(td.completion_port);
        CloseHandle(td.handle);
        return 0;
    }

    BOOL rdc = ReadDirectoryChangesW(td.handle,
                                     td.buffer,    // read results
                                     MAX_BUFFER,
                                     td.recursive, // watch subdirectories
                                     // NOTE: At least one flag is required!
                                     td.flags,     // see Notify Filters below
                                     &td.buffer_len,
                                     &td.overlapped,
                                     NULL);         // completion routine
    if(rdc == 0)
    {
        winerr = GetLastError();     // "The handle is invalid. (0x6)"
        CloseHandle(td.completion_port);
        CloseHandle(td.handle);
        return 0;
    }

    // Launch thread here to handle completions and trigger new ones
    ...

    // Clean up when the thread is done
    CloseHandle(td.completion_port);
    CloseHandle(td.handle);

    return 0;
}

关于这段代码需要注意的是,它是在用C语言编写的Python模块(“watcher”)之后建模的,它提供了与Python环境类似的功能。我在Python中使用它,并且它在预期的情况下与此C ++片段中的所有相同设置一起工作。

在上面的代码中, CreateIoCompletionPort()接受由 CreateFileW()生成的HANDLE,但 ReadDirectoryChangesW()则不接受。它返回0, GetLastError()返回“句柄无效。(0x6)”。我在32位和64位编译下都试过这个,以防万一(我使用的是64位版本的Python)。此外,指定的目录似乎不重要:我指定的所有目录产生相同的结果,这表明它在某处设置有问题。

CreateFileW()调用中是否存在可能导致HANDLE生成完成端口有效的内容,但是会给 ReadDirectoryChangesW()函数设置胃灼热?

2 个答案:

答案 0 :(得分:3)

您没有正确初始化I / O完成端口,并且您根本没有初始化OVERLAPPED结构。 ReadDirectoryChangesW()失败,因为OVERLAPPED::hEvent字段包含无效的事件对象句柄。这是错误代码所指的无效句柄,而不是目录句柄。

请改为尝试:

#include "stdafx.h"

#define MAX_BUFFER 4096

struct ThreadData
{
    DWORD           winerr;
    HANDLE          handle;
    DWORD           flags;
    BOOL            recursive;
    HANDLE          completion_port;
    CHAR            buffer[MAX_BUFFER];
    DWORD           buffer_len;
    OVERLAPPED      overlapped;
};

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD winerr;
    ThreadData td;

    td.flags = FILE_NOTIFY_CHANGE_FILE_NAME|
               FILE_NOTIFY_CHANGE_DIR_NAME|
               FILE_NOTIFY_CHANGE_ATTRIBUTES|
               FILE_NOTIFY_CHANGE_SIZE|
               FILE_NOTIFY_CHANGE_LAST_WRITE|
               FILE_NOTIFY_CHANGE_LAST_ACCESS|
               FILE_NOTIFY_CHANGE_CREATION|
               FILE_NOTIFY_CHANGE_SECURITY;
    td.recursive = TRUE;
    td.completion_port = NULL;
    td.handle = CreateFileW(L"J:\\Font",         // arbitrary folder
                            FILE_LIST_DIRECTORY, // required
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            NULL,
                            OPEN_EXISTING,
                            // Use FILE_FLAG_OVERLAPPED for asynchronous operation with ReadDirectoryChangesW.
                            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                            NULL);

    if(td.handle == INVALID_HANDLE_VALUE)
    {
        winerr = GetLastError();
        return 0;
    }

    td.completion_port = CreateIoCompletionPort(td.handle,
                                                NULL,
                                                (ULONG_PTR)&td,
                                                0);    // max num processors
    if(td.completion_port == NULL)
    {
        winerr = GetLastError();
        CloseHandle(td.handle);
        return 0;
    }

    ZeroMemory(&td.overlapped, sizeof(td.overlapped)); // <-- add this!

    // required if the thread uses GetOverlappedResult()...
    // optional if the thread uses GetQueuedCompletionStatus()...
    /*
    td.overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if(td.overlapped.hEvent == NULL)
    {
        winerr = GetLastError();
        CloseHandle(td.completion_port);
        CloseHandle(td.handle);
        return 0;
    }
    */

    BOOL rdc = ReadDirectoryChangesW(td.handle,
                                     td.buffer,    // read results
                                     MAX_BUFFER,
                                     td.recursive, // watch subdirectories
                                     // NOTE: At least one flag is required!
                                     td.flags,     // see Notify Filters below
                                     &td.buffer_len,
                                     &td.overlapped,
                                     NULL);         // completion routine
    if(rdc == FALSE)
    {
        winerr = GetLastError();
        //CloseHandle(td.overlapped.hEvent);
        CloseHandle(td.completion_port);
        CloseHandle(td.handle);
        return 0;
    }

    // Launch thread here to handle completions and trigger new ones
    ...

    // Clean up when the thread is done
    //CloseHandle(td.overlapped.hEvent);
    CloseHandle(td.completion_port);
    CloseHandle(td.handle);

    return 0;
}

答案 1 :(得分:1)

错误时

CreateIoCompletionPort会返回NULL,而不是INVALID_HANDLE_VALUE。所以你的第一个错误是在这一行:

 td.completion_port = INVALID_HANDLE_VALUE;

一定是这样:

 td.completion_port = NULL;

这个错误的检查:

if(td.completion_port == INVALID_HANDLE_VALUE)

必须是这样:

if(td.completion_port == NULL)

NULL之后,td.completion_port中的CreateIoCompletionPort得到td.completion_port,因为facebookConnectPlugin.login(['email', 'public_profile', 'user_friends'], //first argument is an array of scope permissions function (userData) { if (userData.authResponse) { facebookConnectPlugin.api('me/?fields=email,name,first_name,last_name', ["public_profile"], function (inforesult) { facebookConnectPlugin.getAccessToken(function (token) { //alert("Token: " + token); var credential = firebase.auth.FacebookAuthProvider.credential(token); firebase.auth().signInWithCredential(credential).then(function (result) { alert(JSON.stringify(result)); // the email field is null. $scope.myprofile = result; }).catch(function (error) { // Handle Errors here. alert(error.message); / ... }); }); }); } }, function (error) { alert(error); } ) 的初始值无效。此外,您错误地处理错误情况(例如尝试关闭无效句柄)。