Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Ungültiges Handle
HenryHux - Fr 10.12.10 13:48
Titel: Ungültiges Handle
Hi,
in meinem Bilderkennungsprogramm bekomme ich nach einer längeren Laufzeit (>20 Min) den o.g Fehler.
Ich bekomme nicht mehr Informationen vom Debugger als die Meldung ungültiges Handle und er zeigt immer auf verschiedene Befehle, die rein garnichts mit Handles zu tun haben.
Insofern habe ich leider keine Idee wodran das liegen könnte.
Der Quelltext ist viel zu lang als das ich ihn einfach posten könnte, deshalb wollte ich mal fragen, ob ihr eventuell einen Verdacht habt.
Handles benutze ich aber in folgenden Funktionen:
Einmal als sleep Alternative, dürfte eigentlich keine Probleme machen :
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure wait(Milliseconds: Integer); var Tick: DWORD; Event: THandle; begin Event := CreateEvent(nil, False, False, nil); try Tick := GetTickCount + DWORD(Milliseconds); while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do begin Application.ProcessMessages; Milliseconds := Tick - GetTickCount; end; finally CloseHandle(Event); end; end; |
Und einmal als Screenshot Funktion, dadran könnte es liegen, da sie immer mit verschiedenen Parametern aufgerufen wird, aber auch die zeit nach 10k durchläufen keine Fehlermeldung:
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:
| function Screenshot(Bounds:TRect; Links, Rechts, Oben, Unten : Integer) : tbitmap; inline; var DeskCanvas: TCanvas; ShotTargetBitmap : TBitmap; Cut : TRect; begin result:=TBitmap.Create; bounds.left:=bounds.Left+verschiebenx; bounds.right:=bounds.right+verschiebenx; bounds.top:=bounds.top+verschiebeny; bounds.bottom:=bounds.bottom+verschiebeny; try DeskCanvas := TCanvas.Create; DeskCanvas.Handle := GetDC(0); Shottargetbitmap:=TBitmap.create; try ShotTargetbitmap.Width := Round((Bounds.Right - Bounds.left) * 1); ShotTargetbitmap.Height := Round((Bounds.Right - Bounds.Left) * 1); BitBlt(ShotTargetBitmap.Canvas.Handle, 0 ,0, bounds.Right-bounds.left, bounds.Bottom-bounds.top, DeskCanvas.handle, bounds.Left, bounds.Top, SRCCOPY); Cut.Left := Links; Cut.Top := Oben; Cut.Right := Rechts; Cut.Bottom := Unten; result.Width := Cut.Right - Cut.Left; result.Height := Cut.Bottom - Cut.Top; BitBlt(result.Canvas.Handle, 0, 0, Cut.Right, Cut.Bottom, ShotTargetBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY); finally ReleaseDC(0,DeskCanvas.Handle); end; finally FreeAndNil(deskcanvas); FreeAndNil(ShotTargetBitmap); end; end; |
Wie gesagt, ich habe keine Idee was da schief läuft, vlt fällt euch ja was ein.
Lg
Henry
jaenicke - Fr 10.12.10 15:02
Das hört sich nach einem Problem mit Threads an. Und zwar verwendest du da vermutlich irgendwelche visuellen Komponenten oder Klassen, die einen DC benutzen, z.B. TBitmap.
HenryHux - Fr 10.12.10 15:24
Hmm und was könnte das sein?
Threads habe ich keine, ohne Klassen kommt das Problem auch nicht.
Visuelle Komponenten sind auch keine drin außer labels.
Und die einzige Funktion die ein DC benutzt ist die Screenshot Funktion, die ich schon gepostet hab.
Wenn man das Problem nicht genauer lokalisieren kann, kann ichs einfach irgendwie ignorieren?
Lg
jaenicke - Fr 10.12.10 15:36
Kann es sein, dass du die erzeugte Bitmap, die du zurückgibst (äußerst schlechter Stil... :roll:), nicht wieder freigibst? Dann hat dein Programm einfach zu viele GDI-Handles...
Schau einmal nach deren Anzahl im Taskmanager / Process Explorer.
HenryHux - Fr 10.12.10 15:57
Okay, das wird ein Problem sein, dass ich die nicht wieder freigebe.
Wie kann ich denn den Rückgabewert von Funktionen nach Abschluss der Funktion löschen oder was wäre ein besserer Stil?
Dachte mir, das würde so am saubersten gehen, denn dann kann der Aufruf einer anderen Funktion ja einfach so aussehen:
Delphi-Quelltext
1: 2: 3: 4:
| ComparePicture:= Tbitmap.create; ComparePicture.LoadFromFile(Path+'Ordner2\'+'bsp.bmp'); result := CompareImages(Screenshot(Rect(sittingoutlinks,sittingoutoben,sittingoutlinks + 100,sittingoutoben + 100),20,100,85,100), ComparePicture); |
Wenn ich eine globale Bitmap benutze gäbe das keine Probleme?
Lg
jaenicke - Fr 10.12.10 16:01
Übergib die (vorher erzeugt, wenn es sein muss als Feld der Klasse im Konstruktor) als Parameter und gib die danach wieder frei. Das ist die einzige wirklich saubere Lösung.
HenryHux - Fr 10.12.10 16:19
Ok, nochmal zum Verständnis, ob ich dich richtig verstanden habe.
Angenommen ich mach ne neue TBitmap var, nennen wir die TBmp.
Die Create ich in der Screenshot Funktion und .Free sie bei nem except.
Dann rufe ich die Funktion auf in ner anderen Prozedur und arbeite mit der TBmp und .Free die dann auf finally.
Ist das also so io?
Das einzige was passieren könnte ist, dass er in der Funktion einen except bekommt die Variable auflöst und eine andere Prozedur versucht mit der zu arbeiten und auch abstürzt weil die versucht die aufzulösen?
LG
Gerd Kayser - Fr 10.12.10 17:51
jaenicke hat folgendes geschrieben : |
Kann es sein, dass du die erzeugte Bitmap, die du zurückgibst (äußerst schlechter Stil... :roll:), nicht wieder freigibst? Dann hat dein Programm einfach zu viele GDI-Handles...
Schau einmal nach deren Anzahl im Taskmanager / Process Explorer. |
Ich würde das einfach mit "ReportMemoryLeaksOnShutdown" überprüfen. Beim Programmende zeigt das die Speicherlecks an.
HenryHux - Fr 10.12.10 18:34
Ich weiß nicht, was es genau war aber nachdem ich die Bitmaps nicht als Rückgabewert übergebe, klappt es (vorerst).
FastMM4 zeigt mir jetzt auch keine Leaks mehr an.
Danke!
Lg
jaenicke - Sa 11.12.10 01:39
Und dann hier auch noch eine saubere Variante (gekürzt), falls du es noch nicht so hast:
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:
| function CreateSnapshot(AWindow: HWND; ATarget: TBitmap): Boolean; var DesktopDC: HDC; begin Result := False; DesktopDC := GetDC(AWindow); try ... Result := True; finally ReleaseDC... end; end;
var MySnapshot; TBitmap; begin MySnapshot := TBitmap.Create; try if CreateSnapshot(0, MySnapshot) then WorkWithMySnapshot... else finally MySnapshot.Free; end; end; |
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!