Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   GDIPlus (Erik van Bilsen) mit ‘(GDI+Error) Generic Error’ nach Zugriff auf WinControl (https://www.delphipraxis.net/199082-gdiplus-erik-van-bilsen-mit-%91-gdi-error-generic-error%92-nach-zugriff-auf-wincontrol.html)

HintByError 22. Dez 2018 10:49

GDIPlus (Erik van Bilsen) mit ‘(GDI+Error) Generic Error’ nach Zugriff auf WinControl
 
Liste der Anhänge anzeigen (Anzahl: 2)
Beschreibung des Symptoms

Es liegt eine initialisierte lokale Variable g des Typs IGPGraphics vor, die bereit ist, in eine Steuerelement der Klasse TPaintBox Bildschirmausgaben zu tätigen. Wenn nach der Initialisierung von g ein Zugriff auf die Felder von Instanzen der Klassen TComboBox, TListBox oder TMemo erfolgt, wird die nachfolgende Zeichenoperation mittels g mit der Fehlermeldung „(GDI+Error) Generic Error“ abgebrochen. Wird nach dem Zugriff g neu initialisiert, dann tritt der Fehler nicht mehr auf.

Interpretation

Offensichtlich hat der lesende Zugriff auf die Klassen TComboBox, TListBox und TMemo einen schreibenden Seiteneffekt auf die lokale Variable g zur Folge. Aufgrund der Kapselung dürfte ein solcher Effekt nicht eintreten. Die Klassen TComboBox, TListBox und TMemo enthalten alle eine Klasse vom Typ TStringlist. Wenn man auf eine separate Instanz des Typs TStringList vor der GDI-Operation einen Zugriff ausführt, dann tritt kein Fehler auf. Der Code von Erik van Bilsen ist minimalistisch und offensichtlich fehlerfrei. Kommt der Seiteneffekt aus dem Betriebssystem oder aus der VCL?

Demonstrationsprogramm

Rechts auf dem Formular befindet sich ein Optionsfeld, in dem der Fall ausgewählt werden kann. Die Schaltfläche „GDI Test“ bringt dann die Zeichenoperationen zur Ausführung. Es wird ein Kreuz in der Zeichenfläche im Formular unten ausgeführt. Bei den Optionen „Kein Zugriff“ und „Zugriff mit Neuinitialisierung“ wird, ohne eine Fehlermeldung hervorzurufen, gezeichnet. Quellcode befindet sich in der angehängten .zip-Datei.

Uwe Raabe 22. Dez 2018 12:46

AW: GDIPlus (Erik van Bilsen) mit ‘(GDI+Error) Generic Error’ nach Zugriff auf WinCon
 
Die VCL erlaubt nur eine begrenzte Zahl (4) gleichzeitig von TControlCanvas geöffneter Device Contexts zu einer bestimmten Zeit. Deswegen wird der Device Context eines TControlCanvas (das Handle) intern freigegeben, wenn eine andere TControlCanvas-Instanz eines benötigt. Ich vermute mal, daß nach dem Zugriff auf das jeweils andere Control das PaintBox1.Canvas.Handle auf 0 steht (kannst du ja mal prüfen).

HintByError 22. Dez 2018 15:05

Der Hinweis ist nicht zutreffend.
 
Liste der Anhänge anzeigen (Anzahl: 1)
Im Demoprogramm zeigt sich im Debugger, dass die Handle PaintBox1.Canvas.Handle gültig bleibt, d. h., nicht den Wert 0 annimmt.

Es wundert mich warum die VCL die Zahl der offene Canvas-Handle-Nummern limitieren sollte. Die verfügbaren Handle-Nummern werden vom Betriebssystem verwaltet und sind von dessen Seite „limitiert“. Prinzipiell können bei 32-Bit-Betrieb in dem Pool der Canvas-Handle-Nummern 4 Milliarden Nummern angelegt werden, was dann einem Speichervolumen von 16 Gigabyte bei einem Adressraum vom maximal 4 Gigabyte entspricht.

Wenn ich ein Formular mit 5 TPaintBox-Instanzen anlege und die gleichzeitig offenen Handle-Nummern mittels der Anweisung
Code:
  ShowMessage(IntToStr(PaintBox1.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox2.Canvas.Handle) + #13#10 + IntToStr(PaintBox3.Canvas.Handle)
    + #13#10 + IntToStr(PaintBox4.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox5.Canvas.Handle));
ausgeben lasse, dann erhalte ich keinen Nullwert bei den Handlenummern. Siehe angehängtes Bild.

Fritzew 22. Dez 2018 15:37

AW: GDIPlus (Erik van Bilsen) mit ‘(GDI+Error) Generic Error’ nach Zugriff auf WinCon
 
Liste der Anhänge anzeigen (Anzahl: 1)
Gewöhne Dir an nur im WM_Paint zu zeichnen.
Das ist in meinen Augen einer der grössten DesignFehler von Windows das außerhalb des PaintEvents gezeichnet werden kann.

Ich habe das Projekt mal angepasst:
Es wird nur im onPaint der Paintbox gezeichnet.

Uwe Raabe 22. Dez 2018 16:16

AW: Der Hinweis ist nicht zutreffend.
 
Zitat:

Zitat von HintByError (Beitrag 1421757)
Wenn ich ein Formular mit 5 TPaintBox-Instanzen anlege und die gleichzeitig offenen Handle-Nummern mittels der Anweisung
Code:
  ShowMessage(IntToStr(PaintBox1.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox2.Canvas.Handle) + #13#10 + IntToStr(PaintBox3.Canvas.Handle)
    + #13#10 + IntToStr(PaintBox4.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox5.Canvas.Handle));
ausgeben lasse, dann erhalte ich keinen Nullwert bei den Handlenummern. Siehe angehängtes Bild.

Das liegt daran, daß der Getter von Handle bei Bedarf ein neues Handle erzeugt. Sind bei dir nicht die Handle-Werte von PaintBox1 und PaintBox5 gleich? Du kannst das auch auf 6 und mehr Paintboxen ausdehnen, wirst aber vermutlich immer nur vier verschiedene Werte angezeigt bekommen.

Ändere mal den Aufruf so und vergleiche den ersten und letzten Wert:

Delphi-Quellcode:
  ShowMessage(
    IntToStr(PaintBox1.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox2.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox3.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox4.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox5.Canvas.Handle) + #13#10 +
    IntToStr(PaintBox1.Canvas.Handle)
    );
Lass die PaintBox5 weg und die Werte sind gleich.

HintByError 23. Dez 2018 18:00

AW2: Der Hinweis ist nicht zutreffend.
 
[QUOTE=Uwe Raabe;1421765]
Zitat:

Zitat von HintByError (Beitrag 1421757)
Das liegt daran, daß der Getter von Handle bei Bedarf ein neues Handle erzeugt. Sind bei dir nicht die Handle-Werte von PaintBox1 und PaintBox5 gleich? Du kannst das auch auf 6 und mehr Paintboxen ausdehnen, wirst aber vermutlich immer nur vier verschiedene Werte angezeigt bekommen.

Tatsächlich. In der Erwartung einer Null hatte ich nicht richtig beobachtet. Ein interessantes Detail, dass die Frage aufwirft, weshalb die VCL so sparsam mit Handlenummern umgeht. Vielleicht ist der Grund ein historisches Relikt. Ich halte es nicht für nötig. Die richtige Antwort auf den Ausgangsbeitrag findet sich in dem Beitrag von Fritzew.

HintByError 23. Dez 2018 18:07

AW: GDIPlus (Erik van Bilsen) mit ‘(GDI+Error) Generic Error’ nach Zugriff auf WinCon
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Fritzew (Beitrag 1421762)
Gewöhne Dir an nur im WM_Paint zu zeichnen.
Das ist in meinen Augen einer der grössten DesignFehler von Windows das außerhalb des PaintEvents gezeichnet werden kann.

So ähnlich hatte ich es auch im ersten Ansatz programmiert. Über den Methodenzeiger TPaintBox.OnPaint wird gezeichnet und mit einem Aufruf von TPaintBox.Repaint wird der Inhalt aktualisiert. Wenn nur eine Darstellung benötigt wird, dann genügt dies. Es handelt sich bei dem richtigen Programm um eine Lady mittlerer Komplexität (ein Charting-Tool), siehe beigefügte Abbildung. In der oberen Leiste befinden sich 3 Auswahllisten für Finanztitel, Darstellungsbreite eines Intervalls und Variante der Darstellung. Mit den Ankreuzkästchen des offenen Menüs „Darstellungsoptionen“ lassen sich Linien in dem Diagramm ein- und ausblenden, wobei bei der Aktualisierung das Menü geöffnet bleibt. Es gibt 3 Methoden, die eine Ausgabe produzieren, und 2 davon wurden nicht über TPaintBox.OnPaint aufgerufen. Die 3. war die PaintBox.OnPaint selbst. Damit die beiden anderen auch von TPaintBox.OnPaint aufgerufen werden, ist der Code dahin gehend angepasst worden, dass über das Feld TPaintBox.Tag festgelegt wird, welche Methode innerhalb von PaintBox.OnPaint aufgerufen werden soll. Um die Sache zum Laufen zubringen, muss dann statt TPaintBox.Repaint tatsächlich TPaintBox.Invalidate verwendet werden. Wenn es nur um Teilbereiche geht, dann sollte man InvalidateRect verwenden. Eine der Routine zeichnet eine vertikale Positionsmarke in Form eines schmalen Rechteckes, die von der Mausposition abhängig ist. Diese Positionsmarke ist in der Abbildung nicht zu sehen. Für das Zeichnen einer solchen Positionsmarke hat sich gezeigt, dass die Blitting-Methode (BitBlT-Routine) mit dem direkten Speicherzugriff und das Zeichnen außerhalb von TPaintBox.OnPaint besser ist. Die Darstellung über TPaintBox.OnPaint reagiert hier zu träge, sodass man hier besser die Programmiertechnik der alten Dinosaurier verwendet. Man muss dabei dafür sorgen, dass vor der Initialisierung von IGPGraphics die benötigten Inhalte aus den Steuerelementen ausgewertet sind.

Vielen Dank für Deinen Beitrag, der mich effektiv weiter gebracht hat.

Uwe Raabe 23. Dez 2018 22:11

AW: AW2: Der Hinweis ist nicht zutreffend.
 
Zitat:

Zitat von HintByError (Beitrag 1421829)
Ein interessantes Detail, dass die Frage aufwirft, weshalb die VCL so sparsam mit Handlenummern umgeht. Vielleicht ist der Grund ein historisches Relikt.

Delphi 1 lief damals noch auf Windows 3.x :)

HintByError 24. Dez 2018 00:17

AW: Der Hinweis ist nicht zutreffend
 
Zitat:

Delphi 1 lief damals noch auf Windows 3.x :)
Dazu muss ich aber einwenden, dass zu diesen Zeiten jede Menge Neues emuliert wurde. Windows 4.0 (sic!) erschien im August 1994 überraschenderweise oder unüberraschenderweise nicht. Je nach Hintergrundwissen. Das danach erscheinende Windows 95 hat mit einem Jahr zusätzlicher Entwicklungsarbeit richtig Hauruck gehabt. Die OWL (Object Windows Library) von TPW (Turbo Pascal for Windows) ist verschwunden und durch die VCL ersetzt worden. Windows 95 und Windows 98 konnten mit 8192 Selectoren mal 64 kByte 512 MByte adressieren. Das sind zwar nicht 4Gbyte, aber es liegt kein Anlass vor, noch so sparsam zu sein.

Uwe Raabe 24. Dez 2018 08:59

AW: Der Hinweis ist nicht zutreffend
 
Zitat:

Zitat von HintByError (Beitrag 1421955)
aber es liegt kein Anlass vor, noch so sparsam zu sein.

Nein, natürlich nicht! Windows 3.11 wird ja von aktuellen Delphi-Versionen auch nicht mehr unterstützt. Es bedarf auch nur der Anpassung einer einzigen Konstante (CanvasListCacheSize) in Vcl.Controls um das zu ändern.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:09 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