Autor Beitrag
HenryHux
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 10.12.10 13:48 
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 :
ausblenden 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 > 0and
      (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:
ausblenden volle Höhe 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, 00, 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Fr 10.12.10 17:51 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 11.12.10 01:39 
Und dann hier auch noch eine saubere Variante (gekürzt), falls du es noch nicht so hast:
ausblenden 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
      // error handling
  finally
    MySnapshot.Free;
  end;
end;