SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Sicro »

Bisonte hat geschrieben:

Code: Alles auswählen

FileAction_File = PeekS(@buffer\Filename, buffer\FileNameLength, #PB_Unicode)
Das ist auch nicht korrekt, weil PeekS() als Parameterangabe die Anzahl der Zeichen haben möchte, die ausgelesen werden sollen, buffer\FileNameLength enthält aber laut MSDN (FILE_NOTIFY_INFORMATION) die Länge des Dateinamens in Bytes.
Deine Zeile sollte also so aussehen:

Code: Alles auswählen

FileAction_File = PeekS(@buffer\Filename, buffer\FileNameLength / 2, #PB_Unicode)
Ein Unicode-Zeichen in PB benötigt 2 Bytes.

Der Grund, warum du den Fehler nicht reproduzieren kannst, liegt daran, weil bei deinem buffer\Filename glücklicherweise jedes Mal ein Null-Byte am Ende ist und PeekS() rechtzeitig mit dem Auslesen abbricht. Die Parameterangabe "Länge" bei PeekS() gibt ja nur die maximale Anzahl zu lesende Zeichen an, wenn aber schon vorher ein Null-Byte entdeckt wird, bricht PeekS() schon vorher mit dem Auslesen ab. Im buffer\Filename von oO0XX0Oo gibt es aktuell leider erst viel später ein Null-Byte, weshalb nach dem Dateiname auch noch weitere Zeichen aus dem Memory gelesen werden.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Bisonte »

Hab ich das Bytes überlesen ? Alle Achtung.
Dann macht das ganze natürlich Sinn.

Änderung wird implementiert.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
oO0XX0Oo
Beiträge: 55
Registriert: 21.07.2017 22:36

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von oO0XX0Oo »

Danke @Sicro für die Erklärung und die Korrektur der nötigen Zeile und danke @Bisonte
für die Änderung(en)!

Funktioniert hier im Moment hervorragend :mrgreen:
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Bisonte »

Neues Update : V1.06

Das beenden einer Überwachung ist wohl etwas buggy gewesen. Da innerhalb des Threads ReadDirectoryChangesW die Bremse darstellt,
blieb nur ein Killthread übrig. Dank an Silbersurfer fürs entdecken.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Regenduft »

Anscheinend hatte ich mich beim Suchen im Forum vertippt... sonst hätte ich nicht das Rad neu erfinden müssen.. :roll:

Mir ist bei Deinem Code ein potentieller Fehler aufgefallen - eventuell liege ich aber falsch und meine (sehr ähnliche) Lösung ist fehlerhaft...

Dein Code:

Code: Alles auswählen

If SHGetKnownFolderPath(*FolderID, kfFlag, #Null, @*UnicodeBuffer) = #S_OK And *UnicodeBuffer
  Result = PeekS(*UnicodeBuffer, -1, #PB_Unicode) + "\"
  CoTaskMemFree_(*UnicodeBuffer)
EndIf
Mein Code:

Code: Alles auswählen

Define *Path, *ppszPath.String = @*Path

If SHGetKnownFolderPath(*rfid, KF_Flags, 0, *ppszPath ) >= 0 And *Path And Asc(*ppszPath\s)
  Result$ = *ppszPath\s + "\"
EndIf

CoTaskMemFree_(*Path)
*Path = 0
Ich rufe CoTaskMemFree_() IMMER auf, denn...
https://docs.microsoft.com/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath hat geschrieben:
Type: PWSTR*

When this method returns, contains the address of a pointer to a null-terminated Unicode string that specifies the path of the known folder. The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree, whether SHGetKnownFolderPath succeeds or not. The returned path does not include a trailing backslash. For example, "C:\Users" is returned rather than "C:\Users\".
Ein Aufruf von CoTaskMemFree_() mit einem Null-Zeiger ist übrigens keine Problem:
https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cotaskmemfree hat geschrieben:[in, optional] pv

A pointer to the memory block to be freed. If this parameter is NULL, the function has no effect.
Ansonsten überprüfe ich noch mit "Asc(*ppszPath\s)", dass SHGetKnownFolderPath() nicht einen Leerstring rückgegeben hat, bevor ich "\" anhänge.
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Bisonte »

@Regenduft: Ok ... guter Einwand ;)

Die Reihenfolge ist auch so im Original, daher hab ich das so übernommen.
Es macht für mich Sinn, nur wenn SH auch was zurückgibt, das wieder freizugeben...
Allerdings ist deine Begründung stichhaltig ( von wegen es ist egal ob NULL oder nicht bei CoTaskMemFree ) ;)

Das Überprüfen auf Leerstring ist allerdings eine Sache die ich anscheinend übersehen habe...
wobei dieser Fall bisher noch nie eintrat, oder sich nicht bemerkbar machte.
(Dafür hatte ich ja extra die Konstanten gewählt... und weil man sich das leichter merken kann ;)
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
oO0XX0Oo
Beiträge: 55
Registriert: 21.07.2017 22:36

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von oO0XX0Oo »

Ich hab gerade noch mal zwei Fragen:

01.
Was ist denn der Grund dafür, dass eine Datei, die geändert wird, 2 mal vom superviser thread gefunden wird?

Also ich überwache z.B.: "D:\Temp"

Dort liegt die Datei "___a.txt"

Jedesmal, wenn ich die Datei editiere und dann wieder speichere:

File ___a.txt was modified
File ___a.txt was modified

Kann man das auch auf 1 x begrenzen (also ohne das man jetzt schauen würde ob die letzte entdeckte Datei wieder der jetztigen entspricht) :)


02. Gibt es einen Grund, warum das supervising nicht für UNC Pfade funktioniert?
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von Bisonte »

oO0XX0Oo hat geschrieben: 20.11.2022 21:09 Ich hab gerade noch mal zwei Fragen:

01.
Was ist denn der Grund dafür, dass eine Datei, die geändert wird, 2 mal vom superviser thread gefunden wird?

Also ich überwache z.B.: "D:\Temp"

Dort liegt die Datei "___a.txt"

Jedesmal, wenn ich die Datei editiere und dann wieder speichere:

File ___a.txt was modified
File ___a.txt was modified

Kann man das auch auf 1 x begrenzen (also ohne das man jetzt schauen würde ob die letzte entdeckte Datei wieder der jetztigen entspricht) :)


02. Gibt es einen Grund, warum das supervising nicht für UNC Pfade funktioniert?
Zu 1: Ja, das kann man begrenzen.

MSDN Link : https://learn.microsoft.com/en-us/windo ... rychangesw

In der Threadprozedur wir der NotifyFilter mit #FILE_NOTIFY_CHANGE_ALL definiert. in der MSDN stehen diverse Werte, wie du es anpassen kannst, das nur bestimmte Ereignisse erfasst werden.
In meinem "original" reagiert er 2x weil einmal ein Speichern (also Attribute z.b. Datumstempel) geändert wird UND die Dateigrösse sich ändert...

und zu 2... Ich schätze es liegt daran, dass die Funktion ReadDirectoryChanges für Windows XP geschrieben wurde, wo es so etwas noch nicht gab... bzw keiner an sowas gedacht hat. Also zu alt ;)
Eine wirkliche Antwort weiss ich darauf nicht....
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
oO0XX0Oo
Beiträge: 55
Registriert: 21.07.2017 22:36

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von oO0XX0Oo »

Hi Bisonte und danke für deine Antwort.

1. Auch wenn ich

Code: Alles auswählen

Protected NotifyFilter.l = #FILE_NOTIFY_CHANGE_LAST_WRITE
benutze (oder alternativ zum Testen: #FILE_NOTIFY_CHANGE_SIZE)

bekomme ich trotzdem immer 2 events beim Speichern der Datei...

2. Eigentlich sollte das gehen:
ReadDirectoryChangesW fails with ERROR_INVALID_PARAMETER when the buffer length is greater than 64 KB and the application is monitoring a directory over the network. This is due to a packet size limitation with the underlying file sharing protocols.
Es wäre auch komisch, wenn das nicht so wäre. XP kam erst nach Windows 2000 heraus und 2000 wurde damals schon in Firmennetzwerken verwendet wo es fileserver mit Freigaben gab.
oO0XX0Oo
Beiträge: 55
Registriert: 21.07.2017 22:36

Re: SuperviseDirectory() & GetKnownFolder() [Module][WIN]

Beitrag von oO0XX0Oo »

Hätte irgendjemand Zeit, sich das (noch mal) anzuschauen, warum es trotz Limitierung auf #FILE_NOTIFY_CHANGE_LAST_WRITE oder #FILE_NOTIFY_CHANGE_SIZE immer 2 events auswirft und warum es zur Zeit nicht mit UNC-Pfaden funktioniert?

Ich geb auch gern ein Bier oder 2 dafür aus ;)
Antworten