如何从命名空间扩展中向Explorer视图添加虚拟文件夹(IShellFolder)?

时间:2016-11-21 18:50:11

标签: winapi com windows-shell

我在开发中有一个命名空间扩展,我无法在扩展程序中以编程方式添加文件夹。视觉上发生的是单击工具栏按钮,选择文件路径,该文件是创建虚拟文件夹和文件的数据源。

我想要发生的事情是因为工具栏上的加载文件按钮位于名称空间扩展名根目录中,是为了自动显示新的虚拟文件夹。为了显示它,我需要单击树视图或从根目录向上并返回。然后文件夹存在。

我研究过这个问题,通常在发生这种情况时,人们正在使用SHChangeNotify。我试着像下面的例子那样使用各种组合,例如提供名称空间扩展根目录的路径或pidl,下面的例子包括应该在那里的新文件夹,使用该路径的pidl(在SHChangeNotify中有适当的标志)和仍然没有骰子。我还尝试了SHCNE_xxx,其中xxx是一个通知全部标志。     SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_IDLIST,retPidl,0);

右键单击视图窗格并选择刷新不会调用要显示的文件夹。

在获取文件夹路径的代码中,我调用了我的文件夹的BindToObject,然后调用了EnumObjects和Next,没有命中断点。当我单击树视图或上升文件夹并返回时,所有断点都会被点击。 SHChangeNotify不会调用断点。

使用CreateViewObject中的SHCreateShellFolderView创建视图,如下所示:

if (IID_IShellView == riid) {
    SFV_CREATE csfv = {0};
    csfv.cbSize     = sizeof(SFV_CREATE);
    hr              = QueryInterface(IID_PPV_ARGS(&csfv.pshf));
    if (SUCCEEDED(hr)) {
        hr = CShellFolderView_CreateInstance(IID_PPV_ARGS(&csfv.psfvcb));
        if (SUCCEEDED(hr)) {
            hr = SHCreateShellFolderView(&csfv, (IShellView**)ppv); 
            csfv.psfvcb->Release();
    m_hWnd = hwndOwner;
        }
        csfv.pshf->Release();
    }
}
在ShellVolderView类中,我在通知标志上设置了一个bp,它们从未命中过。我读到SFVM_UPDATEOBJECT需要返回S_OK,所以我添加了。

IFACEMETHODIMP CShellFolderView::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) {
    HRESULT hr = E_NOTIMPL;
    switch(uMsg) {
        case SFVM_GETSORTDEFAULTS:
            wParam  = (WPARAM)(int*)-1;
            lParam  = (LPARAM)(int*)Col::Size;
            hr      = S_OK;
            break;
        case SFVM_GETNOTIFY:
            *((LONG*)lParam)    = SHCNE_ALLEVENTS;
            hr                  = S_OK;
            break;
    }
    return hr;
}

*编辑:添加可疑功能。当* ppidl为NULL时,返回E_INVALIDARG。

STDMETHODIMP CShellFolder::ParseDisplayName(HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) {
    HRESULT hr = E_INVALIDARG;

    if (pszDisplayName && *ppidl) {
        WCHAR szNameComponent[MAX_SIZE] = {};
        PWSTR pszNext                   = PathFindNextComponent(pszDisplayName);
        if (pszNext && *pszNext) {
            // unsure of max length, can't use StringCchLength for this
            size_t len      = lstrlen(pszDisplayName);
            size_t nextLen  = 0;
            StringCchLength(pszNext, MAX_SIZE, &nextLen);
            hr = StringCchCopyN(szNameComponent, MAX_SIZE, pszDisplayName, len - nextLen);
        }
        else {
            hr = StringCchCopy(szNameComponent, MAX_SIZE, pszDisplayName);
        }
        if (SUCCEEDED(hr)) {
            PathRemoveBackslash(szNameComponent);
            PIDLIST_RELATIVE pidlCurrent    = NULL;
            LPPIDLDATA child                = m_pPidlMgr->GetSubItemFromPidl((LPCITEMIDLIST)ppidl);
            hr                              = m_pPidlMgr->Create(&pidlCurrent, child);
            if (SUCCEEDED(hr)) {
                if (pszNext && *pszNext) {
                    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 {
                    *ppidl = pidlCurrent;
                }
            }
        }
    }
    return hr;
}

我应该采取哪些步骤让该文件夹以编程方式显示?

1 个答案:

答案 0 :(得分:1)

尝试以下方法:

SFVM_GETNOTIFY:
  begin
    PDWORD(ALParam)^ := SHCNE_ALLEVENTS;
    Result := S_OK;
  end;