ListBox - ERangeError beim Scrollen bei zu vielen Items

Rund um die LCL und andere Komponenten
Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Hallo Leute,

folgendes Problem:

Ich habe einen Algorithmus geschrieben, der einen angegebenen Ordner und die Unterordner nach Dateien durchsucht. Als kleine Übung und weil mir die Funktion FindAllFiles() nicht ausreicht, weil sie nicht die Datei-Attribute berücksichtigt.
Jedenfalls habe ich dann die Ergebnisse in eine ListBox ausgegeben und wollte nach ganz unten scrollen und dann kamen folgende Fehlermeldungen:

1. Debuggerausnahmen-Nachricht

Projekt <beliebiger Projektname> hat Exception-Klasse >>RunError(201)<< ausgelöst.

In Datei 'win32\win32callback.inc' in Zeile 742:
ScrollCode := LOWROD(WParam);


2. Debuggerausnahmen-Nachricht

Projekt <beliebiger Projektname> hat Exception-Klasse >>ERangeError<< ausgelöst mit der Meldung:
Range check error.

In Datei 'win32\win32callback.inc' in Zeile 742:
ScrollCode := LOWROD(WParam);


Dann habe ich mir den Quellcode der Datei angesehen, in der die Exception auftritt und folgenden Kommentar gefunden:

MWE hat geschrieben:TLMScroll has not the same size as the VCL/Winapi counterpart.
IMO we don't have to force all widgetsets to be compatible in a shortcoming
in the win32 API.
So POS: SmallInt -> LongInt and a win32compatible smallpos is added
Due to this, the record is a LongInt to large.


Lässt sich mit folgendem Code reproduzieren:

Code: Alles auswählen

  ListBox1.Items.BeginUpdate;
  repeat
    ListBox1.Items.Add('TEST');
    ListBox1.Tag := ListBox1.Tag + 1;
  until ListBox1.Tag = 40000;     // mit 30.000 geht es noch aber mit High(SmallInt) + 20 schon nicht mehr
  ListBox1.Items.EndUpdate


Natürlich könnte man sich jetzt fragen, ob man unbedingt 30.000 Items in einer ListBox haben möchte, aber so viele sind es doch auch nicht. Wenn es etliche Milliarden wären, hätte ich ja noch Verständnis.

Gibt es eine Möglichkeit, diesen Fehler zu umgehen? Ich habe probiert, die Datentypen anzupassen, also aus SmallInt -> Integer, aber das klappt nicht. (Hätte ich mir auch denken können, denn, wenn es gehen würde, würde es dort auch stehen. Ich probiere eben gerne rum.)

-- Dee

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von fliegermichl »

Ich verwende so ziemlich für alles und jedes den VirtualStringTree. Ist rasend schnell, kann Millionen von Einträgen verwalten und in der Optik in extrem weitem Rahmen angepasst werden. Allerdings ist der Lernaufwand deutlich höher.

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Na das werde ich mir doch mal ansehen. Das Beispiel dafür ist auf jeden Fall sehr umfassend und erschlägt mich. :shock:
Aber da muss ich wohl durch.

Danke!

-- Dee

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von wp_xyz »

Kann ich nicht bestätigen. Wenn ich den Code-Schnippsel in ein Projekt mit Listbox und sonst nichts einbaue, kann ich auch bis zu 1 Million Items reinladen (mehr hab ich nicht versucht) und ans Ende scrollen (Laz trunk/32bit, fpc 3.0.4/32bit, Win 10/64 bit). Bitte nenne mehr über deine Randbedingungen (Laz version, OS), damit ich das besser nachstellen kann.

Ansonsten wäre eine ListView im virtuellen Modus auch eine Alternative zu VirtualTreeView. "Virtuell" heißt hier: die Daten sind nicht in der ListView gespeichert, sondern z.B. in einem Array. Einfach OwnerData auf true setzen und zum Beginn die Anzahl der Einträge mitteilen: ListView.Items.Count := <anzahl>. Dann einen Event-Handler für das Ereignis OnData schreiben, in dem man der ListView sagt, welcher Eintrag bei welchem Index stehen soll. Das beigefügte Demo zeigt das Vorgehen. Es lädt 10.000.000 Einträge schneller als ein Wimpernschlag.
Dateianhänge
listview_virtualMode.zip
(2.02 KiB) 109-mal heruntergeladen

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

wp_xyz hat geschrieben:Kann ich nicht bestätigen. Wenn ich den Code-Schnippsel in ein Projekt mit Listbox und sonst nichts einbaue, kann ich auch bis zu 1 Million Items reinladen (mehr hab ich nicht versucht) und ans Ende scrollen (Laz trunk/32bit, fpc 3.0.4/32bit, Win 10/64 bit). Bitte nenne mehr über deine Randbedingungen (Laz version, OS), damit ich das besser nachstellen kann.

Ansonsten wäre eine ListView im virtuellen Modus auch eine Alternative zu VirtualTreeView. "Virtuell" heißt hier: die Daten sind nicht in der ListView gespeichert, sondern z.B. in einem Array. Einfach OwnerData auf true setzen und zum Beginn die Anzahl der Einträge mitteilen: ListView.Items.Count := <anzahl>. Dann einen Event-Handler für das Ereignis OnData schreiben, in dem man der ListView sagt, welcher Eintrag bei welchem Index stehen soll. Das beigefügte Demo zeigt das Vorgehen. Es lädt 10.000.000 Einträge schneller als ein Wimpernschlag.

Wieder etwas gelernt. Danke, für deine Demo! Jedoch tritt der Fehler interessanterweise auch bei deiner Demo auf mit exakt den selben Meldungen. Ich habe Lazarus heute reinstalliert, weil, als ich mit dem Online Package Manager diese VirtualTreeView Komponente installieren wollte, gab es beim Kompilieren der IDE etliche Speicherlecks. Merkwürdigerweise waren nach der Neuinstallation beide Pakete (OPM & VirtualTreeView) bereits installiert, obwohl ich das Installationsverzeichnis und das Lazarus-Appdata-Verzeichnis entfernt habe.

Mein System:
OS = Windows 10 Pro 64-bit Build 17763
Lazarus-Version = 2.0.2 r60954
FPC = 3.0.4
CPU = AMD Ryzen 5 2600
Lazarus-Installations-Setup: lazarus-2.0.2-fpc-3.0.4-win64.exe

-- Dee

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von siro »

Hallo,

Ich habe es eben mit 1 Million Einträgen ausprobiert.
Das dauert zwar ewig (über 2 Minuten), aber es funktioniert einwandfrei...
Das Programm beenden (alles wieder freigeben) dauert dann bei mir 45 Sekunden

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
begin
       ListBox1.Items.BeginUpdate;
      repeat
        ListBox1.Items.Add('TEST'+IntToStr(ListBox1.Tag));
        ListBox1.Tag := ListBox1.Tag + 1;
      until ListBox1.Tag = 1000000;     // 1 Million Einträge
      ListBox1.Items.EndUpdate;
end;
 


Windows 64 Bit
Lazarus 2.0.0
FPC 3.0.4

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von wp_xyz »

Dee hat geschrieben:Jedoch tritt der Fehler interessanterweise auch bei deiner Demo auf mit exakt den selben Meldungen.

Du meinst exact das gepostete Programm? Ich habe es gerade mit genau derselben Konfiguration probiert (Laz 2.0.2/fpc3.0.4/64 bit auf Win 10/64 bit), nur Intel statt AMD: kein Problem

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Ich habe herausgefunden, was das Problem ist.

Unter "Werkzeuge -> >>Lazarus kompilieren<< einrichten ..." habe ich bei "Profil zum Kompilieren" IDE mit Debugger-Informationen ausgewählt, in der Hoffnung, dass mir beim Debuggen meiner Programme mehr Informationen zur Verfügung stehen. Mekrwürdigerweise führte aber eben genau diese Einstellung zum besagten Fehler.
Ich habe es auf mein Notebook mit Windows 7 64-bit und Intel-Prozessor probiert. Sowohl mit der 2.0.0 als auch der 2.0.2 Version gab es keine Probleme, bis ich die IDE mit Debugger-Informationen rekompiliert habe.

Wieder einmal ein Beispiel dafür, dass das Problem nicht im Rechner, sondern vor dem Rechner sitzt.

-- Dee

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von wp_xyz »

Weiß nicht... Auch die Debug-IDE-Einstellung macht bei mir keinen Fehler.

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Ich habe es noch mal getestet. Es muss an dieser Einstellung liegen. Außerdem habe ich herausgefunden, dass der Fehler nur ausgelöst wird, wenn ich das Mausrad zum Scrollen verwende, nicht aber den Scrollbalken. Es hängt also eventuell mit WindowsMessages, die vom Scrollen mit dem Mausrad gesendet werden, zusammen.

-- Dee

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von wp_xyz »

Dee hat geschrieben:Ich habe es noch mal getestet. Es muss an dieser Einstellung liegen. Außerdem habe ich herausgefunden, dass der Fehler nur ausgelöst wird, wenn ich das Mausrad zum Scrollen verwende, nicht aber den Scrollbalken.

Da kriege ich ja einen wunden Finger, wenn ich bei 1.000.000 Einträgen mit dem Mausrad scrollen muss. Bitte genaue Angaben: Verwendest du das von mir oben gepostete Demoprogramm? Wenn nicht, poste deins (bitte keine Code-Schnipsel, sondern Dateien im Anhang, sonst gibt es wieder zig Unwägbarkeiten, etwas anders aufzusetzen). Auflistung der Schritte, die man machen muss, um den Fehler zu produzieren.

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

@wp_xyz:

Bitte entschuldige. Ich wollte dir keine zu großen Umstände bereiten. :oops:
Aber schön, dass du so engagiert bist und Geduld übst. Props an dich!

So, weiter im Text. Ja, der Fehler tritt auch bei deinem Demo-Programm auf. Und es müssen keine 1 Mio Items sein. 100.000 reichen auch. 8) Ich werde noch die genaue Anzahl ermitteln, ab wann der Fehler auftritt. Und von oben bis unten mit dem Mausrad zu scrollen, ist auch nicht nötig. Du kannst den Scrollbalken nehmen und ganz nach unten ziehen und dann versuchen, mit dem Mausrad nach oben/unten zu scrollen. Da tritt dann bei mir der Fehler auf. Da habe ich mich wohl etwas ungenau ausgedrückt.

Ich werde mich jetzt darum kümmern, eine genaue Beschreibung für den Fehler zu erstellen und poste ihn dann später. Ich bitte also um Geduld. :wink:

-- Dee

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Betriebssystem: Windows 7 Home Premium SP1 64-bit
CPU: Intel Core i5-4210M
RAM: 8 GB

Verwendung folgender Lazarus-Setup-Datei: lazarus-2.0.0-fpc-3.0.4-win64.exe

Lazarus-Version: 2.0.0
FPC-Version: 3.0.4
Installationsverzeichnis: “C:\lazarus”

Crosscompiling-Addon/-Plugin vorhanden: Nein
Zusätzliche Pakete installiert: Nein
Compiler-Einstellungen: Default (keine sonstigen manuellen Änderungen)
Änderungen an der IDE: Ja
Anzahl der Änderungen: 1
Art der Änderung: Kompilierung der Lazarus-IDE mit Debugger-Informationen

Anleitung für Änderung:
1. Linksklick auf “Werkzeuge” in der Menüleiste der Lazarus-IDE
2. Linksklick auf Menüpunkt “>>Lazarus kompilieren<< einrichten ...”
3. im sich öffnenden Fenster mit dem Titel “Lazarus kompilieren einstellen” im Reiter “Neu kompilieren” neben “Profil zum Kompileren” den Eintrag “IDE mit Debugger-Informationen” auswählen
4. unten im Fenster auf “neu kompileren” klicken
5. Kompilerung und Neustart der IDE abwarten

Sonstige Änderungen: Keine

Art der Fehler: ERangeError, RunError 201
Tritt in folgender Datei auf: win32callback.inc, Zeile 738

Beschreibung zur Reproduktion:
1. Lazarus-IDE mit Debugger-Informationen rekompilieren (siehe oben)
2. eine beliebige ListBox mit mindestens 32779 Items füllen
3. nachdem die ListBox gefüllt ist, ganz nach unten Scrollen (Art & Weise ist egal)
4. nach oben scrollen, bis das letzte Item der ListBox nicht mehr zu sehen ist (Art & Weise ist egal)
5. mit dem Mausrad in der ListBox nach unten scrollen
6. Fehler wird ausgelöst, beim Versuch, das 32779-ste Item anzuzeigen (wenn mit Mausrad gescrollt)


Ich hoffe, dass das an Informationen reicht. Der Fehler wird auch auf meinem Windows 10 Desktop-Rechner ausgelöst. Demo-Programm im Anhang.

-- Dee
Dateianhänge
ListBox_ERangeError.zip
SHA1-Prüfsumme: 095056e3ef393f356a0ad8f20196c5c9409e6312
(2.01 KiB) 99-mal heruntergeladen

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von wp_xyz »

ok, ich seh's jetzt auch: in meiner Demo bis ganz ans Ende scrollen mit dem Rollbalken, dann eine Raste am Mausrad nach oben -> crash. Das passiert mit Laz 2.0.2/fpc 3.0.4 /64 bit genauso wie mit Laz trunk /fpc 3.0.4 / 64 bit, aber nicht mit Laz / fpc 3.0.4 / 32 bit. Ein 64-Bit Problem also...

Der Code an der Absturzstelle ist (aus win32callback.inc):

Code: Alles auswählen

procedure TWindowProcHelper.HandleScrollMessage(LMsg: integer);
var
  ScrollInfo: TScrollInfo;
begin
  with LMScroll do
  begin
    Msg := LMsg;
    ScrollCode := LOWORD(WParam);   // <--- Crash
    SmallPos := 0;
    ScrollBar := HWND(LParam);
    Pos := 0;
  end;
...

WParam ist deklariert als PtrInt, das ist ein Int64 bei 64-Bit und Integer/LongInt bei 32 Bit. Die Funktion LoWord(), die in Unit LCLType implementiert ist, hat als Parameter einen Integer. Bei 64-Bit wird ihr aber ein Int64-Parameter übergeben, und das macht dann halt den Überlauf.

Mit der überladenen Funktion

Code: Alles auswählen

function LoWord(i: int64): Word;
begin
  Result := Lo(Lo(i));
end;

kommt man ein paar Zeilen weiter. Nun hat man dasselbe Problem mit der Funktion HiWord. Leider kenne ich mich mit dem Windows-API zu wenig aus, um sagen zu können, welches der vier Words hier zu nehmen ist, wahrscheinlich

Code: Alles auswählen

function HiWord(i:in64): word;
begin
  Result := Hi(Lo(i));
end;

denn das entspricht der Situation bei dem Überlauf. Das Programm funktioniert nun, aber eine HiWord-Funktion mit "Result := Hi(Hi(i))" funktioniert auch... Da bin ich mit meinem Latein am Ende.

Am besten wäre, du meldest dies als Fehler im BugTracker, so dass sich jemand darum kümmert, der weiß, was er tut. Du kannst ja auf diesen Post verweisen.

P.S.
Klingt ein bisschen wie Sam Hawkens: "Hi Hi Hi, wenn ich mich nicht irre..."

Dee
Beiträge: 54
Registriert: Do 10. Jul 2014, 20:56
OS, Lazarus, FPC: Windows 10 Pro 64-bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: Ryzen 5 2600

Re: ListBox - ERangeError beim Scrollen bei zu vielen Items

Beitrag von Dee »

Alles klar. Vielen Dank für deine Mühe! Dann werde ich mal den Bug reporten.

-- Dee

Antworten