我实现了一个程序,使用ReadDirectoryChangesW
重叠模式和完成例程来跟踪给定文件夹中的更改。效果很好。
我计划重建它以创建一个更通用的库——完成例程应该将文件更改保存在队列中。
问题:我如何将一个参数传递给完成例程cr
,该参数将指向我的队列以供使用cr
?
当完成例程cr
调用并且文件更改显示时,我需要继续跟踪:参见行DoRDC = true; // RESTART WATCHING
。
这是可能的,因为它在循环中运行while (_kbhit() == 0) {
。 重构后,我将消除此循环。
我的代码如下。主要函数 - WatchDirectory();
void DisplayFileInfo(LPVOID FileInfoRecords, DWORD FileInfoLength) {
// Display file changes. Called from completion routine "cr".
//ActionText[0] = L"-";
FILE_NOTIFY_INFORMATION* fi = (FILE_NOTIFY_INFORMATION*)FileInfoRecords;
if (FileInfoLength == 0) {
std::wcout << L"No file info!" << std::endl;
return;
}
int RecNum = 1;
DWORD OffsetToNext = 0;
do {
fi = (FILE_NOTIFY_INFORMATION*)(((char*)fi) + OffsetToNext);
std::wstring wfname;
std::wstring wActionName;
if ((fi->Action < MIN_ACTION_CODE) || (fi->Action > MAX_ACTION_CODE))
wActionName = L"Unknown code";
else
wActionName = ActionText[fi->Action];
int slen = fi->FileNameLength / sizeof(WCHAR);
wfname.assign(fi->FileName, slen);
std::wcout << L"Rec " << RecNum << L": Action = " << wActionName << L"(" << fi->Action << L") Offset = " << fi->NextEntryOffset <<
L" File = " << wfname << std::endl;
OffsetToNext = fi->NextEntryOffset;
assert(RecNum < 50);
RecNum++;
} while (OffsetToNext > 0);
}
LPVOID lpBuffer = NULL;
bool DoRDC = true;
VOID WINAPI cr(DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped) {
// Completion routine
DoRDC = true; // RESTART WATCHING
std::wcout << L" ------------- lpCompletionRoutine --------------- " << std::endl;
std::wcout << L" ErrCode = " << dwErrorCode
<< L" BytesTransferred = " << dwNumberOfBytesTransfered << std::endl;
if (dwErrorCode != 0) {
return;
}
std::wcout << L"..............." << std::endl;
DisplayFileInfo(lpBuffer, dwNumberOfBytesTransfered);
}
bool WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
HANDLE hDir = INVALID_HANDLE_VALUE;
std::wcout << L"3_Watching for: " << lpDir << std::endl;
_tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
int EventsNumber = 1;
DWORD Flags = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME;
hDir = CreateFile(lpDir, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if (hDir == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
std::wcout << L"ERROR: CreateFile(folder to trace) function failed = " << err << std::endl;
return false;
///ExitProcess(err);
}
DWORD nBufferLength = 30000;
lpBuffer = malloc(nBufferLength);
BOOL bWatchSubtree = TRUE;
DWORD BytesReturned = 0;
HANDLE hEvent = CreateEvent(NULL, FALSE /*manual reset = true*/, FALSE /* initial state*/, NULL);
if (hEvent == NULL) {
printf("\n Cannot create event.\n");
CloseHandle(hDir);
return false;
//ExitProcess(GetLastError());
}
// =============================================================
OVERLAPPED Overlapped;
//---Overlapped.hEvent = hEvent;
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine = cr;
// =============================================================
DoRDC = true;
while (_kbhit() == 0) {
if (DoRDC) {
ZeroMemory(&Overlapped, sizeof(Overlapped));
BOOL res_rdc = ReadDirectoryChangesW(hDir,
lpBuffer,
nBufferLength,
bWatchSubtree,
Flags,
&BytesReturned,
&Overlapped,
lpCompletionRoutine);
bool ok_rdc = (res_rdc != 0);
if (ok_rdc) {
}
else {
DWORD err = GetLastError();
std::wcout << L"ReadDirectoryChangesW error = " << err << std::endl;
}
DoRDC = false;
}
// Wait for notification.
//std::wcout << L"SleepEx" << std::endl;
SleepEx(1000, TRUE);
}
CloseHandle(hEvent);
CloseHandle(hDir);
free(lpBuffer);
}
定义一个自定义的
struct
,其中包含OVERLAPPED
作为其第一个数据成员,以及您需要的任何其他成员,例如(指向)您的队列。然后,将一个指针传递给的参数
struct
。然后 可以将指针转换回您的以访问其成员。这是可行的,因为结构的第一个数据成员保证具有与结构本身相同的内存地址。LPOVERLAPPED
ReadDirectoryChangesW()
cr()
LPOVERLAPPED
struct
这是在重叠 I/O 操作中传递自定义数据的常用方法。
例如: