I'd like to allow users of my Windows game to use a dialog box to select a folder or a file. I can currently do one or the other using SHBrowseForFolder or GetOpenFileName, but not both options from within the same dialog. Is this possible? (Reason being I'm porting a Mac game where this is possible.)
-
1SHBrowseForFolder with BIF_BROWSEINCLUDEFILES, but it brings up an ugly dialog on Vista and higher. What's wrong to have two menu items, one for files and one for folders? – Sheng Jiang 蒋晟 Nov 11 '11 at 02:33
4 Answers
When you bring up the file dialog, give it a default filename such as "Entire folder" and turn off the flag that requires the file to exist before enabling the OK button. When the dialog returns, check the filename to see if it matches the special string "Entire folder" and treat it accordingly.
Based on my answer to another question: How do you configure an OpenFileDialog to select folders?

- 1
- 1

- 299,747
- 42
- 398
- 622
-
Doesn't work for me with GetOpenFileName. Must be something that works for OpenFileDialog. I'm using C. It is possible to call OpenFileDialog directly from C, or would I have to create a C++ class with a C interface? – Vern Jensen Nov 14 '11 at 18:21
-
@Vern, that's really odd - when I wrote that other answer I tested with a framework that used GetOpenFileName internally. I'll try it again later to see where the problem is. – Mark Ransom Nov 14 '11 at 20:10
If you set OFN_NOVALIDATE in the Flags member of the OPENFILENAME structure, typing a folder name without a '\' at the end, and pressing Enter (or Open), will send the CDN_FILEOK notification to the hook procedure, not the CDN_FOLDERCHANGE notification.
From there, you may do whatever you want with the folder path. To me, this is a bug, but it might help you.

- 63
- 8
I know this thread is old but I recently had the same problem. I discovered that when clicking the OK button the dialog emits the CDN_FOLDERCHANGE message but the folder actually did not change (is the same as at the last call). So I came up with the follwing hook procedure:
UINT_PTR CALLBACK openfilename_cb (
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
NMHDR *nmhdr;
OFNOTIFY *ofnotify;
static char dir_now[PATH_MAX], dir_prev[PATH_MAX];
do_debug (5, "openfilename_cb(): hwnd=%p, msg=%d\n", hwnd, msg);
switch (msg)
{
case WM_INITDIALOG:
do_debug (2, "openfilename_cb(): WM_INITDIALOG\n");
break;
case WM_NOTIFY:
ofnotify = (OFNOTIFY *)lParam;
nmhdr = &ofnotify->hdr;
do_debug (4,"openfilename_cb(): WM_NOTIFY, hwnd=%p, id=%d, code=%d\n",
nmhdr->hwndFrom, nmhdr->idFrom, nmhdr->code);
switch (nmhdr->code)
{
case CDN_INITDONE:
do_debug (3, "openfilename_cb(): CDN_INITDONE\n");
dir_prev[0] = '\0';
break;
case CDN_FILEOK:
do_debug (3, "openfilename_cb(): CDN_FILEOK\n");
break;
case CDN_FOLDERCHANGE:
do_debug (3, "openfilename_cb(): CDN_FOLDERCHANGE\n");
SendMessage (nmhdr->hwndFrom, CDM_GETFOLDERPATH, sizeof(dir_now),
(LPARAM)dir_now);
do_debug (3, " directory=%s\n", dir_now);
if (ofnotify->lpOFN->lCustData & FN_OPENDIR)
{
if (stricmp(dir_now, dir_prev) == 0)
{
/* user clicked the OK button */
strncpy (ofnotify->lpOFN->lpstrFile, dir_now, PATH_MAX);
ofnotify->lpOFN->lCustData = MAGIC;
PostMessage (nmhdr->hwndFrom, WM_COMMAND, IDCANCEL, 0);
do_debug (3, " closing dialog\n");
break;
}
strncpy (dir_prev, dir_now, sizeof(dir_prev));
}
break;
case CDN_HELP:
do_debug (3, "openfilename_cb(): CDN_HELP\n");
break;
case CDN_SELCHANGE:
do_debug (3, "openfilename_cb(): CDN_SELCHANGE\n");
break;
case CDN_SHAREVIOLATION:
do_debug (3, "openfilename_cb(): CDN_SHAREVIOLATION\n");
break;
case CDN_TYPECHANGE:
do_debug (3, "openfilename_cb(): CDN_TYPECHANGE\n");
break;
} /* switch (nmhdr->code) */
break; /* WM_NOTIFY */
} /* switch (msg) */
return 0;
}
Be sure to set the OFN_ENABLEHOOK and OFN_EXPLORER bits in the OPENFILENAME struct Flags member in order to get the hook procedure called. And, of course, set the lpfnHook member to the address of your hook function.
I discovered that the dialog looks quite different whether using the hook procedure or not (elements are sorted differently, there is a tree view in the left pane vs. large icons, maybe more).
You have to communicate back and forth to your calling function that you want to / have selected a directory. I use the lCustData member of the OPENFILENAME struct for that.
I tested with Windows 10, Version 19042.1052, 64bit and Windows XP, 32bit.
Johannes

- 30,962
- 25
- 85
- 135

- 76
- 2
To the very best of my knowledge, the common dialogs cannot be operated in a mode where you can select either folder or file from the same dialog.

- 601,492
- 42
- 1,072
- 1,490