admin管理员组

文章数量:1336631

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);
}

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);
}
Share Improve this question asked Nov 19, 2024 at 18:06 LUNLUN 1031 silver badge7 bronze badges 2
  • 1 Side note: Making lpBuffer global leaves you with non-reentrant functions, a nasty surprise for anyone writing multi-threaded code, and opens it up to abuse or accidental reuse by other functions anywhere in the program turning debugging into a nightmare. Don't do this to yourself. Better solutions will be a bit harder to write, but writing code almost always takes much less time than debugging code, so time you spend making code easier to debug is paid back almost immediately. – user4581301 Commented Nov 19, 2024 at 18:23
  • user4581301, thank you very much! Yes, I know it. After the reconstruction there wtill not be global variables. All of them will be hided in a class "Watcher". – LUN Commented Nov 19, 2024 at 19:01
Add a comment  | 

1 Answer 1

Reset to default 2

how should I restart the tracing inside cr ? Will it be correct to call ReadDirectoryChangesW inside the completion routine cr ?

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.

本文标签: cHow to continue read directory changes after 1st ReadDirectoryChangesW callStack Overflow