Results 1 to 1 of 1

Thread: [VB6] Exclude file types from Open/Save Dialogs ('all except...'): IShellItemFilter

Threaded View

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,654

    [VB6] Exclude file types from Open/Save Dialogs ('all except...'): IShellItemFilter


    IShellItemFilter Demo

    Normally with an Open/Save dialog, you supply filters of a list of file types you want to display. But what if instead of 'only x', you wanted to filter by 'all except x' or similar, excluding only a specific file type? Or even show all files of a particular type, except those that met some other criteria (like created before a certain date)? It's entirely possible to get this level of control using a backend filter supported on the newer IFileDialog, the .SetFilter method with the IShellItemFilter class.

    This is a followup to an earlier project that used a similar principle on the SHBrowseForFolder dialog: [VB6] SHBrowseForFolder - Custom filter for shown items: BFFM_IUNKNOWN/IFolderFilter

    You can do this on Open/Save (and the new folder picker too) also, using a different but similar interface: IShellItemFilter.

    IFileDialog includes a .SetFilter method, this project shows how to create the class for it. It uses a return so has to be swapped out, so the class itself is small:
    Code:
    Option Explicit
    
    Implements IShellItemFilter
    Private mOld4 As Long
    
    Private Sub Class_Initialize()
    Dim pVtable As IShellItemFilter
    Set pVtable = Me
    mOld4 = SwapVtableEntry(ObjPtr(pVtable), 4, AddressOf IncludeItemVB)
    
    End Sub
    
    Private Sub Class_Terminate()
    Dim pVtable As IShellItemFilter
    Set pVtable = Me
    mOld4 = SwapVtableEntry(ObjPtr(pVtable), 4, mOld4)
    
    End Sub
    
    Private Sub IShellItemFilter_IncludeItem(ByVal psi As IShellItem)
    End Sub
    Private Sub IShellItemFilter_GetEnumFlagsForItem(ByVal psi As IShellItem, pgrfFlags As SHCONTF)
    End Sub
    The IncludeItem function is what we're interested in. Each item to be displayed is passed to this first by a pointer to its IShellItem, so you can easily decide to exclude/include it based on any criteria you want. In this demo, we exclude if it matches the filter on the form's textbox, but the options are limitless. Note that unlike normal filters, this cannot be overridden by the user typing in their own filter; items hidden by the IncludeItem function will always be hidden. They can still be selected by manually entering their name†, but will never be shown in the list.
    Code:
    Public Function IncludeItemVB(ByVal this As IShellItemFilter, ByVal psi As IShellItem) As Long
    Dim lpName As Long, sName As String
    Dim dwAtr As Long
    
    If (psi Is Nothing) = False Then
        psi.GetAttributes SFGAO_FILESYSTEM Or SFGAO_FOLDER, dwAtr
        If ((dwAtr And SFGAO_FILESYSTEM) = SFGAO_FILESYSTEM) And ((dwAtr And SFGAO_FOLDER) = 0) Then 'is in normal file system, is not a folder
            psi.GetDisplayName SIGDN_PARENTRELATIVEPARSING, lpName
            sName = LPWSTRtoStr(lpName)
    '        Debug.Print "IShellItemFilter_IncludeItem?" & sName & "|" & gSpec
            If PathMatchSpecW(StrPtr(sName), StrPtr(gSpec)) Then
                IncludeItemVB = S_FALSE 'should not show
            Else
                IncludeItemVB = S_OK 'should show
            End If
        End If
    Else
        Debug.Print "IncludeItemVB.NoItem"
    End If
    End Function
    Think of the other possibilities here... instead of the file name, you could exclude by attribute, or by date, or anything you want.

    Also note that this overrides the normal 'include' filters that you're used to using, like if instead of all files *.* you had *.exe, then set the exclude filter to *a*.exe, the dialog would show all .exe files except for ones with an 'a' in their name.

    Adding the filter to a normal Open call is simple:
    Code:
    Dim fod As New FileOpenDialog
    Set cSIFilter = New cShellItemFilter 'declared as a Public in the module
    Dim psi As IShellItem
    Dim tFilt() As COMDLG_FILTERSPEC
    ReDim tFilt(0)
    tFilt(0).pszName = "All Files"
    tFilt(0).pszSpec = "*.*"
    With fod
        .SetFileTypes UBound(tFilt) + 1, VarPtr(tFilt(0))
        .SetTitle "Browse away"
        .SetOptions FOS_DONTADDTORECENT
        .SetFilter cSIFilter
        .Show Me.hWnd
        .GetResult psi
        If (psi Is Nothing) = False Then
            Dim lp As Long, sRes As String
            psi.GetDisplayName SIGDN_FILESYSPATH, lp
            Label2.Caption = LPWSTRtoStr(lp)
        End If
    End With
    And that's all there is to it. You can use the .SetFilter method whether it's an Open dialog or Save dialog.

    Requirements
    -Windows Vista or newer (the new dialogs weren't available in XP)
    -oleexp v4.0 or newer (only for the IDE, not needed for compiled exe)


    † - If you wanted to refuse to let the user select an excluded file, even manually, you could also do that without closing the dialog by using an events class, and not allowing the dialog to close on the OnFileOk event. See the original IFileDialog project which implements the event sink.



    twinBASIC 64bit compatible version at https://github.com/fafalone/MiscDemos
    Attached Files Attached Files
    Last edited by fafalone; Feb 28th, 2026 at 02:37 PM.

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