# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  [VB6] ucShellTree - Full-featured Shell Tree UserControl

## fafalone

ucShellTree v2.7
Released 25 January 2022

*About*
Designed for navigating the Windows Shell, like my recent Shell Browser Control, ucShellBrowse. This UserControl shows an Explorer-style TreeView of the entire shell, descended from the Desktop like normal. It's very similar to the INamespaceTreeControl in functionality and features, but a manual implementation allows a few extras that aren't available, like automatically handled tri-state checkboxes and open-to-path, and the ability to implement further customizations.  

*Key Features*
Displays complete Explorer-type tree with either Desktop, Computer, or a custom path as the root folder.Tri-state checkboxes show partial selections when check mode is enabled, 4th state with red x is available as an option.Supports drag/drop with modern drag images and drag-over-highlighting (including expanding on hover), based on my cDropTarget project. Can drop on all valid drop targets: folders, zip files, programs, shortcuts to them, etc.Right-click shows the standard Explorer context menu for the clicked itemAutomatically monitors for changes (item created, deleted, renamed) and updates the tree accordingly.Option to show files as wellCan automatically expand to a given path.InfoTips with several lines of details depending on file type are shown as ToolTipsFilter option can limit the type of files displayed (or even folders)Can rename in place using LabelEditCan (optionally) treat .zip/.cab files as a folderOptional additional root entry for 'Favorites' that shows the Links folder.Browses the Network folder too and returns paths as \\Share\etcetcComplete Unicode support

*Requirements*
-Windows Vista or newer
-oleexp 4.42 or higher (not needed once compiled into OCX)

Strongly recommended: Common Controls 6.0 Manifest (see here). The Demo projects have a manifest added for when they're compiled, but the IDE and your own projects will need their own. The control works without it, but I haven't fully explored what other things might break without it. This paragraph previously mentioned checkbox issues--- there's no partial checkboxes or exclusion checkboxes but the project now gets the checkboxes from Windows rather than its own, so normal unthemed checks are fine.

DemoSB: In the DemoSB folder, there's a project that shows the use of ucShellTree with my ucShellBrowse control. This requires ucShellBrowse to be present in the same root as ucShellTree (e.g. C:\vb6\ucShellBrowse and C:\vb6\ucShellBrowse). You can also see this done in the DemoEx sample in the ucShellBrowse download.

*Compiling to OCX*
It's very simple to use the control as an OCX: Open ShellTree.vbp from the main folder, double-click ucShellTree.ctl in the project explorer (under UserControls), and in the properties for the control, change Public to True, you can then compile. Then proceed to move, register, and use as you would any other .ocx. 
*UPDATE:* A project with the OCX requires oleexp.tlb if you want to respond to any event with an IShellItem or IShellItemArray member. I'm sorry for providing inaccurate information about the need to include it in the past.

The demo projects use the control as a .ctl.


*Works with ucShellBrowse*(Optional -- You can of course use this control by itself without the presence of ucShellBrowse)
This project is similar to my recent ucShellBrowse control, and indeed if you prefer a TreeView to the dropdown for navigation, this control works seamlessly with it-- since it can be put into FilesOnly mode. There's a demo project of this setup in the \DemoSB folder (ucShellBrowse DL'd separate, grab the latest version from the ucShellBrowse project thread -- which has its own version of the demo in DemoEx).

There's even an optional feature for seamless integration with the layout options. The ShellTreeInLayout option in ucShellBrowse adds a menu item to allow the user to toggle the ShellTree control (by raising the ShowShellTree event, notifying you to show or hide it) from the ShellBrowse control's layout menu:



*Recent Updates*
UPDATE - 25 Jan 2022
-Project updated to 2.7.


```
-Added ShowHiddenItems/ShowSuperHidden options

-Added EnableShellMenu option to control whether the right-click menu pops up.

-Added SetFocusOnTree method.

-Added public event for UserControl_EnterFocus and UserControl_ExitFocus (EnterFocus
 and ExitFocus, respectively).

-(Bug fix) Keyboard focus never went to ucTreeView when on a form with ucShellBrowse.
```

*UPDATE - 03 April 2021*
Project updated to v2.6. Small update to address a bug in OCX builds, add Select/Click events with IShellItem references, remove the need to track a variable when combined with ucShellBrowse for directory changes (bChanging in the demos), and add a SelectNone sub to deselect.



```
'v2.6 (Released 03 Apr 2021)
'
'-Eliminated the need to use a variable to keep tracking of dir change operations when
' combining this control with a ucShellBrowse control; previously you'd handle a path
' change notification from the browser with
' If bChanging = False Then
'    bChanging = True
'    ucShellTree1.OpenToItem siItem, False
'    bChanging = False
' End If
' Now you no long need the bChanging variable.
'
'-Added SelectNone sub, which will clear all selected items (supports multiselect).
'
'-Added ItemSelectByShellItem event. I wanted to just include an IShellItem member in
' ItemSelect, but the backwards compatibility concerns are too great. This event will
' also include all the information of ItemSelect if you want to fully switch over.
'-Did the same for ItemClick->ItemClickByShellItem
'
'-For MultiSelect, added the MultiSelectChange event, which includes an IShellItemArray
' of selected items as well as a name list and full path list
'
'-(Bug fix) Using On Error Resume Next to handle an uninitialized array in the Terminate
'           event caused the control to freeze on compile or on run after changes if
'           you were using it as an OCX.
```

*UPDATE - 09 December 2020*
Project updated to v2.5 R2 - Critical bug fix; when navigating in the Network folder via OpenToItem (usually from a ShellBrowse control), and potentially other non-standard locations, if the folder wasn't manually expanded, automatic expansion would error out and not expand. 

Project updated to v2.5. Unbelievably, the control never had BackColor/ForeColor options. Those have been added. Also added a full RefreshTreeView function. Previously there was ResetTreeView, which loaded the initial state. But RefreshTreeView will now rebuild all the folders you had open before the Refresh. Also fixed a mobile device bug.

While you're at it, check out the update to ucShellBrowse on the same day as this--- it lets you integrate the two much more closely:


*UPDATE - 20 September 2020*
Project updated to v2.4 in order to eliminate all non-explicit types defined in the TLB. These would cause a show-stopping conflict if the control was used in a project that had any of these as a Public Type, or in a project with them defined in another TLB if it was a higher priority. Also, added AlwaysShowExtendedVerbs option; these are no longer shown by default in the Shell Context Menu, you need to hold Shift when bringing up the menu if this option is False.




*NEW!* I'm also now distributing ucShellBrowse and ucShellTree together as a compiled OCX, complete with SxS resources to create registration-free distributions.

[VB6] Shell Controls OCX

----------


## fafalone

*Known Issues*
There's an issue that when Autocheck = True and ExclusionChecks = False, items that are partially checked (formerly, gray check), are listed as checked in .CheckPaths. To fix, in the WndProc (last function in the module), in the TVN_ITEMCHANGEDW block, the bolded branch should be added to the if-block at the bottom:



```
                If (nmtvic.uStateNew And TVIS_STATEIMAGEMASK) = &H1000 Then
                    TVEntries(nmtvic.lParam).Checked = False
                    TVEntries(nmtvic.lParam).Excluded = False
                ElseIf (nmtvic.uStateNew And TVIS_STATEIMAGEMASK) = &H2000 Then
                    DebugAppend "ItemCheck"
                    TVEntries(nmtvic.lParam).Checked = True
                    TVEntries(nmtvic.lParam).Excluded = False
                ElseIf ((nmtvic.uStateNew And TVIS_STATEIMAGEMASK) = &H3000) And (mAutocheck = True) Then
                    TVEntries(nmtvic.lParam).Checked = False
                    If mExCheckboxes Then
                        TVEntries(nmtvic.lParam).Excluded = True
                    End If
                ElseIf ((nmtvic.uStateNew And TVIS_STATEIMAGEMASK) = &H3000) And (mAutocheck = False) Then
                    DebugAppend "ItemExclude"
                    TVEntries(nmtvic.lParam).Checked = False
                    TVEntries(nmtvic.lParam).Excluded = True
                ElseIf (nmtvic.uStateNew And TVIS_STATEIMAGEMASK) = &H4000 Then
                    TVEntries(nmtvic.lParam).Checked = False
                    TVEntries(nmtvic.lParam).Excluded = True
                End If
```

Do not call the Public dbg_checkstyle sub; it's meant to be Private.

----------


## sabbath69

Fafalone, Great code I must say. It works awesomely!
However I have an issue that I do not understand fully.

I have taken your DEMO.VBP from the DEMO subfolder and added another startup form, named "Form2". On this "Form2" I just have a button that then loads your "Form1" as modal.
When I close your "Form1", I expect that the Usercontrol_Terminate event would be called, however it does not get called until I close "Form2".

Typically when a form that hosts a Usercontrol unloads the Terminate event would get fired. Perhaps there are references left over but I cannot find any?

Can you offer any advise, it would be greatly appreciated.

----------


## fafalone

I can replicate what you're talking about, but I'm unsure of the cause. First thought was holding an open reference; but since the event isn't even firing cleanup doesn't even start. Other API-based CommonControl project I tested doesn't have this issue, so I'll have to study it further.

----------


## fafalone

*ucShellTree 2.0 has been released!*

This update brings in a number of new features in addition to some minor bugfixes. The partial checks/autochecking is now optional (and exclusion checks can be added), you can now specify any folder as the root, get/set checks by path, and more. Here's the full changelog:


```
'v2
'
'-You can now specify a custom folder as root*. Changeable during runtime.

'-Added PathGetCheck and PathSetCheck functions. The Set function also has an option to
' expand to show the given path in the event it's not yet visible.
'
'-The OpenToPath/OpenToItem functions now have an option to just expand to but not select
' the item, primarily for the check set function but available in general; default=select.
'
'-The .InitialPath property is deprecated. The creation sequence has changed, you can
' now just use OpenPath in your Form_Load (or equiv.) event. It remains for compatibility.
'
'-Added RootHasCheckbox option to set whether or not one appears (when checkboxes are enabled).
'
'-Added ExclusionChecks option, which adds an additional checkbox state- a red x. The .ExcludedPaths
' method functions in the same way as the .CheckedPaths method to retrieve paths in this state (they
' are not counted as checked).
'
'-Added ExplorerStyle option to allow control over whether the Explorer visual style is applied.
'
'-Added HorizontalScroll option, to set whether the tree expands without needed HScroll.
'
'-Adjusted the RootHasCheckbox option so that if it's changed at runtime, the correct state is set.
'
'-Changed disable criteria such that valid file drop targets are excepted from normal disabled prop
' list. This was mainly to get the Recycle Bin enabled since it's completely browsable. Other items
' remain disabled. (You can change this in TVExpandFolder if desired).
'
'-Added Autocheck option for control over whether partial checks are shown and whether parent and
' child items are automatically changed according to a new check action.
'
'-The control will now fall back to plain checkboxes if no Common Control 6 manifest is present, but
' all autocheck functionality is unavailable (even checking all children of a checked parent).
' Previously checkboxes were not present at all without a manifest.
'
'(Bug fix) The outer edge of the control on dragover indicated a droptarget on no item but
'          seemingly valid; it now correctly shows no drop is possible.
'
'(Bug fix) Invalid (malformed/corrupt) shortcut files caused an error that wasn't handled, so
'          the item enumeration when expanding a folder stopped when it reached it.
'
'(Bug fix) When you call GetParent on your user folder, you get the desktop instead of \Users\,
'          this caused some issues with auto-navigating.
'
'(Control/code) So I thought you needed to supply your own check imagelist for partial checkboxes,
'               since the extended style wasn't working, but it turned out the problem was just that
'               you can't set the TVS_CHECKBOXES style; just TVS_EX_PARTIALCHECKBOXES. So the images
'               have been removed, which eliminates transparency issues and will keep the appearance
'               the same as the OS.
'
'-------
'* - Technical note: This can be any path string/identifier resolvable by SHCreateItemFromParsingName
```






The terminate issue has been resolved, see this thread for details of how it was done (I'm using the fix Eduardo- worked out in post #5), or just update to the new version:

*Version 2.1 has been released!*

In addition to the bugfix that prompted bumping up the new release to tonight, there's several new features and other fixes (including to the Explorer-style issue from post #2 that was there forever). Here's the full changelog:


```
'v2.11 (Released 15 Feb 2019 - Critical bug fix only)
'-(Bug fix) Previous fix regarding PathMatchSpecW resulted in always loading the Computer
'           folder as root.
'
'v2.1 (Released 30 Jan 2019)
'-The font for the TreeView is now a standard property. (Borrowed from Krool's
' TreeView. Thanks!)
'
'-Shell context menu tips are now passed in the StatusMessage event.
'
'-Filter now supports multiple patterns separated by semi-colon.
'
'-Replaced Border property with BorderStyle, which has several more options.
'
'-(Bug fix) If the control was on a secondary form, unloading that form did not unload
'           the control, and it stayed loaded in the background until the whole program
'           ended. Thanks to dz32 and Eduardo- for figuring out the solution.
'
'-(Bug fix) Fixed automatic navigation not expanding when a parent of a parent was
'           collapsed; only the immediate parent was checked previously.
'
'-(Bug fix) Custom Roots were checked for validity with PathMatchSpecW, which does
'           not support virtual locations. Now it's checked by going ahead and trying
'           to create the IShellItem for it, allowing roots like ::{GUID}
```

*NOTE:* ucShellBrowse, often a companion to this control, has the same bug where UserControl_Terminate doesn't fire. (EDIT: Both projects now have that fixed as of 2.1 for this control, 5.2 for ucShellBrowse)

*UPDATE:* 2.11 released for critical bug fix where Desktop could not be selected and the root.

----------


## sabbath69

Thanks to all involved here, added new changes, tested and all is fine now. Awesome work people.

----------


## sabbath69

Fafalone,

The unloading is now fixed, however the other big-fix around the PathMatchSpecW is causing other problems.

Here is your Demo v2.0:-

You can see that the root is DESKTOP and it shows Libraries, Network.....etc

Now here is your Demo v2.1:-


You can ignore the difference with the checkboxes, but in the new one you can see that the root is now the COMPUTER, even though I have not supplied a custom root.

When there is no custom root and it goes into the Sub EnumRoot.... the following code, calling the SHCreateItemFromParsingName returns an siDesk item, so it then sets the bCustRt as True.
However what it has returned is the Computer.

In v2.0 code it did the PathFileExistsW(StrPtr(mCustomRoot)) call which failed so it then went onto Call oleexp.SHCreateItemFromIDList(VarPtr(0&), IID_IShellItem, siDesk) which then returned the DESKTOP correctly.




```
If mComputerAsRoot Then
    oleexp.SHGetKnownFolderItem FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, 0&, IID_IShellItem, siDesk
Else
    Set siDesk = Nothing
    oleexp.SHCreateItemFromParsingName StrPtr(mCustomRoot), Nothing, IID_IShellItem, siDesk
    If (siDesk Is Nothing) = False Then
        bCustRt = True
    Else
        Call oleexp.SHCreateItemFromIDList(VarPtr(0&), IID_IShellItem, siDesk)
    End If
    TVEntries(0).bDropTarget = True
End If
```


Hope this makes sense, but as I said if you just run the new Demo against the old with no customer root, you should see the difference.

----------


## sabbath69

Fafalone,

I also noticed another issue when attempting to open the Tree to a UNC path.
If the path was "\\server\FolderOne" for example.
In v2.0 of the code it would end up crashing out with an Out of Stack Space error.
It seemed to have an issue once it got the ROOT of this path which was "::{GUID}".
It just seemed to loop around endlessly at this point and then fail.
I assume this is what you had found and were trying to fix with the last changes you made relating to the custom Roots.

In v2.1 of the code it does not crash out, but it does not show the full tree either, and I presume because it is unaware of the NETWORK (see my earlier post).
Let me know if you need a better example on this one.

Trev.

----------


## fafalone

Need more info with what you mean about network paths; opening while running or as root? I'm not seeing any issue loading network paths with either.

----------


## sabbath69

Will post more info on Monday, but if you set the code under the "OPENTO" button in the Demo to open to a path like "\\server\folderone" I would see the problems using v2.0 of the code.
When it attempted to go back up the path to the root, it would get to a path of "::{GUID}" and then just get caught in a loop and eventually crash.

----------


## sabbath69

Fafalone,

Here is more information regarding Network paths, and the differences that we now have between 2.0 and 2.1 code, and the problem I faced with 2.0 code.

Scenario:-
The Tree is loaded, no custom root has been offered so the root is being determined by the 2.1 code.
We then issue a call to -


```
ucShellTree1.OpenToPath "\\server\nonbackup\Folder1\Folder2\Folder3\Mykra", True
```



Here is the result from v2.1 code:-


I have also attached the DEBUG trace output of the above.
UCShellTree2-1 results.txt
As you can see the Network branch is no longer shown in 2.1 and when OpenToPath is issued, all it does is just add the "Mykra" to the tree, with no parent, or expand folders.

Result from 2.0 code:-


No image after call to "OpenToPath" as it crashes with an "Out of Stack Space" error.
The DEBUG trace file is attached, albeit shortened as it just keeps repeating.
UCSHELLOUTPUT.txt

Details for the UNC path I am using.
SERVER is the name of a file server I have.
nonbackup is a shared folder on the server
Folder1, Folder2, Folder3 and Mykra are just subfolders.

I hope this helps. Let me know if you need anything further.

----------


## fafalone

Does fixing the first not fix the second, or had you not applied that change? (What I did was check mCustomPath wasn't blank). I've been really busy this week I'll update things tomorrow. 

Adding the folder without a parent is by-design though; it was made for virtual locations that can be opened but don't have parents; so if a location is valid, but a parent can't be found, it inserts under the root. Once the 'Network' is back it will add under that.

Edit: Project updated to 2.11 to address Desktop not loading as root issue. If this doesn't fix the other issues too we can revisit but in the meantime I had to get a fix out for a bug that severe.

----------


## sabbath69

Will check again with new 2.11 code on Monday and come back to you. Thanks Fafalone.

----------


## sabbath69

Fafalone,

I can confirm that v2.11 resolves the missing Desktop.

I can also confirm that there is still just a very small issue with Network browsing (or any path for that matter, depending on the string value passed).

In my case my Network path still failed and hit your loop limit of 100, because the PATH used was "\\server\nonbackup\Folder1\Folder2\Folder3\Mykra".
The Function GetMapIdxByPath never found a match for the "server" because when it was populated into the TVVisMap it was in UPPERCASE, and we were passing it lowercase. Seems like all Network computers are returned UPPERCASE.

To resolve this I just adjusted this function as follows by adding in the UCASE$ statements.



```
Private Function GetMapIdxByPath(sFullPath As String) As Long
Dim i As Long

    For i = 0 To UBound(TVVisMap)
        If UCase$(TVVisMap(i).sFullPath) = UCase$(sFullPath) Then
            GetMapIdxByPath = i
            Exit Function
        End If
    Next i
    GetMapIdxByPath = -1

End Function
```

Please advise if there was a better way of handling this.

Thanks for this work Fafalone, the code is awesome.
 :Smilie:

----------


## fafalone

Yeah a lot of the directory matching things are case sensitive; I'll include that change in the next update.

You're welcome, always good to know projects are appreciated  :Thumb:

----------


## sabbath69

Fafalone,

Further to my previous note about adding Ucase$ into the GetMapIdxByPath function, it should probably be also added to the GetNodeByPath function as well, like below:-



```
Private Function GetNodeByPath(sFullPath As String) As Long
Dim I As Long

    For I = 0 To UBound(TVEntries)
        If UCase$(TVEntries(I).sFullPath) = UCase$(sFullPath) Then
            GetNodeByPath = TVEntries(I).hNode
            Exit Function
        End If
    Next I
    GetNodeByPath = -1

End Function
```

Cheers.
sabbath69

----------


## sabbath69

Fafalone,

I have discovered an issue with attempting to OpenPath to the User's DESKTOP folder.

If you attempt to "C:\Users\Trevor\DESKTOP" it will fail and not find anything in the TVNavigate sub.

Cheers!

----------


## fafalone

If you look down in TVNavigate, you'll see I had already encountered a similar bug; there's issues with properly returning the parent of user folder items. 
In the case of navigating to the desktop, it returns nothing for the parent of the desktop; which is generally true, as it's also the navigation root--- if you keep requesting parents you always wind up at the desktop. 
So here's a temporary fix, but I'm going to have to look into the possible consequences of sometimes treating it as root and sometimes not (although the root is internally defined as "0" so I'm hoping it's ok).

After the If idx > -1 block, not within it but after it, there's the statement
si.GetParent siPar
replace that line with the following


```
If sFull = sUserDesktop Then
    SHGetKnownFolderItem FOLDERID_Profile, KF_FLAG_DEFAULT, 0&, IID_IShellItem, siPar
Else
    si.GetParent siPar
End If
```

All those vars/functions are already declared so that's the only change to make.

----------


## sabbath69

Fafalone,

I have a Feature Request. (or some guidance on how I could implement)

Another Tree control that I used to use, had a nice feature that was the ability to load/expand to a folder path without traversing all other folders. "Fast" mode if you like.
This enabled great speed and removed some of the overhead of adding all other folders, but still gave the user the ability to expand any folder if they desired.

Example - 
Open to this folder = "\\server\NonBackup\Folder1\Folder2\Folder3"

Would produce this sort of result


As you can see the folders are listed and expanded, although they still have the "+" icon so they can be expanded by the user if desired.


I have tried to have a go myself at adding such a feature, but have struggled basing it on some of you existing routines.
I can see how to add items, but cannot determine how to add a child item and have the Parent expanded, but still keep the "+" icon so that it thinks it is not expanded.

Do you think this you would be able to offer some advise on how I could get this added.

Thanks.
sabbath69

----------


## fafalone

I'm familiar with what you're talking about. It's a good idea and I'll work on it; but it's going to need an entirely new autonavigate function, and might have to change the way the whole directory loading works. So can't put a timeframe on it.

----------


## fafalone

*Project Updated*
ucShellTree v2.12
This is a minor update to correct the Windows 10 Virtual Device Navigation Bug (Phones, cameras, etc, couldn't be browsed past the root, because of an API bug). The DemoSB project shows how change things so that ucShellTree and ucShellBrowse can navigate normally with these devices (ucShellBrowse must be passed an item instead of a path name). 

If any problems persist, let me know, I've tested it best I can but you never know.

_Technical Info_
Navigation in ucShellTree, and previously ucShellBrowse, was conducted by storing the full parsing path of each folder being displayed. Then when it was time to enumerate the next level, an IShellItem was requested using SHCreateItemFromParsingName. Attached USB media devices have crazy long technical names, but on Windows 7 these were resolved fine and the function succeeded. But the same circumstances and same string passed to the API on Windows 10, and it fails. So fallback navigation was added to store file/folder pidls, both the full pidl and the relative pidl, which can then be passed to SHCreateItemFromIDList which succeeds in returning our IShellItem interface.

----------


## MountainMan

In the root folder for you v2.12 update you have a project which will compile to the OCX. However, in ShellTreeVBP there is line

ResFile32="ucst.res"

but that file does not exist in the zip file. It was not in version 2.11 either. Do we need that file or can we make our own .res file that just includes a manifest for the high dpi situation and use of CommonControls 6.0? Thanks.

----------


## fafalone

It's no longer used at all, just an oversight that I forgot to remove that reference, sorry about that.

Several versions ago it had multi-state checkbox images (grayed, red x) but then I realized I was just setting the style flags wrong and the system imagelist had those.

----------


## fafalone

*Project Updated*

Not sure what else I can add for a feature update, so figured I'd go ahead and release a small update to fix the two outstanding bugs.



```
'v2.16 (Released 05 Mar 2020)
'
'-Made extended overlays, found in programs such as TortoiseSVN and Dropbox, a default-off
' option due to the extreme performance cost (a factor of 10-100).
'
'v2.15 (Released 19 Feb 2020)
'
'-(Bug fix) If a Private Enum defined in a UserControl had the same name as one that
'           is defined in a module containing Sub Main, placing more than one of the
'           UserControl in a project caused the control to be grayed out and then an
'           app crash when any other control was initially added to the form.
'           To fix this, all API enums in this control have been prefixed with ucsb_
'           If you're modifying the code of this control, just keep that in mind.
'           No change is needed for using this control or any other code as they're
'           all Private.
'
'-(Bug fix) In ensuring a USB device is already added after OpenToItem, the GetNodeByPath
'           function did not handle USB paths properly, so additional USB device entries
'           were added to the tree.
'
'v2.14
'
'-(Bug fix) If a USB media device (phone, camera, etc-- no drive letter) was added after
'           the program started, it could not be added to the TreeView-- there was some
'           issue with an infinite loop where it kept finding the parent but not adding
'           the child. I couldn't figure out where it was going wrong, so implemented a
'           workaround where the control checks whether it's being asked to navigate to
'           one of these devices, and if it is, manually ensures the device is added.
'           After that, subfolder adding works fine, you can directly navigate to a deep
'           path and all the subfolders will be added; the issue was just adding the
'           device itself.
'
'-(Bug fix) The control uses the SHChangeNotifyRegister API without its own declare; there
'           is a declare in the typelib, and since it wasn't declared explicitly, any
'           Public version in a project module would take precedence, which sometimes
'           caused Type Mismatch errors if the declare was slightly different.
```

Also removed the dead reference from post #22/23

NEW UPDATE ON March 5th, 2020. Major performance boost.

----------


## fafalone

*Project Updated - 05 March 2020*
Due to the extreme magnitude of the performance gain from the following issue, I went ahead and updated the project:

(Fixed in 2.16: Major performance issue) It turns out basically the entire reason ucShellTree is slow for large folders is querying for the overlay icons. It was being done with IShellIconOverlay as that's the only way to get custom overlays for Github, TortoiseSVN, Dropbox, etc. but that single call causes a performance hit by a factor of between *10x and 100x*. Loading a 3,000 item folder literally goes from 100s to 1s just by removing that call. It's now a default-off option. The new way will still display overlays for Shortcuts and Shared folders without enabling the ExtendedOverlays option or suffering any performance degradation, as the index for these is a system constant and presence is determined simply by normal attributes.



```
'v2.16 (Released 05 Mar 2020)
'
'-Made extended overlays, found in programs such as TortoiseSVN and Dropbox, a default-off
' option due to the extreme performance cost (a factor of 10-100).
```

Also note that ucShellBrowse has been updated with this same fix, if you also use that in your project.

----------


## fafalone

*Project Updated - 15 March 2020*

As described in the previous upgrade, the overlays for Shortcuts and Shared should have shown all the time, however they were not shown at all, at overlays have never actually been added until now.

----------


## MountainMan

Fafalone,

Do you have any examples of using drag-and-drop wit ShellTree or ShellBrowse? I looked at the examples you include with these 2 and none have a demo of that capability. Also I don't see an event listed for either control that I can catch and use. Thanks.

----------


## fafalone

You're right I should add an event. 

If you look in the code, there's the TVHandleDrop sub that is already processing drops in place (and the IDropTarget_Drop that calls that), if you wanted to do something further with whatever is dropped.

ShellBrowse has a DropFiles event already:
Public Event DropFiles(sFiles() As String, iEffect As DROPEFFECTS)

Both controls currently fully process the drop- perform the move/copy/paste/execute including showing the menu if it's a right button drag (which includes any shell extension items you see in Explorer) and updates the view.

----------


## fafalone

Ok so until I post an update, add this event to ucShellTree's event declares:
Public Event DropFiles(sFiles() As String, siaFiles As oleexp.IShellItemArray, doDropped As oleexp.IDataObject, sDropParent As String, siDropParent As oleexp.IShellItem, dwDropEffect As oleexp.DROPEFFECTS, dwKeyState As Long)

Then replace IDropTarget_Drop and TVHandleDrop with the following:


```
Private Sub IDropTarget_Drop(ByVal pDataObj As oleexp.IDataObject, ByVal grfKeyState As Long, ByVal ptx As Long, ByVal pty As Long, pdwEffect As oleexp.DROPEFFECTS)
  DebugAppend "IDT_Drop "
   Dim PT As oleexp.POINT
   PT.X = ptx
   PT.Y = pty

pDTH.Drop pDataObj, PT, pdwEffect
TVHandleDrop pDataObj, pdwEffect, PT, grfKeyState
sFolder = ""
TreeView_SelectDropTarget hTVD, 0&
End Sub

Private Sub TVHandleDrop(pdo As oleexp.IDataObject, pdwEffect As oleexp.DROPEFFECTS, PT As oleexp.POINT, dwKeys As Long)
    '<EhHeader>
    On Error GoTo e0
    '</EhHeader>
Dim hSel As Long
Dim lp As Long
Dim psia As oleexp.IShellItemArray
Dim siTarget As IShellItem
Dim pDT As IDropTarget
Dim lpTar As Long, sTar As String
Dim sFilesOut() As String
Dim nFilesOut As Long
ReDim sFilesOut(0)
Dim lButton As Long
If ddRightButton Then
    lButton = MK_RBUTTON
Else
    lButton = MK_LBUTTON
End If

'hSel = TreeView_GetSelection(hTVD)
'lp = GetTVItemlParam(hTVD, hSel)
DebugAppend "DropTarget=" & sFolder
If sFolder = "" Then Exit Sub
oleexp.SHCreateItemFromParsingName StrPtr(sFolder), Nothing, IID_IShellItem, siTarget
If (siTarget Is Nothing) = False Then
    siTarget.BindToHandler 0&, BHID_SFUIObject, IID_IDropTarget, pDT
    If (pDT Is Nothing) = False Then
        pDT.DragEnter pdo, lButton, PT.X, PT.Y, pdwEffect
        pDT.Drop pdo, lButton, PT.X, PT.Y, DROPEFFECT_MOVE Or DROPEFFECT_COPY Or DROPEFFECT_LINK
    Else
        DebugAppend "TVHandleDrop->Failed to get drop target"
    End If
    siTarget.GetDisplayName SIGDN_DESKTOPABSOLUTEPARSING, lpTar
    sTar = LPWSTRtoStr(lpTar)
Else
    DebugAppend "TVHandleDrop->Failed to get target shell item"
End If


oleexp.SHCreateShellItemArrayFromDataObject pdo, IID_IShellItemArray, psia
If (psia Is Nothing) = False Then
    Dim pEnum As oleexp.IEnumShellItems
    Dim sia As oleexp.IShellItem
    Dim lpc As Long, szc As String
    Dim pcl As Long
    psia.EnumItems pEnum
    If (pEnum Is Nothing) = False Then
        Do While pEnum.Next(1&, sia, pcl) = S_OK
            sia.GetDisplayName SIGDN_DESKTOPABSOLUTEPARSING, lpc
            ReDim Preserve sFilesOut(nFilesOut)
            sFilesOut(nFilesOut) = LPWSTRtoStr(lpc)
            nFilesOut = nFilesOut + 1
        Loop
    End If
End If

RaiseEvent DropFiles(sFilesOut, psia, pdo, sTar, siTarget, pdwEffect, dwKeys)
'<EhFooter>
Exit Sub

e0:
    DebugAppend "ucShellTree.TVHandleDrop->Error: " & Err.Description & ", 0x" & Hex$(Err.Number)
'</EhFooter>
End Sub
```

I'll be updating ShellBrowse with a more detailed version like this in the future as well.

----------


## fafalone

*Project Updated! Version 2.2 Released on 23 April 2020*

Made a small feature update with the drop event from above, a drag event, ability to disable drag/drop, and ...MULTISELECT! It turns out MSDN saying 'Not supported. Do not use.' really means 'Fully functional'. Check Windows 7 and 10, works fine. It may stop working at some point in the future, but for now it's good to go.



```
'v2.2 (Released 23 April 2020)
'
'-Added DropFiles event and DragStart event.
'
'-Added Multiselect option. MSDN says "Not supported, do not use." but this style appears
' to be working without issue. Be advised, this deprecated status means that it could cease
' to work in future versions of Windows without notice.
' This effects dragging items, and a new Public Sub SelectedItems has been added; these are
' the only places multiselect currently effects.
'
'-Added DisableDragDrop option if you want to disable it.
```

(PS- I know the main title still says 3/15; I thought I could still edit it until May 3rd... but nope, it's stuck now  :Frown:  )

----------


## MountainMan

What happens on May 3rd?

----------


## fafalone

2 years since this thread was posted. I edited a bunch of my thread titles to figure out how long I could edit titles for, and had it narrowed down within a couple months of 2 years, so concluded it was 2 years. But it's actually a little less than that, so while I could edit the title on 3/15, I can't now, and would have to bother the admins to do it manually. Which I already did for another thread when I was first investigating this, so didn't want to ask again so soon.

----------


## fafalone

*Project Updated to v2.5 on December 9th, 2020*

Well I honestly can't recall why I never put in the options to set the background and text colors of the control, but they're present now. Also added a true RefreshTreeView option, that opens the folders that were previously open. Before, there was the ResetTreeView sub, but that only restores the root appearance that it's like on startup.





```
'v2.5 (Released 09 Dec 2020)
'
'-Added BackColor and ForeColor (text) options.
'
'-Added some missing style options: AutoHScroll, NoIndentState, TrackSelect, and
' ShowSelAlways. The latter two are enabled by default.
'
'-Added RefreshTreeView function. There already is 'ResetTreeView', but that restores the
' tree to its state on load. RefreshTreeView resets it then expands all the folders that
' were previously expanded, which will make any updates in the folders that were visible
' as they're loaded from scratch.
'
'-To perform the refresh, a list is generated of not all folders, but just one per end
' node, otherwise there'd be potentially hundreds of useless OpenToPath calls.
' This list is available if you want to view or save it through the new GetExpansionState
' function. If you want to load a saved list, also added LoadExpansionState. You can pass
' any list of full paths in a string delimited by a | if desired.
'
'-(Bug fix) If a portable device (e.g. phone, camera) was connected while the control was
'           running, it wouldn't be added to the tree.
```



Note: In the original post of Version 2.5, debug output for the Immediate window was turned on. Reposted with it turned off; no other changes. As a reminder, in ucShellTree.ctl, below the intro comments and changelog, there's the dbg_PrintToImmediate user option, switch it to False to turn off debug output without needing to re-download.

----------


## fafalone

*Project Updated to v2.5 Revision 2 (R2) on 15 Dec 2020*

This is a bug fix for the following scenario: A tree is paired with a ShellBrowse control, you open the Network root. If the servers aren't expanded, doubling clicking a server in the browser would get caught in an infinite loop and cancel the expansion, so the tree would never expand to the server you opened on its own. This may effect other special locations, and was related to IShellItem.GetDisplayName returning two difference cases (upper/lower) for the same exact location at different times. It was presumed to always load the same case, so I hadn't made the function that looks up node data by path case insensitive.

----------


## yokesee

hello good job.
I block a lot and there is a lot of lag.
also when I move the mouse wheel it has a lot of lag from loading the folders.
I do not know if it will be because I have many folders.

a greeting

----------


## fafalone

How many folders are you trying to load?

One thing to try would be in the Properties for the control, set InfoTipOnFolders (and InfoTipOnFiles if you're showing those as well). That causes a bit of lag as it looks up all that info on mouseover.

----------


## yokesee

about 100 folders will appear in the tree open the node.
change everything to false and if it works better.
It can also influence two connected external hard drives.
I don't have time to do more exact tests.
but it's a great job.

a greeting

----------


## fafalone

The only setting that should cause lag with that few items is the ExtendedOverlays option. It's only taking 90ms to load 100 folders when I time it. 

Check how it performs from the basic demo, \Demo\ShellTreeDemo.vbp in the download, then see how the performance is for that and how your settings might differ.

----------


## fafalone

*Project Updated to Version 2.6 - 03 April 2021*
Small update to address a bug in OCX builds, add Select/Click events with IShellItem references, remove the need to track a variable when combined with ucShellBrowse for directory changes (bChanging in the demos), and add a SelectNone sub to deselect.



```
'v2.6 (Released 03 Apr 2021)
'
'-Eliminated the need to use a variable to keep tracking of dir change operations when
' combining this control with a ucShellBrowse control; previously you'd handle a path
' change notification from the browser with
' If bChanging = False Then
'    bChanging = True
'    ucShellTree1.OpenToItem siItem, False
'    bChanging = False
' End If
' Now you no long need the bChanging variable.
'
'-Added SelectNone sub, which will clear all selected items (supports multiselect).
'
'-Added ItemSelectByShellItem event. I wanted to just include an IShellItem member in
' ItemSelect, but the backwards compatibility concerns are too great. This event will
' also include all the information of ItemSelect if you want to fully switch over.
'-Did the same for ItemClick->ItemClickByShellItem
'
'-For MultiSelect, added the MultiSelectChange event, which includes an IShellItemArray
' of selected items as well as a name list and full path list
'
'-(Bug fix) Using On Error Resume Next to handle an uninitialized array in the Terminate
'           event caused the control to freeze on compile or on run after changes if
'           you were using it as an OCX.
```

----------


## SMC1979

I had a problem getting the items that where checked inside vb itself without having to compile it. The .checked wasnt working unless it was complied. So I made a small change and now it works in vb and compiled.



```
Private Sub SetCheckedList()
ReDim gPaths(0)
nPaths = 0
'EnumPaths hTVD, m_hRoot
Dim i As Long
Dim fChk As Long

For i = 0 To UBound(TVEntries)
    fChk = 0
    fChk = TreeView_GetCheckState(hTVD, TVEntries(i).hNode)
    If fChk = 2 Then
        ReDim Preserve gPaths(nPaths)
        gPaths(nPaths) = TVEntries(i).sFullPath
        
        nPaths = nPaths + 1
    End If
Next i
End Sub
```

----------


## MountainMan

Fafalone,

Your last ucShellTree upload is v2.6 uploaded 3 Apr 2021. In that package is  DemoSB which I believe is a demo showing ucShellTree and ucShellBrowse working together. In Project1.vbp there is a line for the resource file as follows:



```
ResFile32="..\..\ucShellBrowse\resImagesStd.RES"
```

Unfortunately there is no such file in any of the dowloaded packages at least back to ucShellBrowse 9.3. Do you still have a copy of this file around somewhere or do you have a different .RES file we should use?

Also, the changelog.txt in ucShellBrowse hasn't been updated since version 9.4 (15 Mar 2021).

Thanks.

----------


## fafalone

You can delete that entirely. It's just the images for ucShellBrowse, which are now entirely built into the control, and I hadn't noticed the now unneeded reference in that particular demo. You can replace it with one of the current resources that come with the controls for the manifest, but there's no images or other essential data stored in resource files anymore (except to the extent a common controls 6 manifest is really kinda essential).

changelog.txt contains changelog entries that have been pruned from ucShellBrowse.ctl. Near the top of the control source, you'll find a changelog with the more recent changes. When I remove those from the .ctl, they're moved to that .txt.

----------


## fafalone

*Project Updated to Version 2.7*



```
'v2.7 (Released 25 Jan 2022)
'
'-Added ShowHiddenItems/ShowSuperHidden options
'
'-Added EnableShellMenu option to control whether the right-click menu pops up.
'
'-Added SetFocusOnTree method.
'
'-Added public event for UserControl_EnterFocus and UserControl_ExitFocus (EnterFocus
' and ExitFocus, respectively).
'
'-(Bug fix) Keyboard focus never went to ucTreeView when on a form with ucShellBrowse.
```

Also removed the dead reference in DemoSB mentioned by MountainMan above.

----------


## dmrvb

Initial feedback...

All the focus and focus events, and keyboard navigation, now work exactly as expected, thank you.
The issue with rapid keyboard navigation is fixed.

Is there a method to programmatically expand/collapse the currently selected node (folder)?

The showhidden properties work (thanks) but there are a couple of issues.....
Can the hidden folders be shown faded just like in ucShellBrowse? 
The showhidden does not take effect till I do a "RefreshTreeView" and this is slow and disruptive, it firsts show the tree from the desktop, then shows it again with some "arbitrary" folder selected. Ideally it should just redisplay the tree as close to its previous condition as is possible (if a selected folder is now hidden move up to its parent etc)

I also have a hidden folder  $AV_AVG that appears in ucTree but not in ucShellBrowse??????   maybe its superhidden and Shellbrowse is failing to show superhiddens????

----------


## dmrvb

note that mVersionStr is still set to 2.6 rather than 2.7

----------


## fafalone

Hidden and Superhidden are separate options that both default to using the Explorer value. They don't take effect on their own by design; as you note, applying options where it has to be refreshed are disruptive, so it provides the opportunity to only have to do it once after changing multiple settings.

Not really a way around refreshing it being disruptive, though you're right I should preserve the selection. I suppose it's possible to avoid a full refresh by doing a new enumeration and just inserting or deleting the hidden items... just how slow are we talking about? Recreating the tree as close to possible is, besides the selected item part, why it takes so long as is... it's repeating each expansion action. 


With the extra hidden folder... found a bug. The high performance loader in ucShellBrowse has to convert FILE_ATTRIBUTES to SFGAO_Flags, and wasn't including FILE_ATTRIBUTES_SYSTEM. But I'm not sure why it shows in ucShellTree unless you turned on ShowSuperhidden or have that turned on in Explorer... unless maybe you mean it's in the dropdown in the browser? That's not filtered. 

There's no direct way to expand the selected node, though you could get the hWnd, get the selected node, and send TVM_EXPAND. Or navigate to a child. As for collapsing... could probably get the selected item then change the item state to remove TVIS_EXPANDED.

Could make hidden items faded by applying the TVIS_CUT style... will do that for next version.

----------


## dmrvb

The refresh update only takes about a second (in the compiled EXE) but as it displays the desktop first then some other folder it is very obvious. Maybe I can preserve the selection and then reselect from user code? I will investigate.

How do I get access to the selected node? I will investigate using TVM_EXPAND.

In the current unsupported FileTree component that I am using (and need to replace) I can do
ucTree.selectednode.expanded = true.

Would it be really difficult to give a "selectednode"  ???
I have written a bit of CoreAudio code but am otherwise very new to OLEexp.

----------


## fafalone

There's a property hWndTreeView that returns the TV's hWnd, so you can use any TreeView API on it, including TVM_GETNEXTITEM with TVGN_CARET which gets the (first) selected node.

Preserving the selected item with user code would be as simple as saving ucShellTree.SelectedItem then using ucShellTree.OpenToPath, which has an option to select it too. 

But I'll be adding some code with basic operations for the selected node and automatically preserving selection over the next couple days. They're simple enough if you want to copy them in now, I'll need some time to run down bugs and add some other stuff before updating the download:



```
Public Sub SelectedNodeExpand()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_EXPAND, ByVal hNode)
End If
End Sub
Public Sub SelectedNodeCollapse()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_COLLAPSE, ByVal hNode)
End If
End Sub
Public Sub SelectedNodeToggle()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_TOGGLE, ByVal hNode)
End If
End Sub

Public Sub SelectedNodesExpand()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_EXPAND, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
Public Sub SelectedNodesCollapse()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_COLLAPSE, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
Public Sub SelectedNodesToggle()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_TOGGLE, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
Public Sub CheckedItemsExpand()
Dim i As Long
For i = 0 To UBound(TVEntries)
    If (TVEntries(i).Checked = True) And (TVEntries(i).bDeleted = False) Then
        SendMessage hTVD, TVM_EXPAND, TVE_EXPAND, ByVal TVEntries(i).hNode
    End If
Next i
End Sub
Public Sub CheckedItemsCollapse()
Dim i As Long
For i = 0 To UBound(TVEntries)
    If (TVEntries(i).Checked = True) And (TVEntries(i).bDeleted = False) Then
        SendMessage hTVD, TVM_EXPAND, TVE_COLLAPSE, ByVal TVEntries(i).hNode
    End If
Next i
End Sub
Public Sub CheckedItemsToggle()
Dim i As Long
For i = 0 To UBound(TVEntries)
    If (TVEntries(i).Checked = True) And (TVEntries(i).bDeleted = False) Then
        SendMessage hTVD, TVM_EXPAND, TVE_TOGGLE, ByVal TVEntries(i).hNode
    End If
Next i
End Sub
```

(SelectedNodes____ is for if MultiSelect is enabled)

As for preserving selection I didn't test it yet but modifying RefreshTreeView like this should work:


```
Public Sub RefreshTreeView()
'Resets to the root then expands all the previous locations
'The lengthy code involves minimizing the OpenToPath calls by calculating
'smallest group of folders that will give us the same setup. E.g.:
'C:\a\b\(c,d,e,f) will call only C:\a\b\c, and not d,e,f or C:\a or b, because
'expanding to c will give us a b d e and f too
Dim i As Long
Dim sData() As String

If CalcRefreshData(sData) Then
    ResetTreeView
    
    For i = 0 To UBound(sData)
        OpenToPath sData(i), False
    Next i
End If
OpenToPath sSelectedItem, False, True
Exit Sub
e0:
    DebugAppend "PruneParentsFromRPL.Error->" & Err.Description & "(0x" & Hex$(Err.Number) & ")"

End Sub
```

----------


## dmrvb

A small cosmetic issue....
On my win10 PC:
in ShellBrowse the highlight bar (currently selected item) is quite a dark blue with white text, which is good.
In ShellTree its also blue but the text remains black which is less easy read, can it be white?

----------


## fafalone

That's the default behavior of the controls, not something I've set. But, I can give ucShellTree a CustomColor event like ucShellBrowse and start providing the item state values to them. I don't want to override the defaults but can provide customization.

It also appears to be an issue only present without ComCtl6. With them, it stays black but the lighter blue makes it easier to read. Really advisable to manifest the IDE and your apps.

----------


## dmrvb

I am pretty sure that I am including the manifest, but I will check and confirm.

----------


## fafalone

Press Ctrl+Shift+P in the ucShellBrowse listview, that shows an About box that includes whether ComCtl6 is enabled.

----------


## dmrvb

That About Box is a really useful feature, thanks.
I am using the CC6 manifest (and use it in almost all of the software that I write) but did compile my test program without it to try to find a bug, and also out of curiosity/self education.
usShellBrowse and Tree both work well for me without the manifest. The only things I have observed are:
Different Icons (which I quite like)
Different Font (I don't really understand this, is it a DPI related thing?)
The order of items in This PC are different and not as good (in ucShellBrowse)
The command buttons don't get the satisfying blue highlight on mousemove.
However I suspect there are some things that go badly wrong.

----------


## dmrvb

Concerning expanding and collapsing the treeView nodes programmatically...
Sending the TVM_Expand message works very well and its really easy to get the handle of the currently selected node by just monitoring hitem in ShellTree.ItemSelect.
But it will still be good to have this functionality built in.
Thanks.

----------


## dmrvb

Oops, apologies, I was over confident with my quick testing.
It is only possible to expand a node with a message if that node has been previously expanded by a proper click on its expando. I assume that you build the tree on demand so only you can expand it?, interacting directly with the tree using messages will not get any file system detail????

----------


## fafalone

It should... it expands the folder in response to a TVN_ITEMEXPANDING notification; I'd think the API would send that? Are you changing the item state or using TVM_EXPAND? MSDN says it raises the message for the latter, but I'm not clear if the former would.

It also notes that if you expanded it once, a subsequent message wouldn't send the notification again... so if you tried to expand it, then list files copied after that into that folder, it wouldn't attempt to load them unless you cleared the TVIS_EXPANDEDONCE flag on the item:




> When an item is first expanded by a TVM_EXPAND message, the action generates TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification codes and the item's TVIS_EXPANDEDONCE state flag is set. As long as this state flag remains set, subsequent TVM_EXPAND messages do not generate TVN_ITEMEXPANDING or TVN_ITEMEXPANDED notifications. To reset the TVIS_EXPANDEDONCE state flag, you must send a TVM_EXPAND message with the TVE_COLLAPSE and TVE_COLLAPSERESET flags set. Attempting to explicitly set TVIS_EXPANDEDONCE will result in unpredictable behavior.


Is it generating an ItemExpand event? Also, what's the return code? The control does reject that message under some circumstances; I had put a flag to work around a certain bug, but hadn't considered the case of manipulating it externally through API. If TVM_EXPAND is returning 1, that's the problem.

----------


## dmrvb

I'm doing this with sendmessage:

h = ucTree.hWndTreeView
response = SendMessage(h, TVM_EXPAND, TVE_EXPAND, ByVal hNode)
where hnode is a copy of the most recent hitem.

It returns 0 and nothing happens, but once I have expanded the node by a click on the expando (which fires itemexpand) then it works and returns 1, but still does Not fire itemexpand.

Is it possible to do API calls to the TreeView?, I can't find anything about it on the www. I half remember doing some API calls to a TreeView many years ago and getting big problems.

----------


## fafalone

What do you mean? SendMessage is sending API calls to the TreeView. It's not a VB TreeView, it's a pure API one created with CreateWindowEx. Everything inside the control is done via listening for and sending API messages.

In fact if you look at the TVNavigate routine that expands out to an item, you'll see it's using TVM_EXPAND messages.

I'm not sure why it's ignoring that message, I'll look into it tonight.

----------


## dmrvb

Sorry, my bad terminology I think.
Sendmessage is an API call but its a sort of generic one that can send messages to any window.
I thought it might be also possible to make calls to the TreeView DLL directly (I assume TreeView is a DLL somewhere?), but maybe I am wrong as can't find any info on this.
Note that I try to use VB as a high level language and although I have had to do a lot of API things I really am not expert at this.

----------


## fafalone

It's in Comctl32.dll but that I'm not sure what could be gained. 

There's no problem expanding the node for me, both with the function I'm adding and using SendMessage .hWndTreeView and the hItem from ItemSelect from the host form. Do you have Multiselect = True? In that scenario, the TVN_SELCHANGED message isn't raised by a click, so the correct hItem wouldn't be set if you're getting them from watching ItemSelect. You'd want to look at the ItemClick event in that case probably. Also checking an item wouldn't raise that message either.

You could ask it for the selected node yourself too,
hNodeSelected = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)


Here's the node functions I'm planning for the next version:


```
Public Sub SelectedNodeExpand()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_EXPAND, ByVal hNode)
End If
End Sub
Public Sub SelectedNodeCollapse()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_COLLAPSE, ByVal hNode)
End If
End Sub
Public Sub SelectedNodeToggle()
Dim hNode As Long
hNode = SendMessage(hTVD, TVM_GETNEXTITEM, TVGN_CARET, ByVal 0&)
If hNode Then
    Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_TOGGLE, ByVal hNode)
End If
End Sub

Public Sub SelectedNodesExpand()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_EXPAND, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
Public Sub SelectedNodesCollapse()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_COLLAPSE, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
Public Sub SelectedNodesToggle()
Dim hItemSel As Long
Do
    hItemSel = SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, ByVal hItemSel)
    If hItemSel Then
        Call SendMessage(hTVD, TVM_EXPAND, ByVal TVE_TOGGLE, ByVal hItemSel)
    End If
Loop While hItemSel
End Sub
```

----------


## dmrvb

Its very odd.
I do not have Multiselect enabled.

I have just put my SendMessage test button and code into your ShellTreeDemo and it works ok there, so it must be a property or something in my test app that is the issue. I will investigate. I am a bit busy tomorrow so it might take an extra day to do this.

----------


## dmrvb

Sorted, sort of.
I had SingleClickExpand set True and this is the cause of my problem.
This was my mistake as I did not read your property description and so misunderstood what this property does.
However it does not appear to do what it says...I can still expand multiple parts of the tree even when it is set to true???

----------


## fafalone

Ok, I found the issue. 

SingleClickExpand is False by default, which it triggering code that blocks the expand. (Please turn on dbg_PrintToImmediate, it logs exactly what happened  :Smilie:  I don't have the print to file functionality to log in the exe in it though... will add next version.)

The whole functionality around that setting is a mystery I can't recall... since it doesn't expand in a single click if that setting is True anyway. But it's obviously a bug fix code that was stopping unwanted expansions. So I don't recall what was happening, will have to look into it. For now, since SingleClickExpand doesn't do anything (at least with a manifest, didn't check without cc6), it's ok to turn it on. (Or does it? Didn't check Win7 maybe that's it.)

----------


## dmrvb

ok, away now, should be able to find some time late tomorrow.
We are putting a lot of nitty gritty test detail into this thread, is that ok? or should we do this detail by email and only post the conclusions?

----------


## dmrvb

I was going too fast yesterday and trying to do several things at once (and failing).
As you say SingleClickExpand needs to be True (not False)  for the SendMessage to work, and it does not do anything else and does not implement a  single click expand which might well be an undesirable feature, so all is well.
Also I had confused this with SingleExpand which allows only one node to be expanded, but this also appears not to work and is probably also not a useful feature so not worth investigating???
Maybe these were both options that Microsoft thought about implementing then decided best not to?????

----------


## fafalone

Oh weird... 

If I turn on SingleExpand, SingleClickExpand works when enabled, and then SingleExpand works as advertised; clicking on an item in same level expands that one and collapses the other. But only if you click the item name, using the expando buttons will open multiple. All that code I have in item click and expand revolving around this no doubt relates to this somehow... I'm really going to have to do a review of how these options behave and interact with/without ComCtl6 and Win7 vs Win10. 

But for now be advised I was incorrect; if both of those options are True, it will change the behavior and do as the option names indicate.


It's fine to keep posting in the thread if you want to; others could be encountering similar issues, or related issues in the future where some of the info posted is helpful. Like knowing they're not going crazy when those two options don't work one at a time, but do together.

----------


## dmrvb

You know much more than me, but I suspect that there are many weird, random and undocumented behaviours is these parts of Windows.
Maybe this is why LogicNP withdrew from this business? though I suspect issues with Win10 updates breaking their software was also an issue.
I think you are now the only one with viable ShellBrowsing components for COM (plus maybe Exontrol but theirs have a lot of limitations).
Maybe just need to concentrate on the core functionality for now and note that some of the more obscure features are "not currently supported"??. This is what Microsoft themselves do??

----------


## dmrvb

Is it easy/viable to display Win10 style "Quicklinks" in the ucTree?

How can I set the initialpath to "ThisPC" ?

How can I set the Browserpath in ShellBrowse (and hence the linked ucTree) to either ThisPC or Desktop?

In my file dialogs I try to set the path to that used in the most recent load/save operation and persist this, but need to default to either Desktop or ThisPC if that path is no longer valid.
The LogicNP controls have a "ResettoDesktop" method, but defaulting to ThisPC might be a nicer option.

----------


## fafalone

As the initial path or as the root?

There's an option ComputerAsRoot to make it the root (same on ucShellBrowse for the dropdown).

For other places you enter a path, or to do this manually, and for other special locations without normal paths, it's done by using the GUID that identifies it.

ThisPC is ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}. If you Google that, you'll find it on lists with other locations.

Since it's asking the Windows shell, you can use whatever the shell accepts... enter the above in the Run... command or the Explorer address bar, and you'll find you're also taken to This PC.


--
I'm inclined to leave all options available, since you never know what OS it's being used on... a lot of people run 7 still (and honestly I'm fed up with 10 to the point I'm going to sell my brand new hardware if my next attempt to make 7 boot on it fails too). But I have been adding options that restrict things from being available during if the user wants... like that Content view on ucShellBrowse is a mess, I thought I had it off by default but I guess I left it on. So I had a UserOption flag, then eventually added a Property where any view could be restricted. I will try to make sure the default settings are stable across all Windows versions.

----------


## dmrvb

Thanks
Just after posting above I had a try at browsing to the "ThisPC" GUID and it works fine.

I'm committed to Windows10 (and I suppose soon 11). I held out with both 98 (my favourite) and XP for a long time but have now accepted that its just too difficult fighting against Microsoft. I like a lot of Win10, my only big concern is the frequent automatic updates and the real possibility that one will break my software which is all in VB6. One update did break things but it was the LogicNP shellbrowser that was to blame, and that's written in C++.
This is partly why I am keen to use your Shell Browser, the source code is available so if an update does break it then there is at least a chance that it might get fixed, even if you don't want to do it yourself.

----------


## fafalone

There's now a Beta release of a 64bit-compatible version of this control for twinBASIC. Requires tB Beta 207 or newer.

More info, download, and browse source on GitHub.

ucShellBrowse will take a bit longer, it's much more complex and impacted severely enough by current limitations of tB UserControl support that it doesn't run properly yet. Hopefully soon  :Smilie:

----------

