Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi GDI-Handles Leck (https://www.delphipraxis.net/122082-gdi-handles-leck.html)

DevilsCamp 9. Okt 2008 08:17


GDI-Handles Leck
 
Ich habe in einer Progress-Bar-Komponente folgenden Code zum anzeigen des Fortschritts als Text innerhalb der Komponente:

Delphi-Quellcode:
procedure TIrgendEineKomponente.PaintText(PaintRect: TRect; Canv: TCanvas);
var
  Ima2                        : TBitmap;
  s                          : string;
  X                          : Integer;
  Y                          : Integer;
  diffx                      : Integer;
  t: string;
begin
  if fShowText then
  begin
    Ima2 := TBitmap.Create;
    Ima2.Width := Width;
    Ima2.Height := Height;
    diffx := 0;

    with Ima2.Canvas do
    begin
      CopyMode := cmBlackness;
      CopyRect(Rect(0, 0, Width, Height), Ima2.Canvas, Rect(0, 0, Width, Height));
      CopyMode := cmSrcCopy;
    end;

    with Ima2.Canvas do
    begin
      Font := Self.Font;
      Brush.Style := bsClear;
      Font.Color := clWhite;

      case fTextKind of
        mrgsPercent: s := Format('%0.*f%%', [FNachkommstellen, FPercentage]);
        mrgsXofY: s := Format('%0.0n / %0.0n', [1.0 * FPosition, 1.0 * FMaxWert]);
        mrgsValueOnly: s := Format('%0.0n', [1.0 * FPosition]);
        mrgsOwnText:
          begin
            if (not (csDesigning in ComponentState)) then
            begin
              if Assigned(FOnOwnText) then
                s := FOnOwnText(Self);
            end;
          end;
      end; // case

      if fTextKind <> mrgsXofY then
      begin
        with PaintRect do
        begin
          X := (Right - Left + 1) div 2 - TextWidth(S) div 2;
          Y := (Bottom - Top + 1 - TextHeight(S)) div 2;
        end; // with
      end
      else
      begin
        with PaintRect do
        begin
          X := (Right - Left + 1) div 2 - TextWidth(' / ') div 2;
          X := X - TextWidth(Format('%0.0n', [1.0 * FPosition]));
          Y := (Bottom - Top + 1 - TextHeight(S)) div 2;
        end;
      end;

      TextRect(PaintRect, X, Y, s);
    end; // with Ima2.Canvas

    Canv.CopyMode := cmSrcInvert;
    Canv.Draw(0, 0, Ima2);

    FreeAndNil(Ima2);
  end;
end;
Da ich mit Hilfe des Process Explorers festgestellt habe, dass die Anzahl der GDI-Handles während der Benutzung dieser Komponente steigt, sobald sich der Text ändert, habe ich folgende Theorie:
Im Code wird ja mit der Zeile
Delphi-Quellcode:
Ima2 := TBitmap.Create;
ein TBitmap erzeugt (steigt da die Anzahl der GDI-Handles?) und mit
Delphi-Quellcode:
FreeAndNil(Ima2);
wieder zerstört.
Was aber, wenn FreeAndNil nicht so funktioniert, wie es sollte, d.h. Ima2 NICHT zerstört wird? Dann würde ja das GDI-Handle nicht geschlossen werden, oder? Oder würde das automatisch mit dem beenden der Methode passieren?

Luckie 9. Okt 2008 08:21

Re: GDI-Handles Leck
 
Warum sollte es nicht funktionieren? Ich würde das für sehr unwahrscheinlich halten. Meiner Meinung nach ist der Fehler an einer anderen Stelle zu suchen.

turboPASCAL 9. Okt 2008 09:55

Re: GDI-Handles Leck
 
Ja, das liegt mer oder weniger an Windows.
Erstelle das Bitmap im Create deiner Komponente und gib sie im Destroy frei.

Dru wrist sehen dass das Problem eingrenzt.

DevilsCamp 10. Okt 2008 08:56

Re: GDI-Handles Leck
 
Jetzt bin ich noch verwirrter.

Auf meinem Entwicklungsrechner (Vista Ultimate, 32bit, 2GB RAM) ändert sich die Anzahl der GDI-Handles für den Prozess nicht. Auf 3 Windows XP-Professional Rechnern (2 haben 1GB, einer 3GB RAM) steigt die Anzahl unaufhaltsam (und ich habe die selbe EXE-Datei verwendet). :gruebel:

DevilsCamp 13. Jan 2009 14:32

Re: GDI-Handles Leck
 
:wall:

Ich habe den QuellCode meines Programmes nun komplett zerlegt und habe das Problem endlich aufdecken können.
Um prüfen zu können ob ein Text von der Breite her komplett in in ein TLabel passt, hole ich mir mit GetDC einen Handle auf das Label. Mit dem Handle kann ich nun ein TCanvas "misbrauchen" um die Breite mit Canvas.TextWidth zu bestimmen. Dummerweise habe vergessen, das Handle mit ReleaseDC wieder frei zu geben => irgendwann gehen die Resourcen zu ende.

Warum ich aber keine Probleme unter Windows Vista habe und unter XP schon: :gruebel:

himitsu 13. Jan 2009 14:54

Re: GDI-Handles Leck
 
Vista braucht von sich aus schon genug Resourcen ... vielleicht haben die ja einfach einige Grenzen entsprechend angehoben :roll:

Bei TLabel mit Autosize, könnte man notfalls auch nach dem Zuweisen einfach Width auslesen.
(kommt aber darauf an, was man erreichen will und wie "schön" es werden soll)

DevilsCamp 13. Jan 2009 22:50

Re: GDI-Handles Leck
 
Zitat:

Zitat von himitsu
Bei TLabel mit Autosize, könnte man notfalls auch nach dem Zuweisen einfach Width auslesen.
(kommt aber darauf an, was man erreichen will und wie "schön" es werden soll)

Das Label ist in einem GridPanel. Und sollte der Text (in dem Fall Dateiname inkl. Verzeichnis) zu lang sein, dann will ich den Pfad kürzen.

himitsu 14. Jan 2009 08:50

Re: GDI-Handles Leck
 
in D2009 kann man für Dateinamen follgende Einstellungen verwenden (kA. seit wann es das gibt)
.ShowAccelChar = False
.EllipsisPosition = epPathEllipsis

Ansonsten könnte man (glaub ich) auch TStaticText statt TLabel nutzen und das gleiche Verhalten über die WinAPI steuern (TStaticText nutzt doch das STATIC-Control von Windows :gruebel:) lassen (müßte dann aber mal schaun wie man das dem STATIC sagte, das es so kürzen soll)

DeddyH 14. Jan 2009 09:41

Re: GDI-Handles Leck
 
Evtl. bringt MinimizeName aus FileCtrl ja auch etwas.

DevilsCamp 14. Jan 2009 10:15

Re: GDI-Handles Leck
 
Zitat:

Zitat von DeddyH
Evtl. bringt MinimizeName aus FileCtrl ja auch etwas.

Leider nicht. Mit der selben Funktion sollen auch normale Texte werden können.

Und selbst, wenn ich nur Pfade kürzen lassen wollte wäre MinimizeName nichts für mich. MinimizeName macht ja folgendes:
Delphi-Quellcode:
const
 sPath = 'c:\Pfad\zur\meiner\Super-tollen\Applikation\VollKrass.exe';

ShowMessage(MinimizeName(sPath, Form1.Canvas, 200));

//results in a message: 'c:\...\VollKrass.exe'
Ich möchte den Text so kürzen:
Delphi-Quellcode:
const
 sPath = 'c:\Pfad\zur\meiner\Super-tollen\Applikation\VollKrass.exe';

ShowMessage(MeinEigenesKuerzen(sPath, Form1.Canvas, 200));

//results in a message: '...r-tollen\Applikation\VollKrass.exe'
Sollte es bereits so eine Funktion geben: Ich schau sie mir gerne an :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:31 Uhr.
Seite 1 von 2  1 2      

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