Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Exception EOSError Systemfehler Code 1158
D. Annies - Do 20.01.11 20:10
Titel: Exception EOSError Systemfehler Code 1158
Hi, Delpher,
ich kopiere per Delphi-Programm viele Dateien z.B. von D nach H.
Uv's werden angelegt, alles läuft bestens.
Gegen Ende der umfangreichen Transaktion tritt der obige Fehler auf mit der Erläuterung:
Der aktuelle Prozess verwendet alle Handles der zulässigen Höchstanzahl für Windows Managerobjekte
Prozess wurde angehalten ...
Was ist denn da los?
Gruß, Detlef
jaenicke - Do 20.01.11 20:53
Das bedeutet wohl, dass du die Dateihandles beim Kopieren nicht wieder freigibst. Und wenn alle verfügbaren Handles von dir in Beschlag genommen sind, ist Schluss.
D. Annies - Do 20.01.11 21:41
Klingt sehr plausibel!
Woran erkenne ich ein Dateihandle? Wie vergebe / löse ich ein Dateihandle?
Gruß, Detlef
jaenicke - Do 20.01.11 21:44
Das kommt ja drauf an wie du kopierst...
Nebenbei zeigen der Taskmanager bzw. der Process Explorer auch an wie viele Handles ein Programm gerade verwendet.
D. Annies - Do 20.01.11 21:56
Ich kopiere folgendermaßen:
Delphi-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:
| if (fileexists(home_filename)) and (fileexists(work_filename)) then begin
if (FileDateToDateTime(FileAge(work_filename)) <> FileDateToDateTime(FileAge(home_filename))) and (fileage(work_filename) + 3600 <> FileAge(home_filename)) and (fileage(work_filename) <> FileAge(home_filename) + 3600) then begin erg := xmessagedlg('ArchivBit wurde gesetzt' +#13 + 'Soll ' + work_filename + ' '+#13+ datetimetostr(filedatetodatetime(FileAge(work_filename))) +#13+ 'durch ' + home_filename + ' '+#13+ datetimetostr(filedatetodatetime(FileAge(home_filename))) +#13+ ' ersetzt werden?', mtConfirmation, [mbYes, mbno, mbcancel], ['ja', 'nein', 'Abbrechen'], self.font); case erg of mryes : CopyFile(PChar(home_filename), PChar(work_filename), FALSE); mrcancel : raus := true; end; end end else if (fileexists(home_filename)) and (not fileexists(work_filename)) then begin erg := xmessagedlg('Soll '+ work_filename + #13+ ' angelegt werden?', mtConfirmation, [mbYes, mbNo, mbcancel], ['ja', 'nein', 'Abbrechen'], self.font); case erg of mryes : begin if not directoryexists(ziel+uvname) then CreateDir(ziel+uvname); CopyFile(PChar(home_filename), PChar(work_filename), TRUE); end; mrcancel : raus := true; end; end; |
Das Handle ist wohl der PChar (??)
(Wie) Geht es anders / besser?
Gruß, Detlef
Moderiert von
Narses: Delphi-Tag repariert.
jaenicke - Do 20.01.11 22:02
Da ist kein Handle, das du explizit benutzt. In den verwendeten Delphifunktionen wird das ziemlich sicher alles richtig freigegeben.
Ich habe aber einen Verdacht:
Ich rate einmal, dass du FindFirst usw. benutzt um nach den Dateien zu suchen. Kann es sein, dass du vergessen hast, diese Suchhandles mit FindClose auch wieder zu schließen? ;-)
D. Annies - Do 20.01.11 23:05
Ich dachte erst: Volltreffer, aber ich glaube, nicht:
Die komplette Proc:
Delphi-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: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109:
| Procedure TBuchMain.FindFiles (aPath, aFindMask: String; aWithSub: Boolean); Var FindRec : tSearchRec; home_filename, work_filename, Pfad, uvname, start, ziel : string; n, erg : integer; raus : boolean; Begin raus := false; If (aPath = '') or (aFindMask = '') then Exit; If aPath[Length(aPath)] <> '\' Then aPath := aPath + '\'; Pfad := aPath; If FindFirst (aPath + aFindMask, faAnyFile - faDirectory, FindRec) = 0 Then Repeat If (FindRec.Name <> '.') and (FindRec.Name <> '..') Then begin if aktuser <> 'an s' then begin if (pos('home.', FindRec.Name) > 0) or (pos('.pas', FindRec.Name) > 0) or (pos('.dfm', FindRec.Name) > 0) or (pos('.res', FindRec.Name) > 0) or (pos('.exe', FindRec.Name) > 0) or (pos('.dpr', FindRec.Name) > 0) OR (pos('.ddp', FindRec.Name) > 0) or (pos('.dof', FindRec.Name) > 0) or (pos('.dsk', FindRec.Name) > 0) or (pos('.dcu', FindRec.Name) > 0) or (pos('.cfg', FindRec.Name) > 0) then begin end end else begin if (pos('.ddp', FindRec.Name) > 0) or (pos('.dof', FindRec.Name) > 0) or (pos('.dsk', FindRec.Name) > 0) or (pos('.dcu', FindRec.Name) > 0) or (pos('.cfg', FindRec.Name) > 0) then begin end else if (FindRec.Name[1] = '_') or (pos('.~', FindRec.Name) > 0) or (pos('bestand_', FindRec.Name) > 0) or (pos('temp_', FindRec.Name) > 0) or (pos('Geburtstag_', FindRec.Name) > 0) then begin showmessage(apath + findrec.name + ' wird gelöscht'); DeleteFile(apath + FindRec.name) end else begin uvname := ''; for n := pos('Buecherei\', Pfad)+10 to length(Pfad) do uvname := uvname + apath[n]; if aPath[1] = stdwert[1] then begin start := stdwert; ziel := label30.Caption; home_filename := stdwert + uvname + FindRec.Name; work_filename := label30.caption + uvname + FindRec.name; end else begin start := label30.Caption; ziel := stdwert; home_filename := label30.caption + uvname + FindRec.name; work_filename := stdwert + uvname + FindRec.name; end; if (fileexists(home_filename)) and (fileexists(work_filename)) then begin
if (FileDateToDateTime(FileAge(work_filename)) <> FileDateToDateTime(FileAge(home_filename))) and (fileage(work_filename) + 3600 <> FileAge(home_filename)) and (fileage(work_filename) <> FileAge(home_filename) + 3600) then begin erg := xmessagedlg('ArchivBit wurde gesetzt' +#13 + 'Soll ' + work_filename + ' '+#13+ datetimetostr(filedatetodatetime(FileAge(work_filename))) +#13+ 'durch ' + home_filename + ' '+#13+ datetimetostr(filedatetodatetime(FileAge(home_filename))) +#13+ ' ersetzt werden?', mtConfirmation, [mbYes, mbno, mbcancel], ['ja', 'nein', 'Abbrechen'], self.font); case erg of mryes : CopyFile(PChar(home_filename), PChar(work_filename), FALSE); mrcancel : raus := true; end; end end else if (fileexists(home_filename)) and (not fileexists(work_filename)) then begin erg := xmessagedlg('Soll '+ work_filename + #13+ ' angelegt werden?', mtConfirmation, [mbYes, mbNo, mbcancel], ['ja', 'nein', 'Abbrechen'], self.font); case erg of mryes : begin if not directoryexists(ziel+uvname) then CreateDir(ziel+uvname); CopyFile(PChar(home_filename), PChar(work_filename), TRUE); end; mrcancel : raus := true; end; end; end; end end; Until FindNext(FindRec) <> 0; FindClose(FindRec);
If (Not aWithSub) or (raus) Then Exit; If FindFirst (aPath + '*.*', faAnyFile, FindRec) = 0 Then Repeat If (FindRec.Name <> '.') and (FindRec.Name <> '..') Then If Boolean (FindRec.Attr and faDirectory) Then If ((FindRec.Attr and faDirectory) <> 0) then FindFiles(aPath + FindRec.Name, aFindMask, aWithSub); Until FindNext(FindRec) <> 0; FindClose(FindRec); End; |
Uff, Detlef
jaenicke - Do 20.01.11 23:38
Dann bleibt nur im Taskmanager bzw. besser dem Process Explorer auf die Handles zu achten und zu schauen ob und wo deren Anzahl zunimmt.
D. Annies - Fr 21.01.11 07:42
Ich habe keine Ahnung, wie ich dabei vorgehen könnte. :(((
(Nun, den Process Manager habe ich, aber damit umgehen kann ich nicht)
jaenicke - Fr 21.01.11 08:08
Im Anhang einmal ein Screenshot. Das sind die Eigenschaften eines Prozesses. Und dort steht die Handleanzahl. Wenn du jetzt im Debugger schrittweise durchgehst, siehst du wo diese steigt oder sinkt.
Und wenn sie bei der selben Operation immer weiter steigt und nie wieder auf den alten Wert zurückgeht, stimmt etwas nicht.
D. Annies - Fr 21.01.11 10:54
Es läuft doch darauf hinaus, dass ich da im Code einen Logikfehler eingebaut habe,
kann den jemand auch so erkennen? - Ich vermute ihn bei der Rekursion am Proc-Ende.
Ich krieg den Fehler nicht raus :( (trotz guter Hilfe bisher)
Detlef
zuma - Fr 21.01.11 11:49
Ich find merkwürdig, das du eine Methode 'FindFiles' hat, die sucht UND kopiert, beides in einem. Mein Lösungsansatz wäre gewesen, 2 Methoden zu haben:
Eine Methode, die die zu kopierenden Dateien ermittelt (und wirklich auch nur das macht) und z.b als Liste wieder gibt
und
eine Methode, die anhand einer übergebenen Liste Dateien kopiert (ala kopiere(xDateiliste, xZiel).
dein Findclose wird erst nach abarbeiten der repeatschleife aufgerufen, du kopierst aber innerhalb der schleife.
D. Annies - Fr 21.01.11 12:36
Hi, zuma,
das ist richtig, aber wenn ich das Findclose in die Schleife setze, wird immer nur eine Datei
pro Verzeichnis kopiert.
Es sind zwar 1348 Dateien insgesamt, aber nicht > 1000 in einem UV!
Detlef
zuma - Fr 21.01.11 14:38
Hallo Detlef,
das ist richtig, aber mein Lösungsvorschlag war ja auch nicht, das FindClose in die Schleife zu verlagern, sondern deine Schleife in 2 aufzuteilen. In der jetzigen Variante wirste das Kopieren raus und merkst dir dort stattdessen die Dateie, die du kopieren möchtest (z.B. in einer Stringlist). Das Ergebnis (also die gefüllte Stringlist) übergibst du dann an die 2te, neu zu erstellende Methode, die dann das eigentliche Copy macht.
D. Annies - Fr 21.01.11 19:45
hab jetzt eine Menge versucht, noch ohne Erfolg: Ich scheitere an der Erstellung der Proc,
die dann für das Kopieren en bloc zuständig sein soll. Wobei ja kopiert oder ersetzt werden soll!
Wie könnte die aussehen, sprich welcher Befehl gilt da? CopyFile(), CopyFileEx() oder was?
jaenicke - Fr 21.01.11 20:04
An SHFileOperation könntest du auch gleich mehrere Dateien auf einmal übergeben.
Welchen Befehl du da nutzt, ist im Grunde nicht so wichtig. Wobei ich vermute, dass SHFileOperation mit jeweils mehreren Dateien einen Geschwindigkeitsvorteil bringen könnte.
BenBE - Fr 21.01.11 20:32
jaenicke hat folgendes geschrieben : |
An SHFileOperation könntest du auch gleich mehrere Dateien auf einmal übergeben.
Welchen Befehl du da nutzt, ist im Grunde nicht so wichtig. Wobei ich vermute, dass SHFileOperation mit jeweils mehreren Dateien einen Geschwindigkeitsvorteil bringen könnte. |
Ist in der Regel 5%, teilweise bis zu 15% langsamer als die Dateien selbst mit geeigneter Puffergröße zu kopieren. Hatte da mal selber mir ein Tool geschrieben, was immer Meilenweit vor dem Explorer fertig war.
D. Annies - Fr 21.01.11 20:40
Aber leider nicht mit D6Enter. :(
D. Annies - Sa 22.01.11 08:17
So, ich hab's gelöst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| if (fileexists(home_filename)) and (not fileexists(work_filename)) then begin erg := xmessagedlg('Soll '+ work_filename + #13+ ' angelegt werden?', mtConfirmation, [mbYes, mbNo, mbcancel], ['ja', 'nein', 'Abbrechen'], self.font); case erg of mryes : begin if not directoryexists(ziel+uvname) then CreateDir(ziel+uvname); CopyFile(PChar(home_filename), PChar(work_filename), TRUE);
end; mrcancel : raus := true; end; end; |
Ich lasse die xmessagedld-Abfrage weg, nur die drei Zeilen "in der Mitte" lasse ich stehen, damit auf jeden Fall
(ohne Nachfrage) kopiert wird!
Yes! Uff!
Gruß, Detlef
P.S. Weiß jemand, warum das die Handles "spart"?
jaenicke - Sa 22.01.11 09:10
D. Annies hat folgendes geschrieben : |
| P.S. Weiß jemand, warum das die Handles "spart"? |
Naja, ich weiß ja nicht was xmessagedlg für eine Funktion ist, aber ich könnte wetten, dass da etwas nicht freigegeben wird...
Vielleicht der angezeigte Dialog selbst? Der beinhaltet natürlich gleich mehrere Handles und Objekte.
Mit FastMM kannst du solche nicht freigegebenen Sachen aber auch finden.
D. Annies - Sa 22.01.11 10:21
Hi, Sebastian,
danke für deine Nachsorge, hier der xMessageDlg-Code.
Bin mal neugierig, was du findest:
Delphi-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:
| function TBuchMain.xMessageDlg(const Msg: string; DlgType : TMsgDlgType; Buttons : TMsgDlgButtons; Captions: array of string; myFont:TFont) : Integer; var aMsgDlg : TForm; CaptionIndex, i : integer; dlgButton : TButton; begin aMsgDlg := CreateMessageDialog(Msg, DlgType, buttons); aMsgDlg.Font.style := []; aMsgDlg.setbounds(300,520,650,200); CaptionIndex := 0; for i := 0 to aMsgDlg.ComponentCount - 1 do begin if (aMsgDlg.Components[i] is TButton) then begin dlgButton := TButton(aMsgDlg.Components[i]); dlgButton.Left := 100*(i-2) + 10*(i+1); dlgbutton.width := 100; if CaptionIndex > High(Captions) then Break; dlgButton.Caption := Captions[CaptionIndex]; Inc(CaptionIndex); end; end; Result := aMsgDlg.ShowModal; end; |
Bis denne, Detlef
jaenicke - Sa 22.01.11 11:25
aMsgDlg wird nicht freigegeben.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| aMsgDlg := ... try ... Result := aMsgDlg... finally aMsgDlg.Free; end; |
D. Annies - Sa 22.01.11 14:30
Danke, Sebastian! - das heißt also: jedesmal, wenn ich etwas der Form .create habe,
sollte ich mit try .. except arbeiten und mit free, richtig?
Detlef
jaenicke - Sa 22.01.11 16:17
Mit try..finally. ;-) Es sei denn du hast einen Owner angegeben. In diesem Fall gibt dieser Owner bei dessen Zerstörung das Objekt frei. Wenn du das selbst machen möchtest, solltest du nil angeben.
In diesem Fall hier wird innerhalb CreateMessageDialog Application als Owner verwendet. Das heißt beim Beenden der Anwendung würde der Dialog auch freigegeben. Aber eben erst dann, und wenn du zu viele solcher Dialoge erzeugst, bleiben die alle bis dahin im Speicher. ;-)
D. Annies - So 23.01.11 21:57
Danke, Sebastian
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!