If you are implementing a shell namespace extension and want to know when a file system item in your shell namespace extension is chosen by the user from Open Dialog, this blog post is for you.
The basic steps on how to do this as follows:
- Implement IObjectWithSite in your COM class that is passed to SHCreateShellFolderView inSFV_CREATE::psfvcb.
- In your implementation of IObjectWithSite::SetSite, query IUnknown *pUnkSite for SID_SExplorerBrowserFrame service to retrieve IFileOpenDialog interface.
Note: it will be NULL if your namespace extension is not hosted by Open Dialog as the interface name suggests. - Implement IFileDialogEvents::OnFileOk in a COM class and pass it to IFileDialog::Advise (IFileOpenDialog is derived from IFileDialog)
OnFileOK will be called when a file system item in your shell namespace extension is chosen by the user from Open Dialog.
Here is how this can be implemented:
classCFolderViewCB : publicIShellFolderViewCB,
publicIFolderViewSettings,
publicIObjectWithSite
{
public:
CFolderViewCB() : _cRef(1), m_pUnkSite(NULL), m_cookie(0), m_fileOpenDialog(NULL) {}
// IUnknown
IFACEMETHODIMP QueryInterface(REFIIDriid, void **ppv)
{
staticconstQITAB qit[] =
{
QITABENT(CFolderViewCB, IShellFolderViewCB),
QITABENT(CFolderViewCB, IFolderViewSettings),
QITABENT(CFolderViewCB, IObjectWithSite),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
…
IFACEMETHODIMP SetSite(IUnknown *pUnkSite);
IFACEMETHODIMP GetSite(REFIID riid, void **ppvSite);
private:
…
IUnknown *m_pUnkSite;
DWORD m_cookie;
IFileOpenDialog *m_fileOpenDialog;
};
…
HRESULTCFolderViewCB::SetSite(IUnknown *pUnkSite)
{
if (m_pUnkSite != NULL)
{
m_pUnkSite->Release();
if (m_fileOpenDialog != NULL)
{
m_fileOpenDialog->Unadvise(m_cookie);
m_fileOpenDialog->Release();
m_fileOpenDialog = NULL;
m_cookie = 0;
}
}
m_pUnkSite = pUnkSite;
if (m_pUnkSite != NULL)
{
m_pUnkSite->AddRef();
HRESULT hr = IUnknown_QueryService(m_pUnkSite, SID_SExplorerBrowserFrame, IID_PPV_ARGS(&m_fileOpenDialog));
if (SUCCEEDED(hr))
{
IFileDialogEvents *fileDialogEvents;
hr = FileDialogEvents_CreateInstance(IID_PPV_ARGS(&fileDialogEvents));
if (SUCCEEDED(hr))
{
hr = m_fileOpenDialog->Advise(fileDialogEvents, &m_cookie);
fileDialogEvents->Release();
}
if (FAILED(hr))
{
m_fileOpenDialog->Release();
m_fileOpenDialog = NULL;
}
}
if (FAILED(hr))
{
//OutputDebugString(L"Failed to subscribe for IFileDialogEvents::Advise\n");
}
}
returnS_OK;
}
HRESULTSTDMETHODCALLTYPECFolderViewCB::GetSite(REFIIDriid, void **ppvSite)
{
HRESULT hr = E_FAIL;
if (m_pUnkSite != NULL)
{
hr = m_pUnkSite->QueryInterface(riid, ppvSite);
}
if (FAILED(hr))
{
*ppvSite = NULL;
}
return hr;
}
classFileDialogEvents : publicIFileDialogEvents
{
public:
FileDialogEvents() : _cRef(1) {}
// IUnknown
IFACEMETHODIMP QueryInterface(REFIIDriid, void **ppv)
{
staticconstQITAB qit[] =
{
QITABENT(FileDialogEvents, IFileDialogEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef() { returnInterlockedIncrement(&_cRef); }
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (0 == cRef)
{
deletethis;
}
return cRef;
}
IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
{
PWSTR filePath;
IShellItem *shellItem;
if (SUCCEEDED(pfd->GetResult(&shellItem)))
{
if (SUCCEEDED(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)))
{
//OutputDebugString(filePath);
//OutputDebugString(L"\r\n");
CoTaskMemFree(filePath);
}
shellItem->Release();
}
returnS_OK;
}
IFACEMETHODIMP OnFolderChanging(IFileDialog * /*pfd*/, IShellItem * /*psiFolder*/)
{
returnE_NOTIMPL;
}
IFACEMETHODIMP OnFolderChange(IFileDialog * /*pfd*/)
{
returnE_NOTIMPL;
}
IFACEMETHODIMP OnSelectionChange(IFileDialog * /*pfd*/)
{
returnE_NOTIMPL;
}
IFACEMETHODIMP OnShareViolation(IFileDialog * /*pfd*/, IShellItem * /*psi*/, FDE_SHAREVIOLATION_RESPONSE * /*pResponse*/)
{
returnE_NOTIMPL;
}
IFACEMETHODIMP OnTypeChange(IFileDialog * /*pfd*/)
{
returnE_NOTIMPL;
}
IFACEMETHODIMP OnOverwrite(IFileDialog * /*pfd*/, IShellItem * /*psi*/, FDE_OVERWRITE_RESPONSE * /*pResponse*/)
{
returnE_NOTIMPL;
}
private:
~FileDialogEvents()
{
};
long _cRef;
};
HRESULT FileDialogEvents_CreateInstance(REFIIDriid, void **ppv)
{
*ppv = NULL;
HRESULT hr = E_OUTOFMEMORY;
FileDialogEvents *events = new (std::nothrow) FileDialogEvents();
if (events)
{
hr = events->QueryInterface(riid, ppv);
events->Release();
}
return hr;
}
Additional references:
IExplorerBrowser interface
https://msdn.microsoft.com/en-us/library/windows/desktop/bb761909(v=vs.85).aspx
Follow us on Twitter, www.twitter.com/WindowsSDK.