How to get the path of the virtual folder in file save dialog?

595 views Asked by At

----------------------------------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. enter image description here

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.

0

There are 0 answers