LaVolpe put out an excellent class module that implements these interfaces, but I've been working on using them through a different approach for some time and wanted to post it as well since, while requiring a TLB, it offers advantages like having IShellItem as a declarable type used all over projects, interfaces, and APIs.
IFileSaveDialog and IFileOpenDialog were introduced in Windows Vista to supersede the GetOpenFileName/GetSaveFileName API, and offer several advantages (although certainly some drawbacks). Windows provides a default implementation, so they're fairly easy to use in VB. Among the advantages is easy addition of custom controls, something that was not previously possible in VB (or at least so hard no one bothered).
The typelib:
This project uses oleexp.tlb, which is my own expansion of olelib.tlb. Originally I just had a modified olelib, but now for compatibility reasons I've split off my additions so that there's minimal changes to olelib to maximize compatibility. See the olechanges.txt file for details. This project MIGHT work with an unmodified olelib.tlb since it doesn't use any of the changed interfaces, but I strongly advise using my upgraded olelib, as the only code-breaking changes are turning a few subs into functions since the return value is important (and only on IShellFolder/2 and IEnumIDList).
Full source code for both the upgraded olelib.tlb and oleexp.tlb is included and can be compiled into a hash-identical copy with VS6.0's MKTYPLIB.
This project uses oleexp.tlb version 1.1, if you have an earlier version from my other projects please upgrade it (fully backwards compatible, no code changes to other projects will be needed).
IShellItem:
For modern Windows, IShellItem is becoming more and more important. This project will familiarize you with using this object. The typelib based approach to this offers the advantage of being able to use IShellItem and related types project-wide, and pass them around easily, both within the project and to APIs and interfaces that use them. The sample project has helper functions that show how to create and manipulate IShellItem and related functions.
--
The attached ZIP includes olelib and oleexp, as well as a sample project illustrating the use of the dialogs. There's examples for a very simple Open, a typical Open dialog, a simple Save dialog, a multi-file-open dialog, and a highly customized open dialog.
In Your Own Project
To use IFileDialog-based Open/Save, your project needs to add a reference to olelib and oleexp. cFileDialogEvents.cls is required only if you want to receive feedback while the dialog is open (including from added custom controls).
-----------------------------------
Here's how simple a basic Open File dialog is with this tlb:
That's all it takes to get the very simplest Open File dialog going, and shows how the class is used.
Events
While previously subclassing was required to receive event notifications while the dialog was displayed, this is now accomplished simply by adding the optional cFileDialogEvents class and calling the .Advise method.
This same class also receives events from any custom controls added.
Customization
I thought that even with this approach, it was going to be hard. But the class is set up to make this a very easy process.
To add a simple label and a button,
With that, the events class will have its OnButtonClicked method called when its clicked.
Here's the full sample code that produces the dialog in the above screenshot:
IFileDialog / IFileOpenDialog / IFileSaveDialog
![]()

IFileSaveDialog and IFileOpenDialog were introduced in Windows Vista to supersede the GetOpenFileName/GetSaveFileName API, and offer several advantages (although certainly some drawbacks). Windows provides a default implementation, so they're fairly easy to use in VB. Among the advantages is easy addition of custom controls, something that was not previously possible in VB (or at least so hard no one bothered).
The typelib:
This project uses oleexp.tlb, which is my own expansion of olelib.tlb. Originally I just had a modified olelib, but now for compatibility reasons I've split off my additions so that there's minimal changes to olelib to maximize compatibility. See the olechanges.txt file for details. This project MIGHT work with an unmodified olelib.tlb since it doesn't use any of the changed interfaces, but I strongly advise using my upgraded olelib, as the only code-breaking changes are turning a few subs into functions since the return value is important (and only on IShellFolder/2 and IEnumIDList).
Full source code for both the upgraded olelib.tlb and oleexp.tlb is included and can be compiled into a hash-identical copy with VS6.0's MKTYPLIB.
This project uses oleexp.tlb version 1.1, if you have an earlier version from my other projects please upgrade it (fully backwards compatible, no code changes to other projects will be needed).
IShellItem:
For modern Windows, IShellItem is becoming more and more important. This project will familiarize you with using this object. The typelib based approach to this offers the advantage of being able to use IShellItem and related types project-wide, and pass them around easily, both within the project and to APIs and interfaces that use them. The sample project has helper functions that show how to create and manipulate IShellItem and related functions.
--
The attached ZIP includes olelib and oleexp, as well as a sample project illustrating the use of the dialogs. There's examples for a very simple Open, a typical Open dialog, a simple Save dialog, a multi-file-open dialog, and a highly customized open dialog.
In Your Own Project
To use IFileDialog-based Open/Save, your project needs to add a reference to olelib and oleexp. cFileDialogEvents.cls is required only if you want to receive feedback while the dialog is open (including from added custom controls).
-----------------------------------
Here's how simple a basic Open File dialog is with this tlb:
Code:
Dim fodSimple As FileOpenDialog
Dim isiRes As IShellItem
Dim lPtr As Long
Set fodSimple = New FileOpenDialog
With fodSimple
.SetTitle "Simple File Open"
.Show Me.hWnd
.GetResult isiRes
isiRes.GetDisplayName SIGDN_FILESYSPATH, lPtr
Text1.Text = BStrFromLPWStr(lPtr, True)
End With
Set isiRes = Nothing
Set fodSimple = Nothing
Events
While previously subclassing was required to receive event notifications while the dialog was displayed, this is now accomplished simply by adding the optional cFileDialogEvents class and calling the .Advise method.
This same class also receives events from any custom controls added.
Customization
I thought that even with this approach, it was going to be hard. But the class is set up to make this a very easy process.
To add a simple label and a button,
Code:
Dim fdc As IFileDialogCustomize
Set fdc = pDlg 'pDlg is the FileOpenDialog object
pDlg.Advise cFDE, 0 'the events class
fdc.AddText 1000, "This is a test label."
fdc.AddPushButton 1001, "New Button"
Here's the full sample code that produces the dialog in the above screenshot:
Code:
On Error Resume Next 'A major error is thrown when the user cancels the dialog box
List1.Clear
Dim isiRes As IShellItem
Dim isiDef As IShellItem 'default folder
Dim FOLDERID_Pictures As UUID
Dim pidlDef As Long
Dim lPtr As Long
Dim lOptions As FILEOPENDIALOGOPTIONS
'Set up filter
Dim FileFilter() As COMDLG_FILTERSPEC
ReDim FileFilter(1)
FileFilter(0).pszName = "Image Files"
FileFilter(0).pszSpec = "*.jpg;*.gif;*.bmp"
FileFilter(1).pszName = "All Files"
FileFilter(1).pszSpec = "*.*"
'set up default folder: note that this only shows the very first time
' after that, the last directory is default
' automatically. override with SetFolder.
Call CLSIDFromString(StrPtr(fidPictures), FOLDERID_Pictures)
Call SHGetKnownFolderIDList(FOLDERID_Pictures, 0, 0, pidlDef)
If pidlDef Then
Call SHCreateShellItem(0, 0, pidlDef, isiDef)
End If
Set fod = New FileOpenDialog
Set cEvents = New cFileDialogEvents
With fod
.Advise cEvents, 0
.SetTitle "Select Thine File Sir"
.GetOptions lOptions
lOptions = lOptions Or FOS_FILEMUSTEXIST Or FOS_FORCESHOWHIDDEN 'just an example of options... shows hidden files even if they're normally not shown
.SetOptions lOptions
.SetOkButtonLabel "Mine File"
.SetFileNameLabel "Look! A custom file label!!!"
If (isiDef Is Nothing) = False Then
.SetFolder isiDef
End If
.SetFileTypes 2, VarPtr(FileFilter(0).pszName)
'Now we'll begin adding custom controls
'First, we set up the interface
'The control IDs can be any number, and should
'really be stored as consts
Set fdc = fod
fdc.AddText 1000, "This is a test label."
fdc.AddPushButton 1001, "New Button"
fdc.MakeProminent 1001 'Moves to by the open button; only checkboxes, buttons, combos, menus can be made prominent
fdc.AddPushButton 1002, "Some Other Button"
fdc.StartVisualGroup 2000, "VG-1"
fdc.AddCheckButton 2001, "Checkers!", 1
fdc.AddSeparator 2002
'For menus, and radio buttons/combos, first you add the control, then add items with AddControlItem
fdc.AddMenu 2010, "Checkers?"
fdc.AddControlItem 2010, 3000, "Pretty good."
fdc.AddControlItem 2010, 3001, "Pretty bad."
fdc.AddControlItem 2010, 3002, "Neutral!"
fdc.AddEditBox 2003, "Other."
fdc.EndVisualGroup
fdc.StartVisualGroup 4000, "Radio station?"
fdc.AddRadioButtonList 4001
fdc.AddControlItem 4001, 4010, "Radio Station Alpha"
fdc.AddControlItem 4001, 4011, "Radio Station Beta"
fdc.EndVisualGroup
fdc.AddComboBox 5000
fdc.AddControlItem 5000, 5010, "Combo Alpha"
fdc.AddControlItem 5000, 5011, "Combo Beta"
fdc.AddControlItem 5000, 5012, "Combo Gamma"
fdc.SetSelectedControlItem 5000, 5011
.Show Me.hWnd
.GetResult isiRes
isiRes.GetDisplayName SIGDN_FILESYSPATH, lPtr
Text1.Text = BStrFromLPWStr(lPtr, True)
End With
If pidlDef Then Call CoTaskMemFree(pidlDef)
Set isiRes = Nothing
Set isiDef = Nothing
Set fod = Nothing