I have implemented a program that traces changes in a given folder using ReadDirectoryChangesW
in overlapped mode with a completion routine. It works good.
I am planning to reconstruct it to make a more universal library.
When the completion routine cr
called, and file changes are displayed, I need to continue tracing: see line DoRDC = true; // RESTART WATCHING
.
It was possible in the current version, because it run in a loop while (_kbhit() == 0) {
, but after reconstruction I will eliminate this loop.
WatchDirectory
will call ReadDirectoryChangesW
at first only.
My question is: how should I restart the tracing inside cr
?
Will it be correct to call ReadDirectoryChangesW
inside the completion routine cr
?
But it may cause call of cr
when the previous call was not finished...
May be there is a way to tell ReadDirectoryChangesW
not to stop tracing ?
My code is below. The main function - WatchDirectory();
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;
// simply display dir changes
DisplayFileInfo(lpBuffer, dwNumberOfBytesTransfered);
}
bool WatchDirectory(LPTSTR lpDir)
{
// AFTER RECONSTRUCTION WILL CALL ReadDirectoryChangesW 1 TIME WITHOUT A LOOP
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);
}
how should I restart the tracing inside
cr
? Will it be correct to callReadDirectoryChangesW
inside the completion routinecr
?
Yes. You must call ReadDirectoryChangesW()
again every time a success completion is reported.
But it may cause call of
cr
when the previous call was not finished...
The completion routine is executed when the calling thread is in an alertable state. Since you are already inside of the routine, any new requests will be cached and the routine will be called again at a later time after the routine has exited and the calling thread has a chance to enter a new alertable state.