Delphi-PRAXiS

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 :)

DeddyH 14. Jan 2009 10:28

Re: GDI-Handles Leck
 
Achso, dann hatte ich das falsch verstanden, sry.

himitsu 14. Jan 2009 10:42

Re: GDI-Handles Leck
 
Liste der Anhänge anzeigen (Anzahl: 2)
.EllipsisPosition = True war völliger Schwachsinn ... muß natürlich epPathEllipsis heißen

PS: epWordEllipsis scheint wohl nicht so rEcht zu funktionieren ... das Ganze soll doch bestimmt das Selbe Verhalten nachahmen, wie es vom STATIC bekannt ist und dort wird dann das ganze letze Wort weggelassen (es gibt also keine unvollständigen Wörter) ... glaub ich zumindestens (falls ich mich richtig erinner)

Wegen dem TStaticText schau ich grad mal, ob ich das jetzt noch schnell find.

[add]
man könnte sich bezüglich TStaticText eine neue Klasse/Komponente definieren, oder (ach, ich liebe es Delphi was unterzuschmuggln :angel2: ) ... siehe Anhang
Delphi-Quellcode:
type TEllipsisStaticText = class(TStaticText)
  public
    procedure CreateParams(var Params: TCreateParams); override;
  end;

procedure TEllipsisStaticText.CreateParams(var Params: TCreateParams);
begin
  inherited;
  // SS_ENDELLIPSIS
  // SS_PATHELLIPSIS
  // SS_WORDELLIPSIS
  Params.Style := Params.Style or SS_PATHELLIPSIS;
end;

DevilsCamp 14. Jan 2009 10:50

Re: GDI-Handles Leck
 
Zitat:

Zitat von DeddyH
Achso, dann hatte ich das falsch verstanden, sry.

Kein Problem. Habe ja auch nicht klar genug geschrieben, wie ich es haben möchte :)


Zitat:

Zitat von himitsu
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)

hmm. Sieht interessant aus. Mal schauen, ob diese Eigenschaften auch im BDS2006 vorhanden sind.

himitsu 14. Jan 2009 10:58

Re: GDI-Handles Leck
 
ich hatte grade das Bild um TStaicText erweitert
und noch Weiteres dazu nacheditiert > siehe vorheriger Beitrag

SirThornberry 14. Jan 2009 11:00

Re: GDI-Handles Leck
 
Zitat:

Zitat von DevilsCamp
...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:

Ich denke es wird einfach nur anders implementiert sein. Beispielsweise mit einem ReferenzCounter der einfach hochgezählt wird immer wenn GetDC aufgerufen wird und erst wenn der Counter wieder auf 0 gesetzt wird kommt die Freigabe. Bei Funktionen rund um die Desktops schien das bei XP schon so zu sein (da gab jeder Aufruf das gleiche Handle zurück)


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:30 Uhr.

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