Mr. Boy
Mr. Boy

Reputation: 63846

Use file dialog to select a folder that contains a specific file type?

Our application saves its projects as a folder full of stuff, including the actual project file something.abc

It is a niggle that when loading a project, we have to go into the project folder and find the project file. I know there are folder-selection OS dialogs but I only want it to work if it can see the file exists inside the folder.

I'm sure I saw this done but I've no idea how... we're using Qt but answers for that or natively for Windows are welcome. The one thing is I want to use the native OS dialogs not build my own from scratch.

Upvotes: 1

Views: 354

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598449

The Win32 SHBrowseForFolder() and IFileOpenDialog APIs both allow the user to select a folder.

Both APIs allow you to react to dialog events, like changes to the current folder selection, validation of the current selection, etc. SHBrowseForFolder() has a callback function, and IFileOpenDialog has an IFileDialogEvents sink interface.

Such a callback/sink can check whether the currently selected folder has a given file type, and then block or allow the dialog from returning that result to the caller.

SHBrowseForFolder()

To check for a file type's existence:

  • get the folder's filesystem path by passing its absolute PIDL to SHGetPathFromIDList().
  • then search that path using FindFirstFile() with the desired filename pattern mask.

or

  • retrieve an IShellFolder interface by passing the folder's absolute PIDL to SHBindToObject() (or, on pre-Vista systems, use SHGetDesktopFolder() to get the IShellFolder of the top-level Desktop shell namespace, then pass the PIDL to its BindToObject() method).
  • then use the IShellFolder::EnumObjects() method to get its IEnumIDList interface.
  • then enumerate the relative PIDLs of the files, using the parent folder's IShellFolder::GetDisplayNameOf() method to look for a file matching the desired filename pattern.

To block or allow the dialog from returning success to the caller, the callback function can handle the BFFM_SELCHANGED notification to validate the folder as needed and then send the dialog window a BFFM_ENABLEOK message with the lParam set to zero or non-zero accordingly.

IFileOpenDialog

To check for a file type's existence:

  • use the folder's IShellItem::BindToHandler() method to retrieve its IEnumShellItems interface.
  • then enumerate the IShellItem interfaces for the files, using the IShellItem::GetDisplayName() method to look for a file matching the desired filename pattern.

To block or allow the dialog from returning success to the caller, the sink can implement the OnFileOk event to validate the selected folder and return S_OK or S_FALSE as needed.

Alternatively, the sink can implement the OnFolderChange event to enable/disable the dialog's OK button directly (IFileDialogCustomize::SetControlState() doesn't work in this case):

  • retrieve the dialog's HWND by querying the dialog for its IOleWindow interface, and then calling its GetWindow() method.
  • then use the Win32 GetDlgItem() function to get the HWND of the OK button using the standard IDOK control ID.
  • then use the Win32 EnableWindow() function to enable/disable the button.

Upvotes: 6

Related Questions