如何从命名空间扩展中将虚拟文件夹(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;
}
我应该采取什么步骤让文件夹以编程方式显示?
尝试以下操作: “嘿,如果有人在看`thenewfoldername`,他们应该刷新”
SFVM_GETNOTIFY:
begin
PDWORD(ALParam)^ := SHCNE_ALLEVENTS;
Result := S_OK;
end;
在SFVM_GETNOTIFY中,我现在按照您的建议设置标志,并在lParam中设置pidl,但发出SHChangeNotify后却调用了IShellFolder:EnumObjects或BindToObject。但是SFVM_FSNOTIFY现在正在被击中。在用户界面中没有任何更改,该文件夹不会使用该树显示或不显示,或者返回到根文件夹。 –
如果使用DefShellView,则可以尝试删除SFVM_UPDATEOBJECT,SFVM_QUERYFSNOTIFY,SFVM_ADDOBJECT和SFVM_FSNOTIFY处理程序。如果这个值只是返回E_NOTIMPL,因为这个值应该由DefShellView处理。 –
这是有道理的。我盲目地说,在这些情况下做任何事情都没有问题。感谢那。我越来越近了,但EnumObject仍然没有在通过SHChangeNotify发送事件通知后被调用。我想一旦调用了EnumObjects,Explorer将通过调用Enumerator接口显示新数据,然后创建SHITEMID。有任何想法吗? –
SHCNE_UDPATEDIR说但是没有人在看'newfoldername',因为它不存在。该文档说,“如果文件夹已被创建,删除或重命名,分别使用SHCNE_MKDIR,SHCNE_RMDIR或SHCNE_RENAMEFOLDER。” –
命名空间扩展数据源是与SHITEMIDLIST分离的树结构。在更新数据源树以从根上添加另一个分支并正确调用SHChangeNotify(谢谢)后,还需要采取其他哪些步骤才能让Shell调用IShellFolder2 :: EnumObjects()? –
为每个创建的目录提升一个SHCNE_MKDIR。如果你创建了一个子目录,那么这意味着提升两次,一次为第一级目录,一次为第二级目录 –