如何在文件保存对话框中获取虚拟文件夹的路径?

时间:2017-12-18 22:25:36

标签: c++ windows registry shell-extensions shell-namespace-extension

----------------------------------的更新 ----- ------------------------------ 如果我实现ParseDislayName如下所示,对话框将报告“文件已存在,您要替换它吗?”:

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;
}

我使用shell命名空间扩展在Windows 7上创建虚拟文件夹。 然后我在另一个应用程序中调出一个文件“另存为”对话框,并在对话框的虚拟文件夹中选择一个特定的“文件夹”,文件对话框无法获取虚拟文件夹的路径。 经过几次实验,我可以在文件“打开”对话框中获取文件夹的路径,如以下链接所述: cannot get the path for the virtual folder on windows 7 C++(shell namespace extension related) 但是,当我使用类似的方式实现文件“另存为”对话框时,它不起作用。

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;
}

我在上面的代码中在IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; };中添加了断点,但是在我单击文件对话框中的“保存”按钮后,它永远不会被触发。正如您在上面的代码中的注释中所看到的,在对话框出现后,它永远不会在hr = pfd->Show(NULL);之后返回。每次单击“保存”按钮时,它总是报告错误或抛出异常。

我尝试在虚拟文件夹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;
}

但是当它返回E_NOTIMPL时,对话框报告“not implement”错误,如果它返回S_OK,则对话框会抛出异常。 enter image description here

我不是想在虚拟起源下创建一些东西,我只想获得用户试图保存的路径。

0 个答案:

没有答案