----------------------------------update-----------------------------------
If I implement the ParseDislayName
like following, dialog will report "The file already exist, do you want to replace it?":
HRESULT CFolderViewImplFolder::ParseDisplayName(HWND hwnd, IBindCtx *pbc, PWSTR pszName,
ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
{
HRESULT hr = E_INVALIDARG;
if (NULL != pszName)
{
WCHAR szNameComponent[MAX_PATH] = {};
// extract first component of the display name
PWSTR pszNext = PathFindNextComponent(pszName);
if (pszNext && *pszNext)
{
hr = StringCchCopyN(szNameComponent, ARRAYSIZE(szNameComponent), pszName, lstrlen(pszName) - lstrlen(pszNext));
}
else
{
hr = StringCchCopy(szNameComponent, ARRAYSIZE(szNameComponent), pszName);
}
if (SUCCEEDED(hr))
{
PathRemoveBackslash(szNameComponent);
UINT uIndex = 0;
hr = GetIndexFromDisplayString(szNameComponent, &uIndex);
if (SUCCEEDED(hr))
{
BOOL fIsFolder = ISFOLDERFROMINDEX(uIndex);
PIDLIST_RELATIVE pidlCurrent = NULL;
hr = CreateChildID(szNameComponent, fIsFolder, &pidlCurrent);
if (SUCCEEDED(hr))
{
// If there are more components to parse, delegate to the child folder to handle the rest.
if (pszNext && *pszNext)
{
// Bind to current item
IShellFolder *psf;
hr = BindToObject(pidlCurrent, pbc, IID_PPV_ARGS(&psf));
if (SUCCEEDED(hr))
{
PIDLIST_RELATIVE pidlNext = NULL;
hr = psf->ParseDisplayName(hwnd, pbc, pszNext, pchEaten, &pidlNext, pdwAttributes);
if (SUCCEEDED(hr))
{
*ppidl = ILCombine(pidlCurrent, pidlNext);
ILFree(pidlNext);
}
psf->Release();
}
ILFree(pidlCurrent);
}
else
{
// transfer ownership to caller
*ppidl = pidlCurrent;
}
}
}
}
}
return hr;
}
I use shell namespace extension to create a virtual folder on windows 7. Then I bring up a file "Save As" dialog in another application, and select a specific "folder" in the virtual folder in the dialog, the file dialog cannot get the path to the virtual folder. After several experiments, I can get the path of the folder in the file "Open" dialog as described in this link: cannot get the path for the virtual folder on windows 7 C++(shell namespace extension related) But when I use a similar way to implement the file "Save As" dialog, it doesn't work.
class CDialogEventHandler : public IFileDialogEvents,
public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK;
};
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
IFACEMETHODIMP OnTypeChange(IFileDialog *pfd) { return S_OK; };
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
// IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem) { return S_OK; };
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
HRESULT VirtualFolderFileSave()
{
// CoCreate the File Open Dialog object.
//IFileSaveDialog *pfsd; also doesn't work
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileSaveDialog,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
hr = pfd->SetDefaultExtension(L"apx");
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
//never get here.......
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
&pszFilePath);
if (SUCCEEDED(hr))
{
}
psiResult->Release();
}
}
}
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
return hr;
}
I add breakpoint in IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; };
in the above code, but it is never triggered after I click "Save" button in the file dialog. And as you can see in the comments in the above code, after the dialog shows up, it never returns after hr = pfd->Show(NULL);
. Every time when I click "Save" button, it always reports error or throw exceptions.
I tried to implement the following in the virtual folder dll,
// Translates a display name into an item identifier list.
HRESULT CFolderViewImplFolder::ParseDisplayName(HWND /*hwnd*/, IBindCtx * /*pbc*/, PWSTR /*pszName*/,
ULONG * /*pchEaten*/, PIDLIST_RELATIVE * /*ppidl*/, ULONG * /*pdwAttributes*/)
{
return E_NOTIMPL;
}
But when it returns E_NOTIMPL
, dialog reports "not implement"error, if it returns S_OK
, dialog throws exceptions.
I am not trying to create something under virtual foder, I just want to get the path wthere the user is trying to save at.