首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果之前调用了ReadDirectoryChangesW,则CancelIo将失败,错误为995。

如果之前调用了ReadDirectoryChangesW,则CancelIo将失败,错误为995。
EN

Stack Overflow用户
提问于 2017-08-18 15:39:28
回答 1查看 416关注 0票数 0

我对ReadDirectoryChangesW错误995失败的奇怪行为感到困惑。下文解释的设想情况。

  1. FileHandle的制备采用CreateFileW法。
  2. FileHandle在step1中用在ReadDirectoryChangesW中。它成功地将请求发送到服务器。
  3. 轮询10秒,如果服务器没有生成更改通知,则使用cancelIo取消chnagenotify请求。它发送取消&服务器响应。
  4. 现在再次使用在ReadDirectoryChangesW中获得的文件句柄设置change,它在"995 -由于线程退出或应用程序请求而中止I/O操作“时失败。此步骤未向服务器发送实际请求。
  5. 立即使用在ReadDirectoryChangesW中获得的文件句柄再次调用step1 &它成功并向服务器发送请求。

步骤3,4,5在一个循环中重复&每一个备用ReadDirectoryChangesW都会在995中失败,接下来的一个步骤就会成功。

有人能告诉我发生了什么事吗?以下是守则

代码语言:javascript
复制
void setnotify(WCHAR* _path)
{
    OVERLAPPED _overlapped;
    HANDLE     _handle;
    char       _buffer[8192] = {0};
    DWORD      _bufferSize = 8192;
    CnState    _state = CN_READY;
    DWORD      _inactivityTime = 0;

    typedef enum State
    {
        CN_READY,
        CN_REQUEST_PENDING,
        CN_RESPONSE_RECEIVED,
        CN_REQUEST_CANCELLED
    } CnState;

    _handle = CreateFileW(_path,
            GENERIC_READ, // access
            FILE_SHARE_READ |
            FILE_SHARE_WRITE |
            FILE_SHARE_DELETE, // share
            NULL, // sec
            OPEN_EXISTING, // disp
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // flags
            0);
    if (_handle == INVALID_HANDLE_VALUE)
    {
        exit(-1);
    }

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

    if (!ReadDirectoryChangesW(_handle,
                _buffer,
                _bufferSize,
                true,
                0x255,
                NULL,
                &_overlapped,
                NULL)) {

        exit(-1);
    } else {
        _state = CN_REQUEST_PENDING;
        wprintf(L"Sent Change notify to Server\n");
    }


    while (1)
    {
        if ((_state == CN_REQUEST_PENDING) && (HasOverlappedIoCompleted(&_overlapped))) {
            wprintf(L"Response Received from Server\n");
            _state = CN_RESPONSE_RECEIVED;
        }

        if ((_state == CN_RESPONSE_RECEIVED) || (_state == CN_REQUEST_CANCELLED)) {
            memset(&_overlapped, 0, sizeof(OVERLAPPED));
            _inactivityTime = 0;
            if (!ReadDirectoryChangesW(_handle,
                        _buffer,
                        _bufferSize,
                        true,
                        255,
                        NULL,
                        &_overlapped,
                        NULL)) {

                wprintf(L"Sent Change notify to Server Failed.\n");
            } else {
                wprintf(L"Sent Change notify to Server\n");
                _state = CN_REQUEST_PENDING;
            }
        }

        if ((_state == ChangeNotifyRequest::CN_REQUEST_PENDING) &&
                (_inactivityTime >= 5000)){
            if (CancelIo(_handle)) {
                _state = CN_REQUEST_CANCELLED;
                wprintf(L"Cancelled Pending Requests.\n");
            } else {
                wprintf(L"Cancelled failed");
            }

        }

        Sleep(50);
        _inactivityTime += 50;

    }
}

下面是样品O/P:

发送更改通知给服务器

取消待决请求。

发送更改通知给服务器

取消待决请求。

发送更改通知服务器失败。

发送更改通知给服务器

取消待决请求。

发送更改通知服务器失败。

发送更改通知给服务器

取消待决请求。

发送更改通知服务器失败。

发送更改通知给服务器

EN

回答 1

Stack Overflow用户

发布于 2017-08-18 17:20:12

启动一个操作,然后取消它,因此它的完成事件将报告一个ERROR_OPERATION_ABORTED (995)错误。但是,在收到该事件之前,您将开始一个新的操作。当您调用CancelIo()时,它只是一个取消请求,原始操作仍然挂起,实际取消可能需要一段时间(或者在处理取消请求之前成功完成)。因此,您仍然需要等待取消的操作真正完成,然后处理好或坏的结果,然后再开始下一个操作。

另外,您的代码中还有另外两个bug。

当第一次调用ReadDirectoryChangesW()时,您将dwNotifyFilter参数设置为0x255,这是错误的。实际上,您只请求这些过滤器位:

代码语言:javascript
复制
FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_ATTRIBUTES
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_CREATION

随后的调用将dwNotifFilter设置为255,这实际上是在请求以下过滤器位:

代码语言:javascript
复制
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

所以,你的过滤是不一致的。你一开始就不应该使用“魔法数字”。Win32 API有可用标志的#define常量,您应该按照预期的方式使用它们。

最后,您不能将来自CreateEvent()的事件对象与OVERLAPPED结构相关联。当您不使用I/O完成端口或I/O完成回调时,ReadDirectoryChangesW()文档中清楚地说明了这一要求。

尝试更像这样的东西:

代码语言:javascript
复制
void setnotify(WCHAR* _path)
{
    typedef enum State
    {
        CN_READY,
        CN_REQUEST_PENDING,
        CN_REQUEST_COMPLETE
    } CnState;

    OVERLAPPED  _overlapped = {0};
    HANDLE      _handle;
    char        _buffer[8192];
    DWORD       _bufferSize;
    CnState     _state = CN_READY;
    DWORD       _inactivityTime;
    const DWORD _filter = 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;

    _handle = CreateFileW(_path,
            GENERIC_READ, // access
            FILE_SHARE_READ |
            FILE_SHARE_WRITE |
            FILE_SHARE_DELETE, // share
            NULL, // sec
            OPEN_EXISTING, // disp
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // flags
            0);
    if (_handle == INVALID_HANDLE_VALUE)
    {
        wprintf(L"Opening Server failed. Error: %u\n", GetLastError());
        exit(-1);
    }

    _overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (_overlapped.hEvent == NULL)
    {
        wprintf(L"Creating Overlapped Event failed. Error: %u\n", GetLastError());
        exit(-1);
    }

    do
    {
        switch (_state)
        {
            case CN_READY:
            {
                _bufferSize = 0;
                _inactivityTime = 0;

                if (!ReadDirectoryChangesW(_handle,
                        _buffer,
                        sizeof(_buffer),
                        TRUE,
                        _filter,
                        &_bufferSize,
                        &_overlapped,
                        NULL))
                {
                    wprintf(L"Requesting change notify from Server failed. Error: %u\n", GetLastError());
                    exit(-1);
                }

                _state = CN_REQUEST_PENDING;
                wprintf(L"Change notify requested from Server\n");

                break;
            }

            case CN_REQUEST_PENDING:
            {
                if (HasOverlappedIoCompleted(&_overlapped))
                {
                    _state = CN_REQUEST_COMPLETE;
                }
                else if (_inactivityTime >= 5000)
                {
                    if (CancelIo(_handle))
                    {
                        _state = CN_REQUEST_COMPLETE;
                        wprintf(L"No response in 5 seconds. Cancelling pending request\n");
                    }
                    else
                        wprintf(L"No response in 5 seconds. Cancelling pending request failed. Error: %u\n", GetLastError());
                }
                else
                {
                    Sleep(50);
                    _inactivityTime += 50;
                }

                break;
            }

            case CN_REQUEST_COMPLETE:
            {
                if (GetOverlappedResult(_handle, &_overlapped, &_bufferSize, TRUE))
                {
                    wprintf(L"Response received from Server\n");
                    // use _buffer up to _bufferSize bytes as needed...
                }
                else if (GetLastError() == ERROR_OPERATION_ABORTED)
                {
                    wprintf(L"Pending request cancelled\n");
                }
                else
                {
                    wprintf(L"Change notify from Server failed. Error: %u\n", GetLastError());
                    // handle error as needed...
                }

                _state = CN_READY:
                break;
            }
        }
    }
}

但是,如果不使用I/O完成端口或I/O完成回调,则可以通过以下事实大大简化代码:您可以更有效地等待事件对象发出信号,从而更有效地等待OVERLAPPED结果,而不必在循环中轮询OVERLAPPED状态:

代码语言:javascript
复制
void setnotify(WCHAR* _path)
{
    OVERLAPPED  _overlapped = {0};
    HANDLE      _handle;
    char        _buffer[8192];
    DWORD       _bufferSize;
    const DWORD _filter = 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;

    _handle = CreateFileW(_path,
            GENERIC_READ, // access
            FILE_SHARE_READ |
            FILE_SHARE_WRITE |
            FILE_SHARE_DELETE, // share
            NULL, // sec
            OPEN_EXISTING, // disp
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // flags
            0);
    if (_handle == INVALID_HANDLE_VALUE)
    {
        wprintf(L"Opening Server failed. Error: %u\n", GetLastError());
        exit(-1);
    }

    _overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (_overlapped.hEvent == NULL)
    {
        wprintf(L"Creating Overlapped Event failed. Error: %u\n", GetLastError());
        exit(-1);
    }

    do
    {
        _bufferSize = 0;

        if (!ReadDirectoryChangesW(_handle,
            _buffer,
            sizeof(_buffer),
            TRUE,
            _filter,
            &_bufferSize,
            &_overlapped,
            NULL))
        {
            wprintf(L"Requesting change notify from Server failed. Error: %u\n", GetLastError());
            exit(-1);
        }

        wprintf(L"Change notify requested from Server\n");

        // alternatively, use GetOverlappedResultEx() with a timeout
        // instead of WaitForSingleObject() and GetOverlappedResult()
        // separately...

        if (WaitForSingleObject(_overlapped.hEvent, 5000) == WAIT_TIMEOUT)
        {
            if (CancelIo(_handle))
                wprintf(L"No response in 5 seconds. Cancelling pending request\n");
            else
                wprintf(L"No response in 5 seconds. Cancelling pending request failed. Error: %u\n", GetLastError());
        }

        if (GetOverlappedResult(_handle, &_overlapped, &_bufferSize, TRUE))
        {
            wprintf(L"Response received from Server\n");
            // use _buffer up to _bufferSize bytes as needed...
        }
        else if (GetLastError() == ERROR_OPERATION_ABORTED)
        {
            wprintf(L"Pending request cancelled\n");
        }
        else
        {
            wprintf(L"Change notify from Server failed. Error: %u\n", GetLastError());
            // handle error as needed...
        }
    }
    while (true);
}

另外,请参阅my earlier answer to a similar question,这解释了在使用ReadDirectoryChangesW()时必须注意的其他一些问题,特别是处理ERROR_NOTIFY_ENUM_DIR错误。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45760370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档