Autor |
Beitrag |
teamrocket0
Beiträge: 175
Erhaltene Danke: 1
Win ME, Win XP, Win 7, Win 10
Delphi 7, 10.2 Tokyo
|
Verfasst: Mo 16.09.24 14:29
Hallo Delphi Community, teamrocket hier.
Ich bastle gerade ein Programm das eine Remote Desktop Manager werden soll, da ich mit dem auf dem Markt vorhanden Zeug irgendwie nicht zufrieden bin.
Als Übersicht versuche ich ein "VirtualStringTree" zu verwenden.
Das füttern mit Informationen der jeweiligen "Parent-Node" bzw. "Child-Node" funktioniert glaube ich schon ganz gut.
Auch das verwenden der "Meta-Daten" des jweiligen Node funktioniert erstmal. Glaube ich...
Das was ich derzeit nicht auf die Reihe bekomme ist, den gesamten "VirtualStringTree" samt "Meta-Daten" in einem "Stream" zu sichern.
Also, das speichern scheint zwar zu erfolgen und das Laden des Stream auch, jedoch erhalte ich nach dem Laden der "Stream-Datei" eine Fehlermeldung.
Zugrifsverletzung bei Adresse "Blakeks" in Modul "Project1.exe"...
In der officellen Dokumentation finde ich folgende Zeile, mit der ich nichts anfangen kann.
Delphi-Quelltext 1: 2: 3:
| begin Stream.Write(Art, SizeOf(Art)); |
Ich habe mich an folgenden Beitrag aus dem "Stackoverflow" Forum gehalten
HTML-Dokument 1:
| https://stackoverflow.com/questions/45606992/how-to-save-load-to-from-file-in-virtualtree-component-using-delphi |
Kennt sich jemand von euch mit dem speichern des "VirtualStringTree" aus?
Mein bisheriger Quellcode:
VirtualStringView Typ-Deklaration
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| type PMyRec = ^TMyRec; TMyRec = record Caption: WideString; ServerAdress: String; Username: String; Domain: String; ClearPW: WideString; wallpaper: Integer; reconnection: Integer; clipboard: Integer; printers: Integer; PointerNodeData:Pointer; end; |
im FreeNode-Ereigniss
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Data: PMyRec; begin Data := Sender.GetNodeData(Node); Finalize(Data^); end; |
im GetNodeDatraSize-Ereigniss
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TForm1.VirtualStringTree1GetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); begin NodeDataSize := SizeOf(TMyRec);end; |
Das OnGetText-Ereigniss
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); var Data: PMyRec; begin Data := Sender.GetNodeData(Node); if Assigned(Data) then CellText := Data.Caption; end; |
Das OnInitNode-Ereigniss
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure TForm1.VirtualStringTree1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); var Data: PMyRec; begin with Sender do begin Data := GetNodeData(Node); Data.Caption := Format(DisplayName, [GetNodeLevel(Node), Node.Index]); end; end; |
Für das OnLoadNode-Ereigniss
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| procedure TForm1.VirtualStringTree1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream); var Data: PMyRec; Len: Integer; begin Data := Form1.VirtualStringTree1.GetNodeData(Node);
Stream.read(Len, SizeOf(Len)); SetLength(Data^.Caption, Len); Stream.read(PChar(Data^.Caption)^, Len*SizeOf(Char));
Stream.read(Len, SizeOf(Len)); SetLength(Data^.ServerAdress, Len); Stream.read(PChar(Data^.ServerAdress)^, Len*SizeOf(Char));
Stream.read(Len, SizeOf(Len)); Stream.read(Data.wallpaper, SizeOf(Data.wallpaper));
Stream.read(Len, SizeOf(Len)); Stream.read(Data.reconnection, SizeOf(Data.reconnection));
Stream.read(Len, SizeOf(Len)); Stream.read(Data.clipboard, SizeOf(Data.clipboard));
Stream.read(Len, SizeOf(Len)); Stream.read(Data.printers, SizeOf(Data.printers));
Stream.read(Len, SizeOf(Len)); Stream.Read(Data.PointerNodeData, SizeOf(Data.PointerNodeData)); end; |
Und zu guter Letzt das OnSaveNode-Ereigniss
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38:
| procedure TForm1.VirtualStringTree1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream); var Data: PMyRec; Len: Integer; begin Data := Form1.VirtualStringTree1.GetNodeData(Node);
Len := Length(Data^.Caption); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data^.Caption)^, Len*SizeOf(Char));
Len := Length(Data^.ServerAdress); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data^.ServerAdress)^, Len*SizeOf(Char));
Len := Length(Data^.Username); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data^.Username)^, Len*SizeOf(Char));
Len := Length(Data^.Domain); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data^.Domain)^, Len*SizeOf(Char));
Len := Length(Data.ClearPW); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data^.ClearPW)^, Len*SizeOf(Char));
Stream.write(Data^.wallpaper, SizeOf(Data^.wallpaper));
Stream.write(Data^.reconnection, SizeOf(Data^.reconnection));
Stream.write(Data^.clipboard, SizeOf(Data^.clipboard));
Stream.write(Data^.printers, SizeOf(Data^.printers));
Stream.Write(Data^.PointerNodeData, SizeOf(Data^.PointerNodeData)) end; |
Speicher-Button
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.Button4Click(Sender: TObject); var NodeSafe: TFileStream; begin Form1.VirtualStringTree1.SaveToFile(ExtractFilePath(ParamStr(0))+ 'Connections.at1'); end; |
Laden Knopf
Delphi-Quelltext 1: 2: 3: 4:
| procedure TForm1.Button5Click(Sender: TObject); begin Form1.VirtualStringTree1.LoadFromFile(ExtractFilePath(ParamStr(0))+ 'Connections.at1'); end; |
Ich habe sicherlich nur eine Kleinigkeit übersehen oder alles komplett falsch gemacht.
Bitte schaut euch das einmal an. Vielleicht kann mir jemand sagen wo der Fehler liegt.
Ich danke für eure Zeit,
teamrocket0
_________________ To be forgotten is worse than death!
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Di 17.09.24 18:26
Was genau heißt
Zitat: | jedoch erhalte ich nach dem Laden der "Stream-Datei" eine Fehlermeldung. |
?
Benutzt du den Debugger? Was zeigt der Callstack an?
Und stehen in der Nodes nach dem Laden die korrekten Werte?
Auf Anhieb fällt mir nur PointerNodeData auf. Was wird da zugewiesen und wie wird es benutzt? Wenn dies dynamisch allozierter Speicher ist, so ist diese Adresse nach dem Laden (bes. nach Neustart des Programms) natürlich nicht mehr nutzbar.
|
|
teamrocket0
Beiträge: 175
Erhaltene Danke: 1
Win ME, Win XP, Win 7, Win 10
Delphi 7, 10.2 Tokyo
|
Verfasst: Mi 18.09.24 23:14
Hallo Th69,
ehm...mit dem Debugger und dem Callstack habe ich bisher noch nicht gearbeitet.
die Fehlermeldung erhalte ich nachdem ich die Stream-Datei geladen habe und irgendwo auf den "VirtualStringTree1" drauf klicke. Egal ob eine leere Stelle, oder dort wo die Nodes angezeigt werden.
Die Nodes werden zumindest namentlich korrekt dargestellt. Meta-Daten kann ich nix zu sagen. Die Fehlermeldung lässt mich nicht mehr mit dem "VirtualStringTree1" interagieren.
Die angezeigte Fehlermeldung hat mich vermuten lassen, das nicht alle Informationen im Stream gespeichert würden. Somit habe ich die "PointerNodeData" hinzugefügt. Damit konnte ich die Fehlfunktion jedoch nicht beheben.
Dieses "PointerNodeData" benutze ich nur an einer Stelle. Bei der Typ-Deklaration für den Record. In der Anleitung "Virtual Treeview step by step" ist auch so ein Pointer eingebaut.
Ich gehe mal davon aus, das die Stream-Datei nicht ordnungsgemäß gespeichert wird.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| type PMyRec = ^TMyRec; TMyRec = record Caption: WideString; ServerAdress: String; Username: String; Domain: String; ClearPW: WideString; wallpaper: Integer; reconnection: Integer; clipboard: Integer; printers: Integer; PointerNodeData:Pointer;
end; |
_________________ To be forgotten is worse than death!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 19.09.24 08:12
teamrocket0 hat folgendes geschrieben : | ehm...mit dem Debugger und dem Callstack habe ich bisher noch nicht gearbeitet. |
Das solltest du ändern, denn das ist sehr wichtig, um Fehler zu finden.
teamrocket0 hat folgendes geschrieben : | die Fehlermeldung erhalte ich nachdem ich die Stream-Datei geladen habe und irgendwo auf den "VirtualStringTree1" drauf klicke. Egal ob eine leere Stelle, oder dort wo die Nodes angezeigt werden. |
Delphi zeigt diese Fehlermeldung dann ja an. Dann kannst du einfach auf Anhalten drücken und landest dort, wo der Fehler aufgetreten ist. Links oben siehst du, was in welcher Reihenfolge vorher aufgerufen wurde und kannst dich dort durchklicken.
Vermutlich passiert der Fehler in OnGetText oder so, wenn das Laden an sich keinen Fehler produziert.
Ich würde dir aber sehr raten, die Daten unabhängig von der Anzeige zu verwalten. Das ist auch sehr viel einfacher, wenn du die als Json oder XML speicherst, weil die die Inhalte dann auch in einem Texteditor direkt prüfen (und ändern) kannst.
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 19.09.24 10:00
Dann schau dir Tutorial: Debugging in Delphi für Anfänger und Fortgeschr. an (ist zwar für Delphi 2007 geschrieben, grundsätzlich sollte sich aber nicht viel bei neueren Versionen geändert haben - eher verbesserte Benutzung).
|
|
teamrocket0
Beiträge: 175
Erhaltene Danke: 1
Win ME, Win XP, Win 7, Win 10
Delphi 7, 10.2 Tokyo
|
Verfasst: Mi 25.09.24 23:17
Oh kay...cool.
Mit Hilfe des Debuggers habe ich festgestellt, das die Programmausführung an einer Stelle zum stehen kommt, bei welcher über das "OnMouseUp"-Ereignis ein Integer-Wert des markierten Node abgefragt wird.
Ich habe darauf hin alle Integerwerte die sich hinter den Node's befinden umgebaut zu einem normalen String-Wert. Seitdem funktioniert das Schreiben und Lesen der Stream-Datei anscheinend Fehlerfrei.
Also muss der Fehler bei einer der zwei Aufgaben liegen:
Integer-Werte im Stream ablegen:
Delphi-Quelltext 1:
| Stream.write(Data^.wallpaper, SizeOf(Data^.wallpaper)); |
oder Integerwerte aus dem Stream abrufen:
Delphi-Quelltext 1: 2:
| Stream.read(Len, SizeOf(Len)); Stream.read(Data.wallpaper, SizeOf(Data.wallpaper)); |
Der Unterschied zum "String"-Stream ist, das beim einlesen auch die Länge festgelegt wird.
Delphi-Quelltext 1: 2: 3:
| Stream.read(Len, SizeOf(Len)); SetLength(Data^.ServerAdress, Len); Stream.read(PChar(Data^.ServerAdress)^, Len*SizeOf(Char)); |
Ich weiß von meinen Integer-Werten, das diese nur eine Stelle lang sein sollten. 0 oder 1.
Kann ich das nicht kurzerhand auch festlegen?
Soweit erstmal.
_________________ To be forgotten is worse than death!
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Gestern um 09:37
Jetzt sehe ich erst deinen Fehler - auch aufgrund deiner Beschreibung.
Du hast auch bei den Integerwerten jeweils die Länge ( Len) vorher eingelesen, das ist aber unnötig, da Integer binär immer die selbe Größe haben, s. Einfache_Typen_(Delphi) (detaillierter wird es in Interne Datenformate (Delphi) beschrieben).
Lösche also jeweils (vor dem Einlesen der 4 Integer-Werte)
Delphi-Quelltext 1:
| Stream.read(Len, SizeOf(Len)); |
Wenn es sich bei deinen 4 Integerwerten nur um logische Ein-/Ausschalter handelt, dann kannst du auch einfach Boolean (mit den Werten true und false) verwenden - und an dem Code zum binären Lesen und Schreiben ändert sich nichts.
|
|
|