Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1529

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

$
0
0

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.
Attached Files

Viewing all articles
Browse latest Browse all 1529

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>