如何从命名空间扩展中将虚拟文件夹 (IShellFolder) 添加到资源管理器视图?
How can I add a virtual folder(IShellFolder) to the Explorer view from within a namespace extension?
我有一个命名空间扩展正在开发中,但我无法从扩展中以编程方式添加一个文件夹。视觉上发生的事情是单击工具栏按钮,选择文件路径,该文件是创建虚拟文件夹和文件的数据源。
由于工具栏上的加载文件按钮位于名称空间扩展根目录中,所以我希望自动出现新的虚拟文件夹。为了显示它,我需要单击树视图或从根目录中退出并返回。然后文件夹就出现了。
我已经研究过这个问题,通常发生这种情况时人们正在使用 SCHhangeNotify。我尝试像下面的示例一样使用各种组合,例如提供名称空间扩展根的路径或 pidl,下面的示例包括应该存在的新文件夹,使用该路径的 pidl(在 SHChangeNotify 中使用适当的标志)和仍然没有骰子。我还尝试了 SHCNE_xxx,其中 xxx 是通知所有标志。
SCHhangeNotify(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 class 中,我在通知标志上设置了 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;
}
我应该采取什么步骤来让文件夹以编程方式显示?
尝试以下操作:
SFVM_GETNOTIFY:
begin
PDWORD(ALParam)^ := SHCNE_ALLEVENTS;
Result := S_OK;
end;
我有一个命名空间扩展正在开发中,但我无法从扩展中以编程方式添加一个文件夹。视觉上发生的事情是单击工具栏按钮,选择文件路径,该文件是创建虚拟文件夹和文件的数据源。
由于工具栏上的加载文件按钮位于名称空间扩展根目录中,所以我希望自动出现新的虚拟文件夹。为了显示它,我需要单击树视图或从根目录中退出并返回。然后文件夹就出现了。
我已经研究过这个问题,通常发生这种情况时人们正在使用 SCHhangeNotify。我尝试像下面的示例一样使用各种组合,例如提供名称空间扩展根的路径或 pidl,下面的示例包括应该存在的新文件夹,使用该路径的 pidl(在 SHChangeNotify 中使用适当的标志)和仍然没有骰子。我还尝试了 SHCNE_xxx,其中 xxx 是通知所有标志。 SCHhangeNotify(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 class 中,我在通知标志上设置了 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;
}
我应该采取什么步骤来让文件夹以编程方式显示?
尝试以下操作:
SFVM_GETNOTIFY:
begin
PDWORD(ALParam)^ := SHCNE_ALLEVENTS;
Result := S_OK;
end;