如何从命名空间扩展中将虚拟文件夹(IShellFolder)添加到资源管理器视图?

如何从命名空间扩展中将虚拟文件夹(IShellFolder)添加到资源管理器视图?

问题描述:

我在开发中有一个命名空间扩展,我坚持从扩展内部以编程方式添加一个文件夹。在视觉上发生的是单击工具栏按钮,选择文件路径并且该文件是从中创建虚拟文件夹和文件的数据源。如何从命名空间扩展中将虚拟文件夹(IShellFolder)添加到资源管理器视图?

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

我研究过这个问题,通常当这种情况发生时,人们正在使用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,他们从来没有击中。我读过SF_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; 
} 

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

+0

SHCNE_UDPATEDIR说但是没有人在看'newfoldername',因为它不存在。该文档说,“如果文件夹已被创建,删除或重命名,分别使用SHCNE_MKDIR,SHCNE_RMDIR或SHCNE_RENAMEFOLDER。” –

+0

命名空间扩展数据源是与SHITEMIDLIST分离的树结构。在更新数据源树以从根上添加另一个分支并正确调用SHChangeNotify(谢谢)后,还需要采取其他哪些步骤才能让Shell调用IShellFolder2 :: EnumObjects()? –

+1

为每个创建的目录提升一个SHCNE_MKDIR。如果你创建了一个子目录,那么这意味着提升两次,一次为第一级目录,一次为第二级目录 –

尝试以下操作: “嘿,如果有人在看`thenewfoldername`,他们应该刷新”

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

在SFVM_GETNOTIFY中,我现在按照您的建议设置标志,并在lParam中设置pidl,但发出SHChangeNotify后却调用了IShellFolder:EnumObjects或BindToObject。但是SFVM_FSNOTIFY现在正在被击中。在用户界面中没有任何更改,该文件夹不会使用该树显示或不显示,或者返回到根文件夹。 –

+0

如果使用DefShellView,则可以尝试删除SFVM_UPDATEOBJECT,SFVM_QUERYFSNOTIFY,SFVM_ADDOBJECT和SFVM_FSNOTIFY处理程序。如果这个值只是返回E_NOTIMPL,因为这个值应该由DefShellView处理。 –

+0

这是有道理的。我盲目地说,在这些情况下做任何事情都没有问题。感谢那。我越来越近了,但EnumObject仍然没有在通过SHChangeNotify发送事件通知后被调用。我想一旦调用了EnumObjects,Explorer将通过调用Enumerator接口显示新数据,然后创建SHITEMID。有任何想法吗? –