Change usage of SHBrowseForFolder to IFileOpenDialog

549 views
Skip to first unread message

Muazin Mugadr

unread,
Mar 6, 2016, 12:00:28 PM3/6/16
to nw.js
Hello everyone

Today when working with an input that used nwdirectory on windows 10 I'm still getting presented the old (kinda deprecated) folder browser which is pretty annoying to use. It comes from the usage of SHBrowseForFolder which will display an old, XP-like folder dialog. Also the MSDN suggest that on systems with Vista or newer that function should no longer be used.

The better way is to use the IFileOpenDialog interface and set the FOS_PICKFOLDER option which will let you pick a folder. The advantages are abundant:
- Stateful for applications -> The dialog opens in the folder last opened even after restart
- Bigger window, easier to navigate (direct input into the path, etc)
- Consistent style between all filesystem dialogs
- ...

So I was wondering if there is a specific reason why not to use the new functionality. If not I would create a pull request for that.

I have created a simple PoC that decides at compile time which version to use, of course this can (and should) be replaced by a runtime OS version check, since its dynamically loaded via COM.

bool SelectFileDialogImpl::RunSelectFolderDialog(const std::wstring& title,
                                                 HWND owner,
                                                 base::FilePath* path) {
  DCHECK(path);

  bool result = false;

#if !defined(WINVER) || WINVER < _WIN32_WINNT_VISTA 
  // OLD CODE WITH SHBrowseForFolder
#else
  base::win::ScopedComPtr<IFileOpenDialog> file_open_dialog;
  HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_PPV_ARGS(file_open_dialog.Receive()));
  if(SUCCEEDED(hr)) {
    FILEOPENDIALOGOPTIONS options;
    hr = file_open_dialog->GetOptions(&options);
    if(SUCCEEDED(hr)) {
      options |= FOS_PICKFOLDERS | FOS_PATHMUSTEXIST;
      hr = file_open_dialog->SetOptions(options);
      if(SUCCEEDED(hr)) {
        file_open_dialog->SetTitle(title.c_str());
        hr = file_open_dialog->Show(owner);
        if(SUCCEEDED(hr)) {
          base::win::ScopedComPtr<IShellItem> result_item;
          hr = file_open_dialog->GetResult(result_item.Receive());
          if(SUCCEEDED(hr)) {
            LPWSTR result_name = NULL;
            hr = result_item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &result_name);
            if(SUCCEEDED(hr)) {
              result = true;
              *path = base::FilePath(result_name);
              CoTaskMemFree(result_name);
            }
          }
        }
      }
    }
  }
#endif

  if(result) {
    // According to MSDN, win2000 will not resolve shortcuts, so we do it
    // ourself.
    base::win::ResolveShortcut(*path, path, NULL);
  }

  return result;
}

Cheers,
Cromon

Reply all
Reply to author
Forward
0 new messages