Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Aktualisierung erzwingen (https://www.delphipraxis.net/127551-aktualisierung-erzwingen.html)

Carsten1234 15. Jan 2009 11:07


Aktualisierung erzwingen
 
Hallo,

auf/in einem über USB angeschlossenen Gerät wird eine Textdatei (Log-Datei) ausgelesen und in einem TMemo angezeigt.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var FIn : System.Text;
    Line: string;
begin
  Memo1.Lines.Clear;
{$I-}
  System.AssignFile(FIn, FileListBox1.FileName);
  System.Reset(FIn);
{$I+}
  if System.IOResult = 0 then
  begin
    while not(EoF(Fin)) do
    begin
      System.Readln(FIn, Line);
      Memo1.Lines.Add(Line);
    end;
    System.CloseFile(FIn);
  end;
end;
Diese Textdatei wird ausschließlich vom USB-Gerät selbst manipuliert (verändert), auf PC-Seite soll diese Datei immer nur lesend geöffnet werden.
Problem: Windows bekommt eine Aktualisierung nicht mit und auch wenn ich wie oben geschrieben die Datei immer wieder neu öffne und schließe, so ist der mir angezeigte Inhalt derselbe. Ziehe ich hingegen das Gerät ab und wieder an, kann ich eine aktualisierte Datei einlesen.
Dieser Effekt tritt übrigens nicht nur bei meinem Beispielprogramm auf, sondern auch beim Windows Explodierer trotz drücken von F5.
Scheinbar bekommt Windows eine Aktualisierung nicht mit außer die Datei wird von Windows aus verändert.
Frage: Gibt es ggf. eine (API-) Befehl, der Windows zur Aktualisierung zwingt?

Dank vorab und Gruß, Carsten

Nachtrag: Das Gerät meldet sich als HID an und bekommt von Windows einen Laufwerksbuchstaben verpasst.

himitsu 15. Jan 2009 12:56

Re: Aktualisierung erzwingen
 
wenn du am Dateisystemtreiber vorbei die Daten änderst, dann kann ja nichts gutes bei rauskommen.
der Windowstreiber kopiert beim Lesen die Daten in seine Cache und ließt dann dort aus ... drum die unveränderten Daten.

Vorschlag: das Laufwerk dismounten und neu mounten (beim Dismounten sollte die Cache freigegeben werden)

Delphi-Quellcode:
hDrive: THandle;
W: LongWord;

hDrive := CreateFile('\\.\X:', GENERIC_READ or GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDrive <> INVALID_HANDLE_VALUE then begin
  DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME { $00090020 },
    nil, 0, nil, 0, W, nil);
  CloseHandle(hDrive);
end;

Carsten1234 15. Jan 2009 13:14

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
wenn du am Dateisystemtreiber vorbei die Daten änderst, dann kann ja nichts gutes bei rauskommen.

Ich weiß. Und wie es scheint, geht der Weg um einen speziellen (Kauf-) Treiber nicht herum.

Zitat:

Zitat von himitsu
Delphi-Quellcode:
hDrive: THandle;
W: LongWord;

hDrive := CreateFile('\\.\X:', GENERIC_READ or GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDrive <> INVALID_HANDLE_VALUE then begin
  DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME { $00090020 },
    nil, 0, nil, 0, W, nil);
  CloseHandle(hDrive);
end;

Im Anschluss daran scheitern aber jegliche Lesezugriffe auf diese LOG-Datei, weil zwar das Gerät selbst (im Explorer) noch vorhanden ist, aber ich nicht mehr drauf zugreifen kann..

Gruß, Carsten

himitsu 15. Jan 2009 13:25

Re: Aktualisierung erzwingen
 
nja, hab das jetzt nur mal schnell aus Luckie's NTDiskImage rausgemopst.

Bei Disketten scheint es so keine Probleme zu geben.
muß dann wohl noch irgendwie ein FSCTL_MOUNT_VOLUME mit hinten dran.

oder reicht dieses schon aus?
Delphi-Quellcode:
hDrive: THandle;
W: LongWord;

hDrive := CreateFile('\\.\X:', GENERIC_READ or GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDrive <> INVALID_HANDLE_VALUE then begin
  DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME { $00090018 },
    nil, 0, nil, 0, W, nil);
  DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME { $0009001C },
    nil, 0, nil, 0, W, nil);
  CloseHandle(hDrive);
end;

Carsten1234 15. Jan 2009 13:36

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
oder reicht dieses schon aus?

Leider nicht. :pale:

himitsu 15. Jan 2009 14:13

Re: Aktualisierung erzwingen
 
dann bleibt wohl nur dieses
Delphi-Quellcode:
hDrive: THandle;
W: LongWord;

hDrive := CreateFile('\\.\X:', GENERIC_READ or GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDrive <> INVALID_HANDLE_VALUE then begin
  DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME { $00090020 },
    nil, 0, nil, 0, W, nil);
  DeviceIoControl(hDrive, FSCTL_MOUNT_VOLUME,
    nil, 0, nil, 0, W, nil);
  CloseHandle(hDrive);
end;
allerdings hab ich die Definition von FSCTL_MOUNT_VOLUME nicht zur Hand (hier ist kein PSDK installiert und wer weiß, ob's da drinsteht, denn im MSDN wurde garnichts mit FSCTL_MOUNT_VOLUME gefunden)

hier noch 2 Thread, mit selben/ähnlichem Problem ... vielleicht hilft's:
http://groups.google.com/group/micro...11a510107ef5ea
http://www.ureader.com/msg/1473513.aspx


so, ich muß dann aber mal langsam los, hab noch 'nen Termin

Carsten1234 15. Jan 2009 14:20

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
allerdings hab ich die Definition von FSCTL_MOUNT_VOLUME nicht zur Hand (hier ist kein PSDK installiert und wer weiß, ob's da drinsteht, denn im MSDN wurde garnichts mit FSCTL_MOUNT_VOLUME gefunden)

Es steht leider nicht drin (hatte ich schon gesucht). S. Klick mich

Zitat:

Zitat von himitsu
hier noch 2 Thread, mit selben/ähnlichem Problem ... vielleicht hilft's:

Den Fred hatte ich auch schon gelesen, aber trotzdem Danke dafür.

Gruß, Carsten

himitsu 15. Jan 2009 14:30

Re: Aktualisierung erzwingen
 
*noch schnell antworte*
man könnte jetzt auch mal versuchen zu raten :angel2:
Delphi-Quellcode:
FSCTL_LOCK_VOLUME    = ((FILE_DEVICE_FILE_SYSTEM shl 16)
                      or (FILE_ANY_ACCESS shl 14)
                      or (6 shl 2)
                      or METHOD_BUFFERED);

FSCTL_UNLOCK_VOLUME  = ((FILE_DEVICE_FILE_SYSTEM shl 16)
                      or (FILE_ANY_ACCESS shl 14)
                      or (7 shl 2)
                      or METHOD_BUFFERED);

FSCTL_DISMOUNT_VOLUME = ((FILE_DEVICE_FILE_SYSTEM shl 16)
                      or (FILE_ANY_ACCESS shl 14)
                      or (8 shl 2)
                      or METHOD_BUFFERED);
weitergezählt wäre es dann 'ne 9
Delphi-Quellcode:
FSCTL_MOUNT_VOLUME   = ((FILE_DEVICE_FILE_SYSTEM shl 16)
                      or (FILE_ANY_ACCESS shl 14)
                      or (9 shl 2)
                      or METHOD_BUFFERED);

FSCTL_MOUNT_VOLUME   = (($00000009 shl 16)
                      or (0 shl 14)
                      or (9 shl 2)
                      or 0);

FSCTL_MOUNT_VOLUME   = $00090024;
eventuell kommt der Code aber auch vor FSCTL_LOCK_VOLUME (erst mounten, damit man was machen kann), oder so?
nja dafür könnte man im PSDK mal nachsehn welche Konstanten auch noch in diesem Bereich liegen und versuchen daraus zu raten wo es liegen könnte :gruebel:

zu vermuten wäre ja, das es, zumindestens bis auf (9 shl 2) stimmt.

franktron 15. Jan 2009 15:02

Re: Aktualisierung erzwingen
 
Mal son eine ganz dumme zwischenfrage gibts es nicht eine Möglichkeit Windows zu sagen die Datei hat sich geändert, oder lese die Datei neu ein.

Das mit dem Dismounten und neu Mounten kann ja nicht der sinn sein.

P.S. unter Linux heist der Befehl Touch um eine Datei eine Änderung zu erzwingen ohne Sie zu ändern

himitsu 15. Jan 2009 15:24

Re: Aktualisierung erzwingen
 
Touch:
ich glaub Linux lißt nur die Verzeichnisstruckturen nicht neu ein, wenn sie schon im Cache sind ... egal ob sich da was geändert hat, oder nicht.

Mit dem dateiinhalt hat das dann aber nichts zu tun.

Aber du bringts mich da auf 'ne Idee (wenn's klappt) ... also so die Datei öffnen und mit MSDN-Library durchsuchenReadFile lesen.
Delphi-Quellcode:
hFile := CreateFile(PChar(FileName), GENERIC_READ,
  FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
MSDN-Library durchsuchenFILE_FLAG_NO_BUFFERING
dieses sollte die WindowsCache umgehen (leider arbeiten nicht alle USB-Device-Treiber korrekt ... zumindestens kommt es mir so vor, daß dort was mit der Cache vollkommen schief läuft)

falls du was schreiben/speichern willst, dann FILE_FLAG_WRITE_THROUGH, welches an der WindowsCache vorbei direkt auf den Datenträger schreiben sollte.

Carsten1234 16. Jan 2009 05:46

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von franktron
P.S. unter Linux heist der Befehl Touch um eine Datei eine Änderung zu erzwingen ohne Sie zu ändern

Linux verhält sich hier "Windowskonform", zeigt also dasselbe Verhalten wie Windows.
Wenn eine Datei auf dem USB-Gerät vom Betriebssystem aus geändert wird, wird - wie bei Windows - auch der Cache angepasst und man sieht immer den aktuellen Stand. Kommt nun aber ein zweiter Master, hier das USB-Gerät selbst, und ändert diese Datei, bekommt das Betriebssystem diese Veränderung nicht mit.

Gruß, Carsten

Carsten1234 16. Jan 2009 07:34

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
FSCTL_MOUNT_VOLUME = $00090024;[/delphi]

1) Das scheint schon nicht schlecht geraten zu sein, allerdings ist der Effekt etwas merkwürdig.
DeviceIoControl soll lt. Doku einen booleanschen Wert zurück liefern. Dies scheint aber erst der Fall zu sein, wenn ich das CloseHandle aufrufe, denn so lange ich das nicht mache, sehe ich zwar den Laufwerksbuchstaben des USB-Geräts im Explorer, mehr aber auch nicht. Nach dem CloseHandle sehe ich das USB-Gerät wieder im Explorer *komplett*.
Anders ausgedrückt: Das FSCTL_DISMOUNT_VOLUME klappt noch, DeviceIOControl liefert TRUE zurück. Bei FSCTL_MOUNT_VOLUME liefert DeviceIOControl so lange FALSE zurück (wenn ich mit dem Explorer auf das USB-Gerät schaue), bis ein CloseHandle erfolgt. Nach dem CloseHandle steht das USB-Gerät im Explorer wieder korrekt zur Verfügung.

Delphi-Quellcode:
const
  FSCTL_DISMOUNT_VOLUME = $00090020;
  FSCTL_MOUNT_VOLUME   = $00090024;

function TForm1.RefreshDrive: boolean;
var hDrive: THandle;
    W: LongWord;
    Drive: string;
    x   : byte;
begin
  hDrive := CreateFile('\\.\X:',
                       GENERIC_READ or GENERIC_WRITE,
                       FILE_SHARE_READ or FILE_SHARE_WRITE,
                       nil, OPEN_EXISTING, 0, 0);
  if hDrive <> INVALID_HANDLE_VALUE then
  begin
    Result:= DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, nil, 0, nil, 0, W, nil);
    // Testweise:
    Delay(100); // warte 100ms
    if (Result) then
    begin
    // 5 Mountversuche
      for x:= 1 to 5 do
      begin
        Result:= DeviceIoControl(hDrive, FSCTL_MOUNT_VOLUME, nil, 0, nil, 0, W, nil);
        Delay(100);
        if (Result) then
          Break;      
      end;
      if (not Result) then
        MessageDlg('Mount fehlgeschlagen!', mtError, [mbOk], 0);
    end
    else
      MessageDlg('Dismount fehlgeschlagen!', mtError, [mbOk], 0);
    CloseHandle(hDrive);
 end;
end;
Anm.: Delay stammt von hier.

2) Das ganze funktioniert leider auch nur so lange wunderprächtig, bis das USB-Gerät selbst den Inhalt der Log-Datei verändert hat. Hat es diese geändert, geht das Mounten total in die Hose. :wall:

Gruß, Carsten

himitsu 16. Jan 2009 08:09

Re: Aktualisierung erzwingen
 
Da bleibt wohl doch die frage, ob dieser Wert wirklich FSCTL_MOUNT_VOLUME ntspricht ... könnte ja auch was ganz anderes sein :stupid:

hast es auch schonmal mit FILE_FLAG_NO_BUFFERING versuchen?

Carsten1234 16. Jan 2009 08:34

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
Da bleibt wohl doch die frage, ob dieser Wert wirklich FSCTL_MOUNT_VOLUME ntspricht ... könnte ja auch was ganz anderes sein :stupid:

hast es auch schonmal mit FILE_FLAG_NO_BUFFERING versuchen?

S. [1]

Mein immer stärker werdender Verdacht geht in Richtung "Bug in Firmware", denn:
So lange das USB-Gerät die Log-Datei selbst nicht verändert, kann ich von meinem Programm aus das Gerät zigmal Dismounten und wieder Mounten. Klappt (jetzt) auch ohne Debug-Modus einwandfrei[1].
Wenn aber das USB-Gerät die Log-Datei verändert und ich dann das Gerät (dis-)mounten, stürzt es so gnadenlos ab, dass es nur noch durch Strom aus/an wieder belebt werden kann.

Gruß, Carsten

[1]
Delphi-Quellcode:
const
  //Konstanten für Volume Funktionen
  METHOD_BUFFERED            = 0;
  {$EXTERNALSYM METHOD_BUFFERED}
  FILE_ANY_ACCESS            = 0;
  {$EXTERNALSYM FILE_ANY_ACCESS}
  FILE_DEVICE_FILE_SYSTEM    = $00000009;
  {$EXTERNALSYM FILE_DEVICE_FILE_SYSTEM}
  FSCTL_LOCK_VOLUME          = (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (6 shl 2)
                                or METHOD_BUFFERED;
  {$EXTERNALSYM FSCTL_LOCK_VOLUME}
  FSCTL_UNLOCK_VOLUME        = ((FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (7 shl 2)
                                or METHOD_BUFFERED);
  {$EXTERNALSYM FSCTL_UNLOCK_VOLUME}
  FSCTL_DISMOUNT_VOLUME      = ((FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (8 shl 2)
                                or METHOD_BUFFERED);

  FSCTL_MOUNT_VOLUME         = ((FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (9 shl 2)
                                or METHOD_BUFFERED);
(...)
  hDrive := CreateFile('\\.\X:',
                       GENERIC_READ (*or GENERIC_WRITE*),
                       FILE_SHARE_READ (*or FILE_SHARE_WRITE*),
                       nil, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
  if hDrive <> INVALID_HANDLE_VALUE then
  begin
    DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, nil, 0, nil, 0, W, nil);
    Delay(100);
    DeviceIoControl(hDrive, FSCTL_MOUNT_VOLUME, nil, 0, nil, 0, W, nil);
    Delay(100);
    CloseHandle(hDrive);
    Delay(600);
 end;

himitsu 16. Jan 2009 09:35

Re: Aktualisierung erzwingen
 
Ich meinte nur FILE_FLAG_NO_BUFFERING ohne Dismounten,

also einfach Datei so öffnen und dann auslesen?

Delphi-Quellcode:
hFile := CreateFile('X:\LogFile.txt', GENERIC_READ, FILE_SHARE_READ,
  nil, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
ReadFile(hFile, Buffer ...
CloseHandle(hFile);

Luckie 16. Jan 2009 09:42

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
man könnte jetzt auch mal versuchen zu raten :angel2:

Oder man guckt in den entsprechenden Header-Dateien vom Windows SDK nach. :?

himitsu 16. Jan 2009 09:45

Re: Aktualisierung erzwingen
 
Daheim hab'sch das grad nicht installiert und hier isses leider nicht drauf -.-''

DerDan 16. Jan 2009 10:00

Re: Aktualisierung erzwingen
 
Hallo,

kann den USB Host nicht die Daten zum PC Streamen.

man könnte den LOG ja zum beispiel so übertragen, wie es über eine USB RS232 Schnittstelle passiert?

mfg

DerDan

Carsten1234 16. Jan 2009 10:50

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von himitsu
Ich meinte nur FILE_FLAG_NO_BUFFERING ohne Dismounten,
[/delphi]

Könnte ich so auch nochmal versuchen, aber die Tendenz zum Firmwarebug wird größer.
Weil: Ein Log-Eintrag wird nur dann erzeugt, wenn sich der Zustand am/im USB-Gerät ändert (es gibt zwei Zustände ähnl. Start/Stop). Ändere ich den Zustand nur einmal und versuche dann auszulesen, stürzt das Gerät ab.
Ändere ich hingegen zwei Mal den Zustand, stürzt es
1. nicht ab
und
2. ich kann die aktualisierte Log-Datei frisch auslesen!
Der Windows-Cache ist aktualisiert, der Geräteabsturz ist nicht mein Problem. :stupid:

Dank Dir nochmal ganz herzlich, Gruß und schönes WoEn, Carsten

P.S. Dank natürlich auch allen anderen für ihre Lösungsvorschläge

Carsten1234 16. Jan 2009 10:51

Re: Aktualisierung erzwingen
 
Zitat:

Zitat von Luckie
Oder man guckt in den entsprechenden Header-Dateien vom Windows SDK nach. :?

Hamma da, nix gefunden. :gruebel:

devidespe 22. Okt 2009 16:31

Re: Aktualisierung erzwingen
 
Mich würde mal interessieren, ob das Problem schließlich gelöst wurde?

Ich habe hier die gleiche Ausgangssituation, allerdings mit einer CD. Auf der befinden sich 6 große Dateien, die ich nacheinander auf die Festplatte kopiere. Das alles in einer Endlosschleife, um eine Systemlast zu erzwingen.

Spätestens ab dem 2. Lesevorgang kommen die Daten aus dem Windows-Cache. Ich greife dabei nicht mit Assign und Reset auf die Dateien der CD zu, sondern mit TFileStream. Existiert hier eine Funktion, um den Windows-Cache zu deaktivieren?

Die Unmount-Variante wäre noch eine Idee, wenn ich das Laufwerk danach direkt wieder mounte. Leider habe ich zu FSCTL_MOUNT_VOLUME nix gefunden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:53 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz