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

Winapi 如何从命名空间扩展中将虚拟文件夹(IShellFolder)添加到Explorer视图?,winapi,com,windows-shell,Winapi,Com,Windows Shell,我有一个名称空间扩展正在开发中,我一直在以编程方式从扩展中添加文件夹。在视觉上,单击工具栏按钮,选择文件路径,该文件就是创建虚拟文件夹和文件的数据源 由于工具栏上的“加载文件”按钮位于命名空间扩展根目录中,因此我希望新的虚拟文件夹自动显示。为了让它显示出来,我需要单击树状视图,或者从根目录中走出来,然后返回。然后文件夹就出现了 我研究过这个问题,通常情况下,当出现这种情况时,人们会使用SHChangeNotify。我试着像下面的例子那样,使用各种组合,例如提供名称空间扩展根的路径或pidl,下面

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

由于工具栏上的“加载文件”按钮位于命名空间扩展根目录中,因此我希望新的虚拟文件夹自动显示。为了让它显示出来,我需要单击树状视图,或者从根目录中走出来,然后返回。然后文件夹就出现了

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

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

在获取文件夹路径的代码中,我调用了文件夹的BindToObject,然后调用了EnumObjects,接下来,断点没有命中。当我单击树状视图或上一个文件夹再下一步时,所有断点都会被命中。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为空时,返回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;
}
我应该采取哪些步骤以编程方式显示文件夹?

尝试以下操作:

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

在SFVM_GETNOTIFY中,我现在像您建议的那样设置标志,并在LPRAM中设置pidl,但是IShellFolder:EnumObjects或BindToObject在发出SHChangeNotify后被调用。但SFVM_FSNOTIFY现在受到了攻击。UI中没有任何更改,该文件夹不会使用树显示,也不会向上或返回根文件夹。如果使用DefShellView,则可以尝试删除SFVM_UPDATEOBJECT、SFVM_QUERYFSNOTIFY、SFVM_ADDOBJECT和SFVM_FSNOTIFY处理程序。对于这个值,只需返回E_NOTIMPL,因为这个值应该由DefShellView处理。这很有意义。我只是盲目地说,在这种情况下,我们什么都不做,一切都好。谢谢你。我越来越接近了,但在通过SHChangeNotify发送事件通知后,仍然没有调用EnumObject。我想一旦调用了EnumObjects,Explorer就会通过调用Enumerator接口来显示新数据,然后我就可以创建ShitemId了。有什么想法吗?我支持你的问题,但为什么需要EnumObjects?Shell不知道我的数据源中的新文件夹。我认为Shell需要调用EnumObjects来获取我的枚举数(IEnumIDList)。然后Shell将调用IEnumIDList::Next(),在这里我从数据源中为新文件夹创建shitemid并返回它们。至少我认为它应该是这样工作的,我以前从未创建过名称空间扩展。SHCNE_UDPATEDIR说“嘿,如果有人在查看
新文件夹名
,他们应该刷新。”但没有人在查看
新文件夹名
,因为它不存在。文档中说,“如果文件夹已被创建、删除或重命名,请分别使用SHCNE_MKDIR、SHCNE_RMDIR或SHCNE_RENAMEFOLDER。”命名空间扩展数据源是一个独立于SHITEMIDLIST的树结构。在更新数据源树以添加另一根分支并正确调用SHChangeNotify(谢谢)之后,我应该采取哪些其他步骤来获取/请求Shell调用IShellFolder2::EnumObjects()?为创建的每个目录生成一个SHCNE_MKDIR。如果你创建了一个子目录,那就意味着提升它两次,一次是第一级目录,一次是第二级目录。我确实需要使用显式的SCHNE_MKDIR和SCHNE_RMDIR,但是SCHNE_更新没有像很多人使用的那样有效。添加和删除目录现在正在使用一些其他修复程序。顺便说一句,我从97年到11年在Windows上工作。我很荣幸能得到你的帮助。