Recent

Author Topic: [SOLVED] TShellTreeView node corruption  (Read 2917 times)

petevick

  • Sr. Member
  • ****
  • Posts: 419
[SOLVED] TShellTreeView node corruption
« on: January 29, 2024, 07:38:10 pm »
In the attached project is a mini folder browser that creates and deletes folders. When I create a folder in an empty folder I sometimes get a 'External:SIGSEGV' error, but it seems to be a bit random. It's triggered in the MenuNewFolderClick() procedure and starting at line 408, pNode seems to be corrupt after line 409.
This happens in Linux and Windows. I'd be grateful for any help in tracking the problem.
« Last Edit: January 30, 2024, 05:58:06 pm by petevick »
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13212
Re: TShellTreeView node corruption
« Reply #1 on: January 29, 2024, 07:46:38 pm »
Please remove third-party controls from the project and replace them by standard controls if their functionality is needed.

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView node corruption
« Reply #2 on: January 29, 2024, 08:53:09 pm »
Please remove third-party controls from the project and replace them by standard controls if their functionality is needed.
I've replaced all the BGRA controls, but I'm still getting the random error, just not as often, and I'm still unable to track why it happens. The error still happens in Linux and Windows.
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

dsiders

  • Hero Member
  • *****
  • Posts: 1469
Re: TShellTreeView node corruption
« Reply #3 on: January 29, 2024, 09:32:27 pm »
Please remove third-party controls from the project and replace them by standard controls if their functionality is needed.
I've replaced all the BGRA controls, but I'm still getting the random error, just not as often, and I'm still unable to track why it happens. The error still happens in Linux and Windows.

I'll bet you don't have a directory called: C:\home\Pete\C:\
Preview the next Lazarus documentation release at: https://dsiders.gitlab.io/lazdocsnext

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView node corruption
« Reply #4 on: January 29, 2024, 09:38:46 pm »
I'll bet you don't have a directory called: C:\home\Pete\C:\
You're not wrong, it's what happens when you swap from Windows to Linux
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13212
Re: TShellTreeView node corruption
« Reply #5 on: January 29, 2024, 11:35:57 pm »
Yes, I saw some crashes, it seems they occur when the "if pNode.HasChildren" condition is false. In this case you repopulate the tree starting at the parent of pnode. But this is critical since it erases the old pnode and creates a new one. Therefore, pnode which you had determined at the beginning of the procedure is no longer valid.

I'd store the path to the new node in a variable (newPath := mytreeView.path + TmpName;) and then simply call the FindNodeWithPath method of the tree's Items to get to the newly created node.
Code: Pascal  [Select][+][-]
  1.     newPath := mytreeView.path + TmpName;
  2.  
  3.     pNode:=myTreeView.Selected;
  4.     if CreateDir(newPath) then
  5.     begin
  6.       pNode.Expanded:=False;
  7.       pNode.Expanded:=True;
  8.       if pNode.HasChildren then
  9.         pNode:= pNode.FindNode(TmpName)
  10.       else
  11.       begin
  12.         pNode.Parent.Expanded := false;
  13.         pNode.Parent.Expanded := true;
  14.         pNode := myTreeView.Items.FindNodeWithTextPath(newPath);
  15.       end;
  16.       pNode.Selected:=True;
  17.     end;

Another (less important) issue is the check "if OSVersion = 'Win'" since your OSVersion() function returns the string 'Windows' rather than 'Win'.

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView node corruption
« Reply #6 on: January 30, 2024, 08:39:11 am »
Yes, I saw some crashes, it seems they occur when the "if pNode.HasChildren" condition is false. In this case you repopulate the tree starting at the parent of pnode. But this is critical since it erases the old pnode and creates a new one. Therefore, pnode which you had determined at the beginning of the procedure is no longer valid.

I'd store the path to the new node in a variable (newPath := mytreeView.path + TmpName;) and then simply call the FindNodeWithPath method of the tree's Items to get to the newly created node.
Code: Pascal  [Select][+][-]
  1.     newPath := mytreeView.path + TmpName;
  2.  
  3.     pNode:=myTreeView.Selected;
  4.     if CreateDir(newPath) then
  5.     begin
  6.       pNode.Expanded:=False;
  7.       pNode.Expanded:=True;
  8.       if pNode.HasChildren then
  9.         pNode:= pNode.FindNode(TmpName)
  10.       else
  11.       begin
  12.         pNode.Parent.Expanded := false;
  13.         pNode.Parent.Expanded := true;
  14.         pNode := myTreeView.Items.FindNodeWithTextPath(newPath);
  15.       end;
  16.       pNode.Selected:=True;
  17.     end;

Another (less important) issue is the check "if OSVersion = 'Win'" since your OSVersion() function returns the string 'Windows' rather than 'Win'.
Unfortunately that still generates errors for me. Line 14 equates to Nil in both Linux and Windows and then obviously line 16 gives the error.
Full procedure...

Code: Pascal  [Select][+][-]
  1. procedure TForm1.MenuNewFolderClick(Sender: TObject);
  2. var
  3.   pNode: TTreeNode;
  4.   TmpName: String = '';
  5.   NewPath: String = '';
  6.   n: Integer = 1;
  7. begin
  8.   if myTreeView.Selected <> Nil then
  9.   begin
  10.     if OSVersion = 'Windows' then begin
  11.      TmpName:='New folder';
  12.      While DirectoryExists(myTreeView.Path+TmpName) do
  13.        begin
  14.        TmpName:= 'New folder ('+IntToStr(n)+')';
  15.        n:= n+1;
  16.        end;
  17.     end else begin
  18.       TmpName:='Untitled Folder';
  19.       While DirectoryExists(myTreeView.Path+TmpName) do
  20.         begin
  21.         TmpName:= 'Untitled Folder '+IntToStr(n);
  22.         n:= n+1;
  23.         end;
  24.     end;
  25.    NewPath := mytreeView.path + TmpName;
  26.    pNode:=myTreeView.Selected;
  27.    if CreateDir(myTreeView.Path+TmpName) then
  28.    begin
  29.     pNode.Expanded:=False;
  30.     pNode.Expanded:=True;
  31.     if pNode.HasChildren then
  32.       pNode:= pNode.FindNode(TmpName)
  33.     else
  34.     begin
  35.       pNode.Parent.Expanded := false;
  36.       pNode.Parent.Expanded := true;
  37.       pNode := myTreeView.Items.FindNodeWithTextPath(NewPath);
  38.     end;
  39.     pNode.Selected:=True;
  40.     end;
  41.    end;
  42. end;

Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13212
Re: TShellTreeView node corruption
« Reply #7 on: January 30, 2024, 10:35:02 am »
Tested on Windows (Laz/main) and Mint (Laz/3.0) - no problem here...

Set a breakpoint at the guilty line with FindNodeWithTextPath and check what's in "newPath". Sometimes directories have a trailing (back)slash (although I cannot imagine how it could get there). What are the path delimiters? There was an issue because the path delimiter is inherited from the treeview ancestor which always uses a forward slash - this will cause a problem in Windows which wants a backslash (IIRC, this was fixed in Laz 3.0).

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView node corruption
« Reply #8 on: January 30, 2024, 12:02:59 pm »
Tested on Windows (Laz/main) and Mint (Laz/3.0) - no problem here...

Set a breakpoint at the guilty line with FindNodeWithTextPath and check what's in "newPath". Sometimes directories have a trailing (back)slash (although I cannot imagine how it could get there). What are the path delimiters? There was an issue because the path delimiter is inherited from the treeview ancestor which always uses a forward slash - this will cause a problem in Windows which wants a backslash (IIRC, this was fixed in Laz 3.0).
Checked newPath in Linux and Windows and the path and delimiters are correct, there is also no trailing delimiter. I also tried with a trailing delimiter, but still got pNode = Nil. I've never had any success using FindNodeWithTextPath() so I've avoiding using it.

Is it remotely possible that I'm not using the latest FindNodeWithTextPath(), even though I'm using Laz 3.0, how would I check ?.
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView node corruption
« Reply #9 on: January 30, 2024, 05:56:43 pm »
@wp - I think I've finally cracked this. I decided to use your method for creating a folder that was in the project you posted here - https://forum.lazarus.freepascal.org/index.php/topic,65978.msg503556.html#msg503556. In my project it worked without error in Linux but I was getting errors in Windows, and auxiliary drives in the tree where disappearing. I was about to give up on it when I had a light bulb moment, in my project the ShellTreeView.Root value was C:\, I checked with your project and it was blank, I changed the value in my project to blank and all the errors went away, plus I get to keep the nice BGRA components  ;D
For completeness, this is the final procedure.....

Code: Pascal  [Select][+][-]
  1. procedure TForm1.MenuNewFolderClick(Sender: TObject);
  2. var
  3.   selNode: TTreeNode;
  4.   selDir: String;
  5.   newDir: String;
  6.   TmpName: String;
  7.   n: Integer = 1;
  8. begin
  9.   selNode := myTreeView.Selected;
  10.   if selNode <> nil then
  11.   begin
  12.     if OSVersion = 'Windows' then begin
  13.      TmpName:='New folder';
  14.      While DirectoryExists(myTreeView.Path+TmpName) do
  15.        begin
  16.        TmpName:= 'New folder ('+IntToStr(n)+')';
  17.        n:= n+1;
  18.        end;
  19.     end else begin
  20.       TmpName:='Untitled Folder';
  21.       While DirectoryExists(myTreeView.Path+TmpName) do
  22.         begin
  23.         TmpName:= 'Untitled Folder '+IntToStr(n);
  24.         n:= n+1;
  25.         end;
  26.     end;
  27.     selDir := myTreeView.GetPathFromNode(selNode);
  28.     newDir := selDir + TmpName;
  29.     CreateDir(newDir);
  30.     UpdateShellTreeView(myTreeView, selDir);
  31.     myTreeView.Path := newDir;
  32.   end else
  33.     ShowMessage('Please select the folder to which the new folder should be added.');
  34. end;
  35.  

I'll probably sleep a bit better tonight now. Thanks for all the help you've given me wp, I really do appreciate it,  ;)
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13212
Re: [SOLVED] TShellTreeView node corruption
« Reply #10 on: January 30, 2024, 06:03:50 pm »
Yeah, I was about to write the same... Just had to fix a small bug in the Laz/main TShellTreeView.UpdateView.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.MenuNewFolderClick(Sender: TObject);
  2. var
  3.   oldPath: String;
  4.   newPath: String;
  5.   newName: String;
  6.   TmpName: String;
  7.   n: Integer = 1;
  8. begin
  9.   oldPath := myTreeView.Path;
  10.   if OSVersion = 'Windows' then
  11.     newName := 'New folder'
  12.   else
  13.     newName := 'Untitled folder';
  14.   TmpName := newName;
  15.   While DirectoryExists(oldPath+TmpName) do
  16.   begin
  17.     TmpName := Format('%s (%d)', [newName, n]);
  18.     n:= n+1;
  19.   end;
  20.  
  21.   newPath := oldpath + TmpName;
  22.   if CreateDir(newPath) then
  23.   begin
  24.     UpdateShellTreeView(mytreeView, oldPath);
  25.     myTreeView.Path := newPath;
  26.    end;
  27. end;

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: [SOLVED] TShellTreeView node corruption
« Reply #11 on: January 30, 2024, 06:15:18 pm »
Yeah, I was about to write the same... Just had to fix a small bug in the Laz/main TShellTreeView.UpdateView.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.MenuNewFolderClick(Sender: TObject);
  2. var
  3.   oldPath: String;
  4.   newPath: String;
  5.   newName: String;
  6.   TmpName: String;
  7.   n: Integer = 1;
  8. begin
  9.   oldPath := myTreeView.Path;
  10.   if OSVersion = 'Windows' then
  11.     newName := 'New folder'
  12.   else
  13.     newName := 'Untitled folder';
  14.   TmpName := newName;
  15.   While DirectoryExists(oldPath+TmpName) do
  16.   begin
  17.     TmpName := Format('%s (%d)', [newName, n]);
  18.     n:= n+1;
  19.   end;
  20.  
  21.   newPath := oldpath + TmpName;
  22.   if CreateDir(newPath) then
  23.   begin
  24.     UpdateShellTreeView(mytreeView, oldPath);
  25.     myTreeView.Path := newPath;
  26.    end;
  27. end;

Brilliant, even simpler !!  ;D
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: [SOLVED] TShellTreeView node corruption
« Reply #12 on: January 30, 2024, 07:33:05 pm »
Yeah, I was about to write the same... Just had to fix a small bug in the Laz/main TShellTreeView.UpdateView.
wp, would I simply copy the shellctrls.pas file from git to my lcl folder ??
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13212
Re: [SOLVED] TShellTreeView node corruption
« Reply #13 on: January 30, 2024, 07:54:07 pm »
You can try, but there is a high probability that the ShellCtrls of Laz/main depends on changes in other units of main, and then you will not be able to compile that mix-up with your Laz 2.2.6 any more. Therefore, absolutely necessary before such experiments: always make a backup copy of the changed file(s) so that you can always return to the starting point.

The recommended way would be to install Laz/3.0 and to patch ShellCtrls with the two tiny changes I had to make in Shelltreview.UpdateView. Or even better, to install Laz/fixes from source (the new changes are not yet in there, but I can take care of speeding it up).

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: [SOLVED] TShellTreeView node corruption
« Reply #14 on: January 30, 2024, 08:43:30 pm »
You can try, but there is a high probability that the ShellCtrls of Laz/main depends on changes in other units of main, and then you will not be able to compile that mix-up with your Laz 2.2.6 any more. Therefore, absolutely necessary before such experiments: always make a backup copy of the changed file(s) so that you can always return to the starting point.

The recommended way would be to install Laz/3.0 and to patch ShellCtrls with the two tiny changes I had to make in Shelltreview.UpdateView. Or even better, to install Laz/fixes from source (the new changes are not yet in there, but I can take care of speeding it up).
How would I go about installing Laz/fixes. From searching for Laz/fixes I came across FPCUpDeluxe, would that be a better option ?.
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

 

TinyPortal © 2005-2018