当然有一种方法可以获得当前文件夹视图的完整View下拉菜单?

时间:2009-12-02 23:27:48

标签: c++ com winapi windows-shell

动机:创建我们自己的文件对话框,其中包含&行为很像std常用对话框

问题:如何获取当前文件夹/ shell容器的视图下拉列表

明显的死亡结束:

  • 查询IShellFolder的IContextMenu < NULL接口指针。
  • 查询IShellView的IContextMenu < NULL接口指针。
  • IShellFolder :: CreateViewObject(IID_IContextMenu ...) <非常有限的上下文菜单(新)。
  • IShellFolder :: GetUIObjectOf(IID_IContextMenu ...) <有限的上下文菜单(打开,探索,......)。
  • 实施IShellBrowser的InsertMenusSB,RemoveMenusSB和SetMenuSB <菜单从未填充超出我用
  • 填充的菜单

我花了一些时间阅读Implementing a Folder ViewHow to host an IContextMenu。这似乎表明上面的最终方法(实现InsertMenuSB,......)应该有效。 IShellView应该使用适当的项填充IShellBrowser的共享菜单,包括其View子菜单。然而,到目前为止,我从中得到的只是一个空菜单(除非我用项填充它 - 在这种情况下,我只是得到我填充它的项目。)

当然有办法做到这一点。 Windows资源管理器从某处到达它显示的菜单(如果您在Vista或更高版本上按下ALT)。而且我无法想象这个菜单是由资源管理器本身静态构建的 - 它肯定是以与当前显示的IShellView一致的方式动态创建的,以允许shell扩展显示正确的视图选项列表(以及其他菜单选项)。

InsertMenuSB RemoveMenuSB SetMenuSB 的文档令人困惑。它似乎表明,作为容器服务器,我应该在元素0,2和4中填充提供的 OLEMENUGROUPWIDTHS “以反映它在文件中提供的菜单元素的数量,查看和窗口菜单组。“

我已实施以下措施以尝试正确履行此合同:

HRESULT STDMETHODCALLTYPE ShellBrowserDlgImpl::InsertMenusSB(__RPC__in HMENU hmenuShared, /* [out][in] */ __RPC__inout LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
    TRACE("IShellBrowser::InsertMenusSB\n");

    // insert our main pull-downs
    struct  
    {
        UINT    id;
        LPCTSTR label;
    } pull_downs[] = {
        { FCIDM_MENU_FILE, "File" },
        { FCIDM_MENU_EDIT, "Edit" },
        { FCIDM_MENU_VIEW, "View" },
        { FCIDM_MENU_TOOLS, "Tools" },
        { FCIDM_MENU_HELP, "Help" },
    };
    for (size_t i = 0; i < countof(pull_downs); ++i)
    {
        VERIFY(AppendMenu(hmenuShared, MF_POPUP, pull_downs[i].id, pull_downs[i].label));
        ASSERT(GetMenuItemID(hmenuShared, i) == pull_downs[i].id);
    }

    // set the count of menu items we've inserted into each *group*
    lpMenuWidths->width[0] = 2; // FILE: File, Edit
    lpMenuWidths->width[2] = 2; // VIEW: View, Tools
    lpMenuWidths->width[4] = 1; // WINDOW: Help

    return S_OK;
}

是否有人实施过类似资源管理器的项目,将当前的IShellView菜单正确公开给最终用户?

是否有关于 IOLEInPlaceFrame 实施的文档/示例可能会对这个阴暗的主题有所了解?

哎呀!@ - 我觉得我必须亲近 - 但还不够近!

3 个答案:

答案 0 :(得分:3)

使用SVGIO_BACKGROUND获取文件夹的背景菜单,该文件夹应具有视图子菜单。 “视图”菜单项的索引,名称和命令ID可能因Windows版本和本地语言而异,因此这是一种黑客行为。

答案 1 :(得分:1)

对于那些可能感兴趣的人,这里是我正在使用的给定答案的实现:

void ShellBrowserDlgImpl::ViewModeDropDown(const CPoint & pt)
{
    // ask the view for its context menu interface
    CComPtr<IContextMenu> pcm;
    if (FAILED(m_hresult = m_shell_view->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pcm))) || !pcm)
        throw CLabeledException("Unable to query the context menu interface from the shell view: ");

    // create a blank menu to store it in
    CMenu menu;
    if (!menu.CreateMenu())
        throw CContextException("Unable to create an empty menu in which to store the context menu: ");

    // populate the context menu
    if (FAILED(m_hresult = pcm->QueryContextMenu(menu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_NORMAL)))
        throw CLabeledException("Unable to query the context menu for the current folder");

    // obtain the "view" submenu to use as our drop-down menu
    //HACK: we assume that the view pop-up is the first entry (true in English)
    //TODO: We need some way to scan for the correct submenu
    // if we knew of a given command that exists under view - we could FindMenuContaining()
    // of if we could scan for an invariant command name using a similar technique
    // or we could possibly...?
    CMenu * pViewMenu = menu.GetSubMenu(0);

    // get the proper orientation for the drop-menu
    UINT uFlags = ::GetSystemMetrics(SM_MENUDROPALIGNMENT) ? TPM_RIGHTALIGN|TPM_HORNEGANIMATION : TPM_LEFTALIGN|TPM_HORPOSANIMATION;

    // display the menu to the user
    BOOL nCmdID = ::TrackPopupMenu(*pViewMenu, TPM_RETURNCMD|uFlags, pt.x, pt.y, 0, m_shell_view_hwnd, NULL);

    // check if the user canceled the menu
    if (!nCmdID)
        return;

    // create the command to execute
    CMINVOKECOMMANDINFO ici = {0};
    ici.cbSize = sizeof(ici);
    ici.hwnd = m_shell_view_hwnd;
    ici.lpVerb = MAKEINTRESOURCE(nCmdID-1); //NOTE: not sure if the -1 is due to the position of the submenu we're pulling out, or something else - might be invalid for other OSes or languages
    if (FAILED(m_hresult = pcm->InvokeCommand(&ici)))
        throw CLabeledException("Unable to execute your command");
}

答案 2 :(得分:0)

你正在重新实现一个众所周知的难以控制的控制权,以及许多人在开始使用Windows之后知道并使用过的控件。任何未能完全正确的操作都会使至少某些用户的子集烦恼,并且“完全正确”的定义将从Windows版本更改为Windows版本。

为什么你不能使用默认的?您正在实施什么,为这个对话框增加了很多价值,以至于无法使用标准的对话框?