Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

04.01.2013, 15:24

ReadDirectoryChangesW

Hallo alle miteinander,

in meinem Programm möchte ich überprüfen ob Dateien im Hintergrund eingefügt oder gelöscht werden. Dafür benutze ich die Funktion ReadDirectoryChanges mit einer lpCompletionRoutine. Das Anlegen verläuft ohne Probleme( zumindest wird von der Funktion( siehe unten) "true" zurückgegeben), aber die Routine wird nie aufgerufen.

Im Internet habe ich gelesen, dass in der Regel SleepEx verwendet wird, damit das Programm in Bereitschaft bleibt, diese Option fällt allerdings bei mir weg, da ich nebenbei noch andere arbeiten mit meinem Programm verrichten will. Es handelt sich um ein WinMain Programm, es läuft also mit einer Nachrichtenschleife und es hat verschiedene Aufgaben, nicht nur die Überwachung des Verzeichnises.

ReadDirectoryChanges ruft ich wie folgt auf:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
bool CreateDirectoryMonitoring()
{
    //das Verzeichnis zum Überwachen öffnen
    HANDLE hDir = CreateFile("C:"
                                ,FILE_LIST_DIRECTORY
                                ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
                                ,NULL
                                ,OPEN_EXISTING
                                ,FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
                                ,NULL);
    if(hDir == INVALID_HANDLE_VALUE )
    {
        return false;
    }

    OVERLAPPED overlapped;
    ZeroMemory(&overlapped, sizeof(overlapped));
    overlapped.hEvent       = NULL;
    DWORD byteRerurned  = 0;
    FILE_NOTIFY_INFORMATION Buffer[1024];

    if(!ReadDirectoryChangesW(hDir
                                ,&Buffer
                                ,sizeof(Buffer)
                                ,FALSE
                                ,FILE_NOTIFY_CHANGE_FILE_NAME
                                ,&byteRerurned
                                ,&overlapped
                                ,&ChDirCompletionRoutine) )
    {
        return false;
    }

    return true;
}


in der CompletionRoutine soll das programm mir lediglich eine Info in eine Htmldatei schreiben:

C-/C++-Quelltext

1
2
3
4
5
6
void CALLBACK ChDirCompletionRoutine(DWORD dwErrorCode
                                     ,DWORD dwNumberOfBytesTransfered
                                     ,LPOVERLAPPED lpOverlapped)
{
    WriteToHtml("Datei in C: bearbeitet",3);//dieser Aufruf geht auf jedenfall, da er auch in anderen Teilen des Programms erfolgreich genutzt wird
}


Mein Prgramm startet, ruft dann die Funktion zum Anlegen von ReadDirectoryChanges auf und danach beschäftigt es sich mit anderen Aufgaben bis es beendet wird, aber die CompletionRoutine wird nie aufgerufen.

Ich hoffe ihr könnt mir helfen
liebe Grüße setset1994

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

04.01.2013, 17:07

Willst du wirklich nur Änderungen in C:\ und nicht in Unterverzeichnissen tracken?
Und hast du mal, nur zur Sicherheit, einen Breakpoint in deine ChDirCompletionRoutine gesetzt?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

04.01.2013, 18:11

Zitat von »MSDN«

[...] This routine is called whenever the operation has been completed or canceled while the thread is in an alertable wait state.


Abgesehen davon: Ändert sich auch tatsächlich mal ein Dateiname?


Funktionierendes Snippet aus einem meiner Projekte:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    ...

    hot_swap_watch_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0U, 1U);
    hot_swap_watch_thread = std::thread(hotSwapWatchThread, plugin_dir, static_cast<HANDLE>(hot_swap_watch_completion_port), GetCurrentThreadId());

    ...


  void hotSwapWatchThread(const Win32::path& plugin_dir, HANDLE completion_port, DWORD notify_thread)
  {
    const DWORD buffer_size = 2048;
    char buffer[buffer_size];

    while (true)
    {
      Win32::Handle directory = CreateFileW(plugin_dir, FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 0);

      if (CreateIoCompletionPort(directory, completion_port, 0U, 1U) != completion_port)
        return;

      while (true)
      {
        DWORD bytes_read = ~0U;
        OVERLAPPED o;
        o.Pointer = buffer;
        o.hEvent = 0;
        if (ReadDirectoryChangesW(directory, buffer, buffer_size, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &bytes_read, &o, nullptr) == 0)
        {
          if (bytes_read == 0)
            break;
          return;
        }

        ULONG_PTR key;
        OVERLAPPED* io;
        if (!GetQueuedCompletionStatus(completion_port, &bytes_read, &key, &io, INFINITE))
          return;

        auto info = static_cast<FILE_NOTIFY_INFORMATION*>(io->Pointer);

        // do stuff with info

      }
    }
  }

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

04.01.2013, 20:01

@dot:

Zitat von »"MSDN"«

FILE_NOTIFY_CHANGE_FILE_NAME
Any file name change in the watched directory or subtree causes a change notification wait operation to return. Changes include renaming, creating, or deleting a file.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

04.01.2013, 22:28

Das stimmt natürlich, ich wollte nur darauf hinweisen, dass dieses Flag möglicherweise nicht alle gewünschten Fälle abdeckt und nichts passieren wird, wenn eben nicht gerade eine Datei erzeugt, umbenannt oder gelöscht wird.

6

05.01.2013, 12:33

Erst mal danke wegen der schnellen antworten :)

Ich habe während der Versuche einen Breakpoint in die Routine gesetzt und damit überhaubt etwas passieren kann, habe ich immer ein Textdokument in C: eingefügt.

Wegen der Frage ob ich nur C: überwachen will, ich habe es zum Testen erstmal so eingestellt.

Den "alertable wait state" kann man den auch bewirken ohne das Programm anzuhalten durch Funktionen wie SleepEx oder muss ich nach einer anderen Methode suchen damit ich nebenbei noch anderes unternehmen kann?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

05.01.2013, 13:33

Den "alertable wait state" kann man den auch bewirken ohne das Programm anzuhalten durch Funktionen wie SleepEx oder muss ich nach einer anderen Methode suchen damit ich nebenbei noch anderes unternehmen kann?

Nein, wenn du "nebenbei etwas anderes unternehmen" willst, dann mach einen Thread dafür, siehe z.B. mein Beispiel...

8

05.01.2013, 23:41

Ich habe jetzt versucht mein Programm etwas umzuschreiben, damit ich das ReadDirectorychanges als Thread habe, wie es dot empfohlen hat.

Das sieht nun wie folgt aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
DWORD WINAPI CreateDirectoryMonitoringThread(LPVOID Data)
{
    //das Verzeichnis zum Überwachen öffnen
    HANDLE hDir = CreateFile("C:"
                                ,FILE_LIST_DIRECTORY
                                ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
                                ,NULL
                                ,OPEN_EXISTING
                                ,FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
                                ,NULL);
    if(hDir == INVALID_HANDLE_VALUE )
    {
        WriteToHtml("Das Aktivieren der Verzeichnisüberwachung ist fehlgeschlagen",3);
        return 1;
    }

    OVERLAPPED overlapped;
    ZeroMemory(&overlapped, sizeof(overlapped));
    overlapped.hEvent       = NULL;
    DWORD byteRerurned      = 0;
    FILE_NOTIFY_INFORMATION Buffer[1024];

    if(!ReadDirectoryChangesW(hDir
                                ,&Buffer
                                ,sizeof(Buffer)
                                ,FALSE
                                ,FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME
                                ,&byteRerurned
                                ,&overlapped
                                ,&ChDirCompletionRoutine) )
    {
        WriteToHtml("Das Aktivieren der Verzeichnisüberwachung ist fehlgeschlagen",3);
        return 1;
    }

    SleepEx(INFINITE,true);

    return 0;
}


Die ChDirCompletionRoutine bleibt die gleiche und aufgerufen wird der Thread durch:

C-/C++-Quelltext

1
hThread = CreateThread(NULL,0,CreateDirectoryMonitoringThread,NULL,0,&dwThreadID);


das Aufrufen klappt jedenfalls und der Thread wird bis SleepEx durchgespielt,habs per Breakpoint getestet, allerdings bleibt das Problem, dass die ChDirCompletionRoutine nie aufgerufen wird.

Das Verwenden von Thread ist für mich neuland, habe ich dabei vielleicht etwas falsch gemacht?

9

08.02.2013, 20:12

Lösung

Ich habe es mittlerweile geschafft, da wo "C:" steht muss einfach "C:\\" hin.

So einfach kann manchmal die Lösung sein :)

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

08.02.2013, 20:22

Und CreateFile hat trotzdem funktioniert?

Werbeanzeige