Results 1 to 22 of 22

Thread: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    IExplorerBrowser

    IExplorerBrowser is an easy to use, more complete version of IShellView (in fact, it has an IShellView at its core that you can access) that lets you have a complete Explorer frame on your form, with very little code. You can either have just a plain file view, or with a navigation tree and toolbar. It uses all the same settings and does all the same things as Explorer, and your program can interact with those actions to do things like browse for files, or be the basis of a namespace extension.
    The only complication is that there's no event notifying of an individual file selection within the view, and getting a list of selected files is fairly complex- however there is a function to do it in the demo project.
    Here's how it looks if you're just using folder view without the frames:


    INamespaceTreeControl

    If all you want is the navigation tree, you have the INamespaceTreeControl. It's got a decent amount of options for however you want to display things, including checkboxes. There is a wide range of events that you're notified of via the event sink, and most of these use IShellItem- the demo project does show to to convert that into a path, but it's a very useful interface to learn if you're going to be doing shell programming. The selection is reported through IShellItemArray, which is slightly easier than IDataObject.
    It's got one little quirk though... you have the option to set the folder icons yourself, but if you don't want to do that and just use the default icon that you see in Explorer, you have to return -1, which requires a v-table swap. The demo project shows how to go both ways, no thanks to MSDN and their complete lack of documentation of this.
    But this is by far the easiest to create way of having a full-featured Explorer-like navigation- I've made a regular TreeView into this, and it took hundreds of lines and heavy subclassing. This is a simple object. (Note that it does support some advanced features through related interfaces, like custom draw, drop handling, and accessibility... these interfaces are included in oleexp, but have not been brought to the sample project here, perhaps in the future I'll do a more in-depth one if there's any interest)

    Requirements
    Windows Vista or higher required as these interfaces did not exist in earlier OS versions
    oleexp.tlb: Modern Interfaces Type Library v4.0 or higher (17 Jun 2015) - Only required in the IDE.
    mIID.bas - oleexp add-on module, included in the oleexp download

    These 'controls' create themselves- all you need is a blank form, and here's the creation code for a basic idea of how these things work (code to initialize some variables omitted):
    Code:
    Set pNST = New NamespaceTreeControl
    pNST.Initialize Me.hWnd, prc, lFlag
    Set pAdv = New cNSTEvents
    Set pUnkAdv = pAdv
    pNST.TreeAdvise pUnkAdv, lpck
    pNST.InsertRoot 0, isiDesk, SHCONTF_FOLDERS, NSTCRS_EXPANDED Or NSTCRS_VISIBLE, pif


    UPDATE: Enumerating selection in virtual location for IExplorerBrowser.
    So I was showing how this demo can be used to browse FTP sites and realized the IDataObject/DragQueryFile method of obtaining the selection fails in virtual folders that don't have local paths. This is an alternative method that will get their IShellItems, display names, and (if applicable and including network) paths, so that you can further interact with them (for instance, to copy to/from FTP, you can pass the IShellItems to IFileOperation even if there's no valid path):
    Code:
    'frmBasic
    
    Private Sub Command1_Click()
    Dim hr As Long
    Dim sOut As String
    Dim pIDO As oleexp.IDataObject
    Dim psv As IShellView
    Dim fmt As FORMATETC
    Dim stg As STGMEDIUM
    Dim hDrop As Long
    Dim uNumFiles As Long
    Dim i As Long
    Dim Filename As String
    
    pEBrowse.GetCurrentView IID_IShellView, psv
    If (psv Is Nothing) Then
        Debug.Print "Failed to created IShellView"
        Exit Sub
    End If
    
    Dim psia As IShellItemArray
    Dim penm As IEnumShellItems
    Dim lpName As Long
    Dim psiChild As IShellItem
    
    psv.GetItemObject SVGIO_SELECTION, IID_IShellItemArray, psia
    If (psia Is Nothing) = False Then
        psia.EnumItems penm
        If (penm Is Nothing) = False Then
            Do While (penm.Next(1&, psiChild, i) = NOERROR)
                psiChild.GetDisplayName SIGDN_NORMALDISPLAY, lpName
                Filename = BStrFromLPWStr(lpName)
                sOut = sOut & "Display: " & Filename
                psiChild.GetDisplayName SIGDN_DESKTOPABSOLUTEPARSING, lpName
                Filename = BStrFromLPWStr(lpName)
                sOut = sOut & " | AbsParse=" & Filename & vbCrLf
            Loop
        Else
            Debug.Print "Failed to enumerate selection."
        End If
    Else
        Debug.Print "Failed to get selection array."
    End If
    
    'old way that only works on non-virtual locations:        
    'psv.GetItemObject SVGIO_SELECTION, IID_IDataObject, pIDO
    'If (pIDO Is Nothing) Then
    '    Debug.Print "Failed to create IDataObject"
    '    Exit Sub
    'End If
    '
    '
    'fmt.cfFormat = CF_HDROP
    'fmt.dwAspect = DVASPECT_CONTENT
    'fmt.lindex = -1
    'fmt.TYMED = TYMED_HGLOBAL
    'stg.TYMED = TYMED_HGLOBAL
    '
    'hr = pIDO.GetData(fmt, stg)
    'Debug.Print "GetData hr=" & hr
    '
    'hDrop = GlobalLock(stg.Data)
    '
    'uNumFiles = DragQueryFile(hDrop, &HFFFFFFFF, "", 0)
    'Debug.Print "got nfiles=" & uNumFiles
    'For i = 0 To (uNumFiles - 1)
    '    Filename = String$(260, 0)
    '    Call DragQueryFile(hDrop, i, Filename, Len(Filename))
    '    If (InStr(Filename, vbNullChar)) > 1 Then
    '        Filename = Left$(Filename, InStr(Filename, vbNullChar) - 1)
    '        Debug.Print "filename=" & Filename
    '        sOut = sOut & Filename & ", "
    '    End If
    'Next i
    'Call GlobalUnlock(stg.Data)
    'ReleaseStgMedium VarPtr(stg)
    Debug.Print "output=" & sOut
    Text1.Text = sOut
    End Sub
    It's basically the same way it's done on the INamespaceTreeControl form, only difference being that you still need to go through IShellView.

    UPDATE: Showing a Custom List of Files

    (8/2018) This project allows you to browse to any particular location on the system, but what if you want to do something like display a Search Results folder, or some other view where all the files reside in different locations? There's an interface that allows you to easily do just that. See the new project:
    [VB6] Display search results or other custom file set in IExplorerBrowser
    Attached Files Attached Files
    Last edited by fafalone; Aug 24th, 2018 at 12:10 AM. Reason: New related project details added

  2. #2

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Here's what the most complicated part for both, selecting items, looks like:

    INamespaceTreeControl
    Code:
    Dim pisia As IShellItemArray
    Dim lpName As Long, sName As String
    Dim iesi As IEnumShellItems
    Dim psi As IShellItem
    pNST.GetSelectedItems pisia
    pisia.EnumItems iesi
    
    Do While (iesi.Next(1, psi, 0) = NOERROR)
    
        psi.GetDisplayName SIGDN_FILESYSPATH, lpName
        sName = sName & BStrFromLPWStr(lpName) & ", "
        Set psi = Nothing
    Loop
    
    Debug.Print "SelectedItems=" & sName
    Text1.Text = sName
    Set iesi = Nothing
    IExplorerBrowser
    Code:
    Dim hr As Long
    Dim sOut As String
    Dim pIDO As oleexp.IDataObject
    Dim psv As IShellView
    Dim fmt As FORMATETC
    Dim stg As STGMEDIUM
    Dim hDrop As Long
    Dim uNumFiles As Long
    Dim i As Long
    Dim Filename As String
    
    pEBrowse.GetCurrentView IID_IShellView, psv
    If (psv Is Nothing) Then
        Debug.Print "Failed to created IShellView"
        Exit Sub
    End If
    
    psv.GetItemObject SVGIO_SELECTION, IID_IDataObject, pIDO
    If (pIDO Is Nothing) Then
        Debug.Print "Failed to create IDataObject"
        Exit Sub
    End If
    
    
    fmt.cfFormat = CF_HDROP
    fmt.dwAspect = DVASPECT_CONTENT
    fmt.lindex = -1
    fmt.TYMED = TYMED_HGLOBAL
    stg.TYMED = TYMED_HGLOBAL
    
    hr = pIDO.GetData(fmt, stg)
    Debug.Print "GetData hr=" & hr
    
    hDrop = GlobalLock(stg.Data)
    
    uNumFiles = DragQueryFile(hDrop, &HFFFFFFFF, "", 0)
    Debug.Print "got nfiles=" & uNumFiles
    For i = 0 To (uNumFiles - 1)
        Filename = String$(260, 0)
        Call DragQueryFile(hDrop, i, Filename, Len(Filename))
        If (InStr(Filename, vbNullChar)) > 1 Then
            Filename = Left$(Filename, InStr(Filename, vbNullChar) - 1)
            Debug.Print "filename=" & Filename
            sOut = sOut & Filename & ", "
        End If
    Next i
    Debug.Print "output=" & sOut
    Text1.Text = sOut
    Call GlobalUnlock(stg.Data)
    ReleaseStgMedium VarPtr(stg)
    Last edited by fafalone; Nov 24th, 2016 at 05:52 PM.

  3. #3
    Lively Member
    Join Date
    Aug 2008
    Location
    Denmark
    Posts
    85

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    I was trying this example with oleexp3.tlb but could not get the INameSpaceTreeControlEvents to work.

    Got the following message:
    ---------------------------
    Microsoft Visual Basic
    ---------------------------
    Compile error:

    Bad interface for Implements: method uses type that is not supported by Visual Basic
    ---------------------------
    OK Help
    ---------------------------

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    The good news is that error was caused by explicitly having "olelib.IUnknown", which was easily fixed so that error won't happen again.

    The bad news is that the OnBefore/AfterContextMenu function where that was located causes an app crash, and I went back and tested it with the version at the time this was released and it was present there too and I missed it. For reasons I can't even begin to comprehend, it's telling me that "oleexp3.IUnknown" is an unknown type, when it clearly isn't as that interface it forward defined AND appears before the oleexp interfaces, but I don't know that that would correct it either. I'm truly at a loss to explain whats causing the crash right now. It's really supposed to be "As Any" but VB doesn't allow that in functions.

    Note: If you do use it the context menu events have their last parameter as IContextMenu3; I'm not going to update the sample project just yet while I look for a solution to the crashing.
    Last edited by fafalone; Aug 13th, 2015 at 11:54 PM.

  5. #5
    Addicted Member
    Join Date
    May 2016
    Location
    China
    Posts
    197

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    NamespaceTree Basic why can not use the right mouse button pop-up function? When you press the right mouse button will collapse.

  6. #6
    Addicted Member
    Join Date
    May 2016
    Location
    China
    Posts
    197

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Is there any way to solve this problem?

  7. #7
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    As Any (void *) needs to be ByVal Long (long) to be implementable in VB6

  8. #8

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Sometimes it does, sometimes it doesn't. Should probably verify the crash on other systems anyway since I've noticed I get the right-click crash on any app that hosts this object, not just mine, and not just VB apps. It's a pain because to make a new folder I have to go back into Explorer instead of whatever app I'm saving a file in.

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    The issue with right-click crash was finally resolved today; like I said I wasn't sure if anyone else had the problem but if you did, it's caused by a bad context menu shell extension; in my systems case SimpleExt.dll. After disabling that using nirsoft's ShellExView, no more right-click crash in this app or any others.

    Only oddity now is that OnAfterContextMenu must be swapped out and return E_NOTIMPL. If it returns 0, theres a crash. If it's not swapped and Err.Raise E_NOTIMPL is used, there's no crash but the context menu never appears.
    -----------------------

    But the most pressing issue is how do I get that void* ppv ? The riid confirms that it's an IContextMenu object, but the current ppv As IContextMenu doesn't work (==Nothing), so I changed it to ByVal ppv As Long, and it's a non-zero number, but treating it like I've treated every other such pointer, vbaObjSetAddRef IContextMenu, ppv -this results in an app crash.

  10. #10
    Hyperactive Member Mith's Avatar
    Join Date
    Jul 2017
    Location
    Thailand
    Posts
    445

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Does anyone found a solution to get the Events (mouse, keys...) for the items inside the IExplorerBrowser windows?

  11. #11

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    What exactly are you trying to do?

    You could subclass the hWnd and get those events like you would for any other hwnd, but there's probably a better route to whatever end result you're looking for.

  12. #12
    gibra
    Guest

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    When load the project I get a error, because the module mIID.bas is missing (are requeste on the VBP file):

    Code:
    Module=mIID; ..\tl_ole\mIID.bas

  13. #13

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    mIID.bas is included in the main oleexp zip file with the tlb. It can't be referenced by GUID so that leaves hard paths; but it's a common file (it holds all IID_x, FOLDERID_x, SID_x, BHID_x, and some GUID functions, saving a ton of time and code by not having to add on a per-project basis and convert from string to guid) so I don't include it with every project, so that one instance can be easily upgraded.
    Sorry I should have noted that in the Requirements section; it has been updated.
    Last edited by fafalone; Jul 28th, 2017 at 05:39 PM.

  14. #14
    Hyperactive Member
    Join Date
    Feb 2015
    Location
    Colorado USA
    Posts
    261

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    I am having a problem just compiling your sample. I have v4.5 of oleexpl.tlb in SysWOW64 and I am using the latest version (15) of mIID.bas.

    When I compile, I get the error "Procedure declaratino does not match descrition of event or procedure having the same name" and line 121 in the class module cNSTEvents is highlighted:

    Code:
    Public Sub INameSpaceTreeControlEvents_OnBeforeContextMenu(ByVal psi As IShellItem, riid As UUID, ppv As IContextMenu
    Any idea what is going on? All I did was load the .vbp fie and when it couldn't find mIID.bas I told it to continue loading and then I inserted mIID.bas myself. Other than that I haven't done anything except to try to compile.

    MountainMan

  15. #15

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Per post #9 I had to change the last argument to a long; just change it to ByVal ppv As Long. OnAfterContextMenu will need the same change. Sorry for not updating the demo; I was just planning on updating this sample anyway since I figured out how to load custom file sets from anywhere on the system.
    Last edited by fafalone; Aug 11th, 2018 at 02:10 AM.

  16. #16

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    So 8 years later I've finally found the cause and solution to the right-click crash in the tree.

    The arguments in the context menu events are for supplying your own IContextMenu instead of the system one, and the system relies on the HRESULT to determine if you've done that-- it doesn't validate that the pointer is non-zero. So if you don't return E_NOTIMPL, and don't supply an IContextMenu, it crashes trying to access a null pointer.

    Err.Raise E_NOTIMPL in both should fix it; if not, a v-table swap to return it.

  17. #17
    Lively Member
    Join Date
    Oct 2008
    Posts
    123

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Hi Fafalone
    Sorry,
    Err.Raise E_NOTIMPL in both should fix it; if not, a v-table swap to return it.
    but I didn't understand how to solve the right-click crash in the tree.

  18. #18

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    For VB6:

    In a standard module (.bas), add:

    Code:
    Public Function NSTCE_OnBeforeContextMenu(ByVal this As INameSpaceTreeControlEvents, ByVal psi As oleexp.IShellItem, riid As oleexp.UUID, ppv As Long) As Long
    Dim lpsz As Long
    psi.GetDisplayName SIGDN_FILESYSPATH, lpsz
    frmNST.List1.AddItem "OnBeforeContextMenu " & BStrFromLPWStr(lpsz), 0
    NSTCE_OnBeforeContextMenu = E_NOTIMPL
    End Function
    Public Function NSTCE_OnAfterContextMenu(ByVal this As INameSpaceTreeControlEvents, ByVal psi As oleexp.IShellItem, ByVal pcmIn As oleexp.IContextMenu, riid As oleexp.UUID, ppv As Long) As Long
    Dim lpsz As Long
    psi.GetDisplayName SIGDN_FILESYSPATH, lpsz
    frmNST.List1.AddItem "OnAfterContextMenu " & BStrFromLPWStr(lpsz), 0
    NSTCE_OnAfterContextMenu = E_NOTIMPL
    End Function
    In cNSTEvents.cls, add to module level:

    Code:
    Private m_pOldBCM As Long
    Private m_pOldACM As Long
    To Class_Initialize, add

    Code:
    m_pOldBCM = SwapVtableEntry(ObjPtr(pVTable), 18, AddressOf NSTCE_OnBeforeContextMenu)
    m_pOldACM = SwapVtableEntry(ObjPtr(pVTable), 19, AddressOf NSTCE_OnAfterContextMenu)
    and to Class_Terminate, add:

    Code:
    m_pOldBCM = SwapVtableEntry(ObjPtr(pVTable), 18, m_pOldBCM)
    m_pOldACM = SwapVtableEntry(ObjPtr(pVTable), 19, m_pOldACM)

    For twinBASIC:

    Add Err.ReturnHResult = E_NOTIMPL to INameSpaceTreeControlEvents_OnAfterContextMenu and INameSpaceTreeControlEvents_OnAfterContextMenu in cNSTEvents.cls.

  19. #19
    Lively Member
    Join Date
    Oct 2008
    Posts
    123

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Hi Fafalone,thanks for reply.
    I ran the compiled version after inserting your changes and it worked.
    Why does everything freeze when launched in the IDE after right-click in the navigation tree?

    Thanks

  20. #20

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Not sure... it doesn't for me. I only tested that code in the IDE. Which version of Windows? I'm on 10.

    I'll attach the test version I made, it's the one attached to this post with only the mentioned changes applied.
    Attached Files Attached Files

  21. #21
    Lively Member
    Join Date
    Oct 2008
    Posts
    123

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    Hi Fafalone
    you test version works in IDE.
    I checked the differences between your Test version and the modified ExplorerBrowser_Rev2 version.
    In the cNSTEvents class,were missing the line of code Err.Raise E_NOTIMPL in the subs INameSpaceTreeControlEvents_OnBeforeContextMenu and in INameSpaceTreeControlEvents_OnAfterContextMenu

    Thanks
    Problem Solved

  22. #22

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,625

    Re: [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder

    ?? the sample project redirects those functions; they never run.

    In the original project, you can use Err.Raise E_NOTIMPL instead, that will stop the crashing-- however, the default context menu won't appear. You need to use the redirects in the updated version I posted if you want the normal right-click menu to pop up like in Explorer.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width