Einzelnen Beitrag anzeigen

Rolf Frei

Registriert seit: 19. Jun 2006
646 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: EOutOfResources - Wie viele Handles sind noch verfügbar?

  Alt 19. Dez 2019, 15:10
Du solltest da unbedingt mit try/finally arbeiten. Wenn du da irgendwo ausserhalb deiner unnötigen Exceptions eine Exception bekommst, hast du danach zumindest für das Bitmap ein Memoryleak. Dass du da so viele try/excepts drin hast macht keinen Sinn. So wie du das da machst reicht einer um den ganze Code. Oder willst du wirklich, dass Teile deines Codes noch ausgeführt werden, wenn davor eine Exception aufgetreten ist?

Bitte schütze deine erstellten Resourcen mit einem try/finally und alles ist bestens. Sobald du ein Objekt erstellst, kommt immer ein try und am Ende ein finally in dem du das Objket wieder frei gibst. Wenn du dich daran hälst wirst du nie mehr Probleme dieser Art haben.

Für ein Tool, das dir die allozierten Handels und noch viel mehr zeigt, emfehle ich dir den Prozess Explorer von SysInternals (Microsoft).

https://docs.microsoft.com/en-us/sys...ocess-explorer

Delphi-Quellcode:
// Prüft, ob der Inhalt von _Parent komplett Schwarz ist
// Die Prozedur zeichnet, FALLS übergeben, auf _TargetBitmap, was sie "gesehen" hat
// Zum Vermeidung div. Probleme wird der untersuchte Bereich auf 640x480 px skaliert,
// das ist für diese Zwecke mehr als ausreichend genau
function EndOfPresentation_Neu(_Parent: TWinControl; _TargetBitmap: Graphics.TBitmap): Boolean;
var
  myBitmap: graphics.TBitmap;
  DetectHeight, DetectWidth: Integer;
  SourceDC: HDC;
  State: String;
  hwParentHandle: HWND;
const
  CAPTUREBLT = $40000000;
  SCAN_WIDTH = 640;
  SCAN_HEIGHT = 480;
begin
  Result := False;

  // Variablen auf gültige Werte initialisieren, damit sie
  // auf jeden Fall korrekt freigegeben werden können
  hwParentHandle := 0;
  myBitmap := NIL;

  try
    // Kein Parent, keine Analyse
    if not assigned(_Parent) then Exit;
    if not _Parent.InheritsFrom(TWinControl) then Exit;

    DetectWidth := _Parent.Width;
    DetectHeight := _Parent.Height;

    if (DetectHeight < 1) or (DetectWidth < 1) then Exit;

    // TBitmap initialisieren, und auf die erwartete Größe bringen
    State := 'EndOfPresentationDetector.EndOfPresentation_Neu.InitializeValues.Exception: ';
    hwParentHandle := _Parent.Handle;

    myBitmap := Graphics.TBitmap.Create;
    try
      myBitmap.PixelFormat := pf32bit;

      // Zu analysierender Bereich ist lediglich 640 x 480 px
      myBitmap.Width := SCAN_WIDTH;
      myBitmap.Height := SCAN_HEIGHT;

      // Screenshot vom betroffenen Bereich erstellen
      State := 'EndOfPresentationDetector.EndOfPresentation_Neu.DoBitBlt.Exception: ';
      SourceDC := GetDC(hwParentHandle);
      if SourceDC <> 0 then begin
        try // Dieses try/finally ist eigentlch überflüssig, da es hier keine Exception geben sollte
          // das "_Parent"-Objekt abfotografieren. Wir skalieren gleichzeitig auf 640 x 480. Hinreichend genau für unseren Zweck.
          StretchBlt(myBitmap.Canvas.Handle, 0, 0, SCAN_WIDTH, SCAN_HEIGHT, SourceDC, 0, 0, DetectWidth, DetectHeight, SRCCOPY or CAPTUREBLT);
        finally
          ReleaseDC(hwParentHandle, SourceDC);
        end;
      end;

      State := 'EndOfPresentationDetector.EndOfPresentation_Neu.ObereKanteNurSchwarzInProzent.Exception: ';
      // Prozedur, die nur auf die Scanlines von myBitmap zugreift, und zurückgibt, Keine Leak/Handle Bedenken!
      // Gibt an wie viele Prozent des Bildes explizit schwarz sind,
      // bzw. bei wieviel Prozent der Höhes des Bildes (von Oben gesehen)
      // die letzte Zeile mit mind. einem nicht-schwarzen Pixel ist
      Result := (ObereKanteNurSchwarzInProzent(myBitmap) < 25);

      // Falls der Parameter übergeben wurde, wird auf _TargetBitmap das erfasste, nun skalierte und mit
      // Hilfslininen versehene Bild ausgegeben, so dass es dem Benutzer angezeigt werden könnte
      if assigned(_TargetBitmap) then begin
        _TargetBitmap.Assign(myBitmap);
      end;

    finally
      FreeAndNil(myBitmap); // wird so immer freigeben, auch im Fall einer Exception
    end;

  except
    on E: Exception do begin
      log(State + E.Message);
    end;
  end;
end;

Geändert von Rolf Frei (19. Dez 2019 um 15:26 Uhr)
  Mit Zitat antworten Zitat