C++ 如果之前调用了CancelIo,ReadDirectoryChangesW将失败,并出现错误995
我对ReadDirectoryChangesW的奇怪行为感到困惑,因为错误995失败了。下面解释的场景C++ 如果之前调用了CancelIo,ReadDirectoryChangesW将失败,并出现错误995,c++,winapi,readdirectorychangesw,C++,Winapi,Readdirectorychangesw,我对ReadDirectoryChangesW的奇怪行为感到困惑,因为错误995失败了。下面解释的场景 FileHandle是使用CreateFileW获得的 在步骤1中获得的文件句柄已在ReadDirectoryChangesW中使用。它成功地将请求发送到服务器 轮询10秒,如果服务器未生成更改通知,请使用cancelIo取消chnagenotify请求。它发送cancel&服务器响应 现在,再次使用在步骤1中获得的文件句柄设置change notify with ReadDirectoryC
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示例:
已将更改通知发送到服务器
已取消挂起的请求
已将更改通知发送到服务器
已取消挂起的请求
向服务器发送更改通知失败
已将更改通知发送到服务器
已取消挂起的请求
向服务器发送更改通知失败
已将更改通知发送到服务器
已取消挂起的请求
向服务器发送更改通知失败
已将更改通知发送到服务器您启动一个操作,然后取消它,因此它的完成事件将报告一个
错误\u操作被中止
(995)错误。但是,在收到该事件之前,您正在启动一个新操作。当您调用CancelIo()
时,它只是一个取消请求,原始操作仍处于挂起状态,实际取消可能需要一段时间(或者在处理取消请求之前它可能会成功完成)。因此,您仍然需要等待取消的操作实际完成,然后处理结果,无论结果是好是坏,然后再开始下一个操作
另外,代码中还有另外两个bug
首次调用ReadDirectoryChangesW()
时,将dwNotifyFilter
参数设置为0x255
,这是错误的。实际上,您只请求这些过滤器位:
FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_ATTRIBUTES
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_CREATION
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
随后的调用将dwNotifFilter
设置为255
,这将有效地请求这些过滤位:
FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_ATTRIBUTES
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_CREATION
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为可用标志定义了#常量,您应该按照预期的方式使用它们
最后,您没有将来自CreateEvent()
的事件对象与重叠的结构相关联。当您不使用I/O完成端口或I/O完成回调时,文档中明确说明了此要求
请尝试类似以下内容:
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
状态:
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);
}
另外,请参阅至,它解释了在使用ReadDirectoryChangesW()
时必须注意的一些其他问题,特别是错误的处理\u NOTIFY\u ENUM\u DIR
错误。您启动一个操作,然后取消它,因此它的完成事件将报告一个错误\u操作中止的错误。但是,在收到该事件之前,您正在启动一个新操作。当您调用CancelIo()
时,它只是一个取消请求,原始操作仍处于挂起状态,实际取消可能需要一段时间(或者在处理取消请求之前它可能会成功完成)。因此,您仍然需要等待取消的操作实际完成,然后处理结果,无论结果是好是坏,然后再开始下一个操作
另外,代码中还有另外两个bug
首次调用ReadDirectoryChangesW()
时,将dwNotifyFilter
参数设置为0x255
,这是错误的。实际上,您只请求这些过滤器位:
FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_ATTRIBUTES
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_CREATION
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
随后的调用将dwNotifFilter
设置为255
,这将有效地请求这些过滤位:
FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_ATTRIBUTES
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_CREATION
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为可用标志定义了#常量,您应该按照预期的方式使用它们
最后,您没有将来自CreateEvent()
的事件对象与重叠的结构相关联。当您不使用I/O完成端口或I/O完成回调时,文档中明确说明了此要求
请尝试类似以下内容:
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
状态:
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);
}
另外,请参阅至,它解释了在使用ReadDirectoryChangesW()
时必须注意的一些其他问题,特别是错误的处理。\u NOTIFY\u ENUM\u DIR
错误。请显示您的代码,而不是描述它。谢谢。