我正在为我的(基于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()函数设置胃灼热?
答案 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);
}
)
的初始值无效。此外,您错误地处理错误情况(例如尝试关闭无效句柄)。