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

[VB6] Using the new IFileDialog interface for customizable Open/Save (TLB, Vista+)

$
0
0
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.

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

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,
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"

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:

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

Attached Files

Viewing all articles
Browse latest Browse all 1448

Trending Articles



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