Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Fehlermeldung bei Schreiben nach CSIDL_APPDATA (https://www.delphipraxis.net/159860-fehlermeldung-bei-schreiben-nach-csidl_appdata.html)

Bjoerk 15. Apr 2011 17:42

Delphi-Version: 5

Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Die folgende Routine ist Bestandteil eines iniFile Parsers. SaveFile ist gelegentlich (!?) false. Ich suche schon seit Wochen, in den Apps kann ich jedoch keine Fehler entdecken. Dateien vom Typ TStrIniFile werden procdure intern vereinbart, erzeugt und freigegegen. Bei free wird ggf. SaveToFile aufgerufen. Ich bin mir sicher, daß innerhalb von TStrInfile kein Fehler ist.
Delphi-Quellcode:
function TStrIniFile.SaveFile : boolean;
var
  f: TextFile;
  i: integer;
begin
  RESULT:=false;
  AssignFile(f,FileName);
  {$I-} Rewrite(f); {$I+}
  if IoResult=0 then
  begin
    RESULT:=true;
    for i:=0 to Count-1 do
    begin
      if i>0 then
        if posIS[i]<0 then writeln(f);
      writeln(f,item[i]);
    end;
    closeFile(f);
  end;
  sleep(10);
  *** if not RESULT then ***
    MessageDlg(application.ExeName+': '+FileName+' is not ready for WRITE.',mtWarning,[mbOk],0);
end;

procedure TStrIniFile.UpdateFile;
begin
  if FileName<>'' then
  begin
    SaveFile;
    IniFileChanged:=false;
  end;
end;

destructor TStrIniFile.Destroy;
begin
  if IniFileChanged then UpdateFile;
  inherited;
end;
Das Verzeichnis der Dateien ist:
Delphi-Quellcode:
verzA:=VerzMitSlash(trim(GetShellFolderPath(CSIDL_APPDATA)))+'Abel\';
Ein Hauptmenu wird mit einem {$R Adminrechte.res} gestartet und ruft die verschiedenen Apps so auf:
Delphi-Quellcode:
rocedure TForm101.ExecuteWinFileAndWait(Prozess: String);
var SI: TStartupInfo;
    PI: TProcessInformation;
begin
  screen.cursor:=crAppStart;
  FillChar(SI, SizeOf(SI), 0);
  SI.cb:= SizeOf(SI);
  SI.wShowWindow:= SW_SHOWNORMAL;
  if not CreateProcess(nil,PChar(Prozess),nil,nil,false,NORMAL_PRIORITY_CLASS,nil,PChar(VerzE),SI,PI) then
  begin
    messagedlg('... kann den Prozess nicht ausführen.',mterror,[mbok],0);
    EscDateiAnlegen;
  end
  else
  Begin
    WaitForSingleObject(PI.hProcess,INFINITE);
  End;
  screen.cursor:=crdefault;
end;
Woran könnte das liegen, daß es ab und zu nicht geht? Alle Ideen sind willkommen. // D2007

Klaus01 15. Apr 2011 17:52

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Hallo,

es wäre dann vielleicht hilfreich den ErrorCode von IOResult zu erfahren.
Habe deswegen einige Änderungen im Code vorgenommen.

Delphi-Quellcode:
function TStrIniFile.SaveFile : boolean;
var
  f: TextFile;
  i: integer;
  errorCode : Integer;
begin
  RESULT:=false;
  AssignFile(f,FileName);
  {$I-} Rewrite(f); {$I+}
  errorCode := IOResult;
  if errorCode=0 then
  begin
    RESULT:=true;
    for i:=0 to Count-1 do
    begin
      if i>0 then
        if posIS[i]<0 then writeln(f);
      writeln(f,item[i]);
    end;
    closeFile(f);
  end;
  sleep(10);
  *** if not RESULT then ***
    MessageDlg(application.ExeName+': '+FileName+' is not ready for WRITE ['+sysErrorMessage(errorCode)+'].',mtWarning,[mbOk],0);
end;

Grüße
Klaus

Bjoerk 15. Apr 2011 19:11

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Hi Klaus,

Exception.create bringt: Kann die Datei nicht öffnen.

Was mir aber eben einfällt, was passiert denn, wenn die gleiche Datei von zwei Instanzen gleichzeitig geöffnet ist und im Destroy der Form beide sozusagen gleichzeitig geschrieben werden sollen. Gibt es da eine queue oder dann die Fehlermeldung? Ist mir eben eingefallen. Kann man ein Textdatei sharen wie einen Stream?

Gruß
Thomas

Klaus01 15. Apr 2011 19:25

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Hallo,

rewrite öffnet die Datei exclusiv.

Was bezweckst Du denn damit das zwei Instanzen die Datei bearbeiten dürfen?

Die Configurationeinstellungen würde ich zentral bearbeiten (lesen und schreiben)
und dann nur von einer Instanz (eine Singleton Klasse würde sich da anbieten).

Grüße
Klaus

Bjoerk 15. Apr 2011 19:31

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Liste der Anhänge anzeigen (Anzahl: 1)
Anlage errorCode

Klaus01 15. Apr 2011 19:33

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Zitat:

Zitat von Bjoerk (Beitrag 1095453)
Anlage errorCode

siehe Post #4

Grüße
Klaus

Bjoerk 15. Apr 2011 19:40

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Stimmt, eigentlich ja, ist historisch begründet. Die Datei wird an 100-200 Stellen in der Software gelesen und/oder geschrieben, in der Form, in anderen Units, in mehreren Komponenten usw.. Ich werde die Datei jetzt global EINMAL in der Unit in initialization erzeugen und in finalization freigeben. Müsste doch funktionieren?

Namenloser 15. Apr 2011 19:43

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
[OT]Mal was anderes: Was soll das
Delphi-Quellcode:
Sleep(10);
?[/OT]

Klaus01 15. Apr 2011 19:54

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Zitat:

Zitat von Bjoerk (Beitrag 1095457)
.. Ich werde die Datei jetzt global EINMAL in der Unit in initialization erzeugen und in finalization freigeben. Müsste doch funktionieren?

Sollte funktionieren, wenn Du dann die Daten aus der Liste (item[i]) liest
und darin auch die Daten änderst.

Grüße
Klaus

Bjoerk 15. Apr 2011 20:07

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Hi Philip, war eine Verzweiflungstat für Give another Process a chance.

Klaus, funktioniert das auch noch bei Komponenten, die werden u.U. zur Laufzeit schon free und benutzen das selbe initialization/finalization wie die Formulare.

Klaus01 15. Apr 2011 20:51

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Zitat:

Zitat von Bjoerk (Beitrag 1095473)
Klaus, funktioniert das auch noch bei Komponenten, die werden u.U. zur Laufzeit schon free und benutzen das selbe initialization/finalization wie die Formulare.

.. ich verstehe nicht genau was Du damit sagen willst.
initialization wird genau einmal ausgeführt.
Wenn mehrere Units einen initialization Abschnitt haben entscheidet die Reihenfolge
in der uses-Klausel darüber wann welcher initialization Abschnitt ausgeführt wird.

Grüße
Klaus

Bjoerk 15. Apr 2011 21:28

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
vorübergehend habe ich es jetzt erst mal so geändert:

Delphi-Quellcode:
implementation

var
  inUseReadFileName: string='';
  inUseWriteFileName: string='';

function TStrIniFile.isFileReadyForRW: boolean;
var
  r,w: boolean;
begin
  RESULT:=true;
  r:=UpperCase(FileName)=UpperCase(inUseReadFileName);
  w:=UpperCase(FileName)=UpperCase(inUseWriteFileName);
  if (r or w) then
  begin
    repeat
      RESULT:=false;
    until ((inUseReadFileName='') and (inUseWriteFileName=''));
    RESULT:=true;
  end;
end;

function TStrIniFile.LoadFile : boolean;
var
  f: TextFile;
  u: string;
  errorCode: Integer;
begin
  RESULT:=false;
  if IniFileExists then
  begin
    if isFileReadyForRW then  <--
    begin
      AssignFile(f,FileName);
      {$I-} Reset(f); {$I+}
      errorCode:= IOResult;
      if errorCode=0 then
      begin
        RESULT:=true;
        inUseReadFileName:=FileName; <--
        while not eof(f) do
        begin
          readln(f,u);
          if isIniRow(u) then addItem(u);
        end;
        closeFile(f);
      end;
      if not RESULT then
        MessageDlg(application.ExeName+': '+FileName+' ['+sysErrorMessage(errorCode)+'].',mtWarning,[mbOk],0);
    end;
  end;
  inUseReadFileName:=''; <--
end;

function TStrIniFile.SaveFile : boolean;
var
  f: TextFile;
  i, errorCode: Integer;
begin
  RESULT:=false;
  if FileName<>'' then
  begin
    if isFileReadyForRW then <--
    begin
      AssignFile(f,FileName);
      {$I-} Rewrite(f); {$I+}
      errorCode:= IOResult;
      if errorCode=0 then
      begin
        RESULT:=true;
        inUseWriteFileName:=FileName; <--
        for i:=0 to Count-1 do
        begin
          if i>0 then
            if posIS[i]<0 then writeln(f);
          writeln(f,item[i]);
        end;
        closeFile(f);
      end;
      if not RESULT then
        MessageDlg(application.ExeName+': '+FileName+' ['+sysErrorMessage(errorCode)+'].',mtWarning,[mbOk],0);
    end;
  end;
  inUseWriteFileName:=''; <--
end;

Bjoerk 15. Apr 2011 21:42

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
besser ist das:
Delphi-Quellcode:
function TStrIniFile.isFileReadyForRW: boolean;
begin
  if UpperCase(FileName)=UpperCase(inUseReadFileName) then
  begin
    repeat until inUseReadFileName='';
  end;
  if UpperCase(FileName)=UpperCase(inUseWriteFileName) then
  begin
    repeat until inUseWriteFileName='';
  end;
  RESULT:=true;
end;

Bjoerk 16. Apr 2011 13:07

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Zitat:

.. ich verstehe nicht genau was Du damit sagen willst.
initialization wird genau einmal ausgeführt.
Wenn mehrere Units einen initialization Abschnitt haben entscheidet die Reihenfolge
in der uses-Klausel darüber wann welcher initialization Abschnitt ausgeführt wird.
Klaus, ich meinte, ob das Applicationsweit gilt, auch z.B. dann, wenn Komponenten, die modale Ereignisse sind und den gleichen initialization Abschnitt benutzen. Wird der dann bei Komp.Execute nocheinmal ausgeführt? Kann ich aber auch durch ein einfaches Showmessage im initialization Abschnitt selbst testen.

Auf alle Fälle erst mal ein kräftiges Dankeschön für deinen Support, auch an Philip.:thumb:

Jetzt habe ich gesehen, daß mache Programme gleichzeitig gestartet werden und im OnShow Ereignis erst mal kräftig iniDateien lesen, und zwar die selben. Da bleibt wohl nur diese Variante.

Delphi-Quellcode:
procedure Wait (var N: integer);
var
  fTime: Cardinal;
begin
  fTime:=GetTickCount;
  repeat until (GetTickCount-fTime) > 500;
  N:=N+1;
end;

function TStrIniFile.TryOpenFile (var f: TextFile; const fWrite: boolean): boolean;
var
  N,IO: integer;
begin
  N:=0;
  AssignFile(f,FileName);
  if not fWrite then
  begin
    Repeat
      {$I-} Reset(f); {$I+}
      IO:=IOResult;
      if IO<>0 then Wait(N);
    Until ((IO=0) or (N=10));
  end
  else
  begin
    Repeat
      {$I-} Rewrite(f); {$I+}
      IO:=IOResult;
      if IO<>0 then Wait(N);
    Until ((IO=0) or (N=10));
  end;
  RESULT:=(IO=0);
  if not RESULT then
    MessageDlg(Application.ExeName+': '+FileName+' ['+SysErrorMessage(IO)+'].',mtWarning,[mbOk],0);
end;

DeddyH 16. Apr 2011 14:29

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Vielleicht wäre die Verwendung von z.B. FileStreams eine Alternative, da kann man einen Mode (fmShareXXX) mit angeben.

himitsu 16. Apr 2011 15:03

AW: Fehlermeldung bei Schreiben nach CSIDL_APPDATA
 
Könnte man beim AssignFile und Co. auch ... Delphi-Referenz durchsuchenFileMode, wenn man weiß wie :angle2:,
aber mal was Aktuelleres/OOPmäßigeres kann ja nicht schaden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:27 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