【问题标题】:Setting visible columns on new directory在新目录上设置可见列
【发布时间】:2019-11-09 23:27:01
【问题描述】:

我正在开发一个用于创建新文件夹的 shell 扩展。一旦用户浏览到新文件夹,我希望新文件夹在详细信息视图中显示一组自定义列。我认为IColumnManager 可能是完成此任务的正确接口。这是创建新文件夹后我正在尝试的代码(我已缩写 PKEY):

IShellFolder* psdf;
if (SUCCEEDED(SHGetDesktopFolder(&psdf))) {

    PIDLIST_ABSOLUTE pidl = ILCreateFromPath(pwszNewFolderPath);

    LPSHELLFOLDER psf;
    if (SUCCEEDED(psdf->BindToObject(pidl, NULL, IID_IShellFolder, (void**)& psf))) {

        SFV_CREATE sfvc = { 0 };
        sfvc.cbSize = sizeof(SFV_CREATE);
        sfvc.pshf = psf;
        sfvc.psvOuter = NULL;
        sfvc.psfvcb = NULL;

        LPSHELLVIEW psv;
        if (SUCCEEDED(SHCreateShellFolderView(&sfvc, &psv))) {

            IColumnManager* pcm;
            if (SUCCEEDED(psv->QueryInterface(IID_IColumnManager, (void**)& pcm))) {

                PROPERTYKEY rgkeys[] = {
                    PKEY_ [...] ,
                    PKEY_ [...] ,
                    PKEY_ [...] ,
                };

                if (SUCCEEDED(pcm->SetColumns(rgkeys, ARRAYSIZE(rgkeys)))) {
                    //MessageBoxA(NULL, "Success?", "Success?", MB_OK);
                }
                pcm->Release();
            }
            psv->Release();
        }
        psf->Release();
    }
    psdf->Release();
}

这段代码成功地执行了每个方法调用,但是当我进入新创建的文件夹时,列不符合要求。难道我做错了什么? IColumnManager 是否仅在给定文件夹已经可见时才有效?也许它只适用于IExplorerBrowser 或其他什么?如果它不是正确的界面,当用户浏览到文件夹时,如何设置一组自定义列?谢谢。

编辑:此代码实际上适用于文件夹的活动视图。但是,它对列所做的更改不会持续存在(与用户手动进行的列更改不同,它会持续存在)。所以我想我想知道是否有办法让它们持久存在,或者是否有另一种方法来设置列而不需要活动视图。再次感谢。

另外,SHGetViewStatePropertyBag 是否相关?连同IExplorerBrowser::SetPropertyBag?或者那些不能用于常规 shell 文件夹?

【问题讨论】:

  • 注意IColumnManager::SetColumns会清除所有列的状态,所以必须在之后调用IColumnManager::SetColumnInfo来设置各个列的状态。
  • 谢谢,我认为SetColumnInfo 有效,只要文件夹视图处于活动状态。所以这很好。您是否知道在不查看文件夹时是否可以设置列?再次感谢!
  • 列集(及其状态,SHCOLSTATE)由 IShellFolder 接口实现决定。您拥有该文件夹吗?又名:你会写一个 Shell 命名空间扩展吗?
  • 不,我不这么认为。它只是我创建的一个目录,我把它变成了一个系统文件夹。
  • 绑定到正常的“DOS”路径为您提供了 IShellFolder 的基本系统实现,它支持适用于文件系统项的所有列。

标签: c++ winapi directory com multiple-columns


【解决方案1】:

SHCreateShellFolderView 创建一个提供IShellView 的shell 实例,该接口知道如何保存其设置,但它向其IShellBrowser 主机询问存储实现。 IShellView::CreateViewWindow 将视图连接到其主机。

IShellView::SaveViewState:

保存 Shell 的视图设置,以便在后续浏览会话期间可以恢复当前状态。

但是您需要实现IShellBrowser 并调用类似SHGetViewStatePropertyBag 的东西来获取Explorer 使用的存储实现,并在它要求时将其提供给IShellView。这里的大部分细节都没有记录,我建议您使用IExplorerBrowser 导航到文件夹,而不是尝试自己托管IShellView。使用“Shell”作为包名。

SHGetViewStatePropertyBag 已添加到 Windows XP 中,但 IExplorerBrowser 不存在。如果你需要支持the undocumented interface,这是IShellViewSHGetViewStatePropertyBag之间的粘合剂。

在 Windows 2000 和更早版本上,我相信状态直接存储在 IStream 中,而不是在属性包中。 OpenRegStream 用于打开流,但计算 MRU 路径的函数没有记录,但 KB 812003 至少告诉你根。

【讨论】:

  • BFO_BROWSER_PERSIST_SETTINGS 可能会更改设置的存储位置,但同样没有记录。
  • 我知道这个帖子有点老了,但我多年来一直在使用 Explorer 视图(从 XP 开始)——最初使用 VBScript,现在使用 PowerShell。我终于想出了如何解码BagMRU 及其子键(NirSoft's ShellBagsView is inaccurte/incomplete)并将它们与它们在 Shell 命名空间中的相应位置相关联。现在关注这个帖子,所以如果有人感兴趣,请回复此评论。
  • @KeithMiller 当然,我们总是对未记录的 shell 细节感兴趣。
  • 在这里查看我的回复:stackoverflow.com/questions/56451366/… 基本上,BagMRU 的数字命名值中的二进制值是构成数字对应子键的 IDL 的字节。您可以将它们链接在一起,删除除最终值之外的所有终止的两个空字节,并且您获得了完全限定的 IDL。当然,通常只有指针 PIDL 是在代码中传递的。但我想这种结构优化了属性包的查找。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多