2

I am perplexed on whether IFileDialog has the capability of programmatically selecting an item inside the dialog even with out the user selecting.

Ex. IFileDialog shows with nothing selected by default

I was hoping to achieve opening IFileDialog then selecting a default item/folder inside the dialog. Ex. Default selects an item/folder inside the dialog

By the way, in the picture above. I did manually click/select the folder. But I was hoping to implement a defaultly selected item inside the IFileDialog.

Community
  • 1
  • 1
Bryan
  • 51
  • 4
  • Maybe you are looking for [`IFileDialog::SetFileName`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb775974(v=vs.85).aspx)? It does set edit box content, but it does not select item in the list view though. – user7860670 May 08 '18 at 11:08
  • 2
    Set the filename before you display the dialog. – Hans Passant May 08 '18 at 11:13
  • 1
    I think this is the folder selection UI behaving as designed. – David Heffernan May 08 '18 at 12:10
  • 2
    [`IFileDialog::SetFolder()`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb761828(v=vs.85).aspx) - Sets a folder that is always selected when the dialog is opened, regardless of previous user action. – zett42 May 08 '18 at 13:06
  • SetFileName will only set the text on the edit box. I was hoping on setting the selected item(s) inside the dialog programmatically. – Bryan May 08 '18 at 15:04
  • 1
    Never tried, but I believe you could also call `IFileDialog::QueryInterface()` to get a `IShellView` interface. Then call `IShellView::SelectItem()` to select one or more items. Most likely the `IFileDialog` needs to be visible already, so you may have to hook one of the events like `OnFolderChange` via `IFileDialog::Advise()`. Also have a look at [Raymond Chen's blog](https://blogs.msdn.microsoft.com/oldnewthing/) which either already has what you are looking for or could at least give you enough thought food so you can figure it out on your own. – zett42 May 08 '18 at 16:18

1 Answers1

3

The procedure suggested by zett42 works. You need to implement your own version of IFileDialogEvents. After hooking with IFileDialog::Advise you can query your way to IShellView and that lets you change the selection.

This example is a little silly because I'm forcing the directory as well to be sure I have a file I can select.

struct MyIFileDialogEvents : public IFileDialogEvents {
    bool forcedDir, forcedSel;
    MyIFileDialogEvents() : forcedDir(false), forcedSel(false) {}
    ...
};

STDMETHODIMP MyIFileDialogEvents::OnFolderChanging( IFileDialog *pfd, IShellItem*psiFolder)
{
    if (forcedDir) return S_OK; else forcedDir = true;
    IShellItem*psiwindir;
    HRESULT hr = SHGetKnownFolderItem(FOLDERID_Windows, KF_FLAG_DEFAULT, NULL, IID_IShellItem, (void**) &psiwindir);
    if (!hr)
    {
        hr = pfd->SetFolder(psiwindir); // MSDN says it is OK to change the folder in OnFolderChanging with SetFolder
        psiwindir->Release();
    }
    if (FAILED(hr)) forcedSel = true;
    return S_OK;
}

STDMETHODIMP MyIFileDialogEvents::OnFolderChange(IFileDialog *pfd)
{
    if (forcedSel || !forcedDir) return S_OK; else forcedSel = true;
    IShellItem*psiwindir, *psiexp;
    HRESULT hr = SHGetKnownFolderItem(FOLDERID_Windows, KF_FLAG_DEFAULT, NULL, IID_IShellItem, (void**) &psiwindir);
    if (!hr)
    {
        hr = SHCreateItemFromRelativeName(psiwindir, L"Explorer.exe", NULL, IID_IShellItem, (void**) &psiexp);
        psiwindir->Release();
        if (!hr)
        {
            IServiceProvider*pSP;
            IShellBrowser*pSB;
            IShellView*pSV;
            if (!pfd->QueryInterface(IID_IServiceProvider, (void**) &pSP))
            {
                if (!pSP->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, (void**)&pSB))
                {
                    if (!pSB->QueryActiveShellView(&pSV))
                    {
                        PIDLIST_ABSOLUTE pidl;
                        if (!SHGetIDListFromObject(psiexp, &pidl))
                        {
                            pSV->SelectItem(ILFindLastID(pidl), SVSI_SELECT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_DESELECTOTHERS);
                            CoTaskMemFree(pidl);
                        }
                        pSV->Release();
                    }
                    pSB->Release();
                }
                pSP->Release();
            }
            psiexp->Release();
        }
    }
    return S_OK;
}
Anders
  • 97,548
  • 12
  • 110
  • 164