Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XFileDialog - Customizing CFileDialog

0.00/5 (No votes)
23 Jun 2003 2  
XFileDialog demonstrates how to customize CFileDialog by adding a MRU combobox for folders.

Introduction

When new common file dialogs were first introduced, I immediately liked the way they looked. But I also noticed that drop-down list of drives and directories seemed a bit awkward, especially if you wanted to flip between two directories on different drives. When we started hearing same thing from our customers, I knew we should try to make it easier to pick a folder.

Implementation notes

My initial thought was, OK, CFileDialog is a common dialog just like CFontDialog, all I have to do is copy the dialog template and insert my own controls. It turns out that customizing CFileDialog is completely different than customizing CFontDialog. (My article XFontDialog - Customizing CFontDialog Part I: Adding Font Filters explains how to customize CFontDialog). I found a reasonably complete description of what was going on in the MSDN article Open and Save As Dialog Boxes. This article explains that, to add controls to the CFileDialog dialog, what you do is create a dialog template that contains only the controls that you want to add. IDD_XFILEDIALOG is defined as:

IDD_XFILEDIALOG DIALOG DISCARDABLE  0, 0, 360, 20
STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
FONT 8, "MS Sans Serif"
BEGIN
    LTEXT           "Recent folders:",IDC_MRU_CAPTION,13,3,51,8,
                    SS_CENTERIMAGE | NOT WS_GROUP
    COMBOBOX        IDC_MRU_COMBO,85,1,260,102,CBS_DROPDOWN |
                    CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
END

Note the styles of this dialog - they are necessary for proper integration with CFileDialog. Once you have this dialog defined, you can add it to CFileDialog in ctor of your derived class:

SetTemplate(0, _T("IDD_XFILEDIALOG"));

I set up dialog template and its rc file according to guidelines I described in my article XDialogImport - How to share dialogs between projects.

Once I had dialog template, I then started to unravel secrets of how to integrate with CFileDialog. As I said before, it is completely different than CFontDialog. Whereas with CFontDialog all controls are on one dialog, with a customized CFileDialog you have two levels of dialogs: the new IDD_XFILEDIALOG actually is a child of original CFileDialog. This is alluded to in MSDN article, but I did not fully appreciate what this meant, until I saw it using one of my favorite tools, HPS HwndSpy:

screenshot

As you see in the screenshot, IDD_XFILEDIALOG is highlighted in window tree, and it is child of "Open" dialog. What this means in terms of implementation of CXFileDialog is that you can access all controls on IDD_XFILEDIALOG just like you would on any other dialog - by using GetDlgItem() or by using DDX_Control. However, all controls of CFileDialog are sibling to IDD_XFILEDIALOG - to access them, you must use GetParent()->GetDlgItem(xxx). Once I understood this, rest of the code was easy to implement - well, most of it was easy. There were still a few more things that bit me.

Before getting into more details, let me show you what I was attempting to do. I wanted to add a history combo box for most-recently used folders, so that every time user clicked Open, the current folder would be added to history list. Every time CXFileDialog was opened, history list items would be restored to combo box (if they were still valid directories). I decided to use Paul Vickery's excellent History ComboBox to take care of loading and saving folder items, with a modification I made to allow checking folders for validity. Here is what XFileDialog looks like:

screenshot

Of course there were usual details to take care of - like positioning and sizing IDD_XFILEDIALOG controls in the OnSize() handler. But when I tested CXFileDialog with pre-Win2K layout, I discovered that "File Name" control ID actually had two different values - one (1152) for when it was acting like an edit box (pre-Win2K), and another value (1148) for when it was acting like a combo box (Win2K and later). Furthermore, File Name control was also affected by a registry setting, which can be used to enable/disable the MRU property of the File Name control. How did I figure this out? Again, I used HPS HwndSpy:

screenshot

The next thing that I tested was Read-Only checkbox. Naturally, when I enabled it, the checkbox positioned itself right on top of my Recent Folders control, since I had forgotten to account for checkbox in OnSize().

Finally, I tested pre-Win2K layout. There was not enough room for the static label "Recent folders", so for pre-Win2K layout, I moved all combo boxes to the right. Here is the new pre-Win2K layout:

screenshot

CXFileDialog Features

Here are features in new CXFileDialog:

  • Recent folders MRU combo box - adds a combo box with list of most-recently used folders. Selecting a folder from the list will change the file display to that folder.
  • SetTitle() - Provides a convenient way to set title of dialog.
  • SetOsVersion() - Allows you to choose between old-style and Explorer-style dialog.
  • GetPath() - Gets path of selected file.

How to use

To integrate CXFileDialog into your app, you first need to add following files to your project:

  • XFileDialog.cpp
  • XFileDialog.h
  • XFileDialog.rc
  • XFileDialogRes.h
  • XHistoryCombo.cpp
  • XHistoryCombo.h

You also need to add XFileDialog.rc to project rc file - go to View | Resource Includes... and in the bottom listbox, scroll down to the end. Insert #include "XFileDialog.rc" right before the #endif:

screenshot

Next, include header file XFileDialog.h in appropriate project files. Now you are ready to start using CXFileDialog.

Demo App

The XFileDialogTest.exe demo shows how to use CXFileDialog:

screenshot

Acknowledgments

Revision history

  • Version 1.1 - 2003 June 25
    • Fixed some focus bugs;
    • Added check for directory existence.
  • Version 1.0 - 2003 June 24
    • Initial public release.

Usage

This software is released into the public domain. You are free to use it in any way you like. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here