2009-12-02 59 views
2

动机:创建自己的文件对话框,看起来&行为很像常见的性病对话框当然有一种方法可以获取当前文件夹视图的完整视图下拉菜单吗?

问题:如何获取当前文件夹/壳容器

视图下拉表观死角:

  • 查询的IShellFol der为其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键)。我无法想象这个菜单是由Explorer本身静态构建的 - 它肯定会以某种方式与当前显示的IShellView一起动态创建,以允许外壳扩展显示正确的视图选项列表(以及其他菜单选项)。

但在InsertMenuSBRemoveMenuSB,并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

使用SVGIO_BACKGROUND来获取文件夹的后台菜单,该文件夹应该有一个视图子菜单。 “视图”菜单项的索引,名称和命令ID在Windows版本和本地语言之间可能会有所不同,所以这是一种破解。

+0

我不认为你有任何关于如何确保我可以获得视图子菜单的想法,无论我在哪个操作系统下运行(包括版本和语言)。 – Mordachai 2009-12-03 16:48:14

+0

在Windows的英文版中,您可以搜索其文本为“查看”的子菜单,并希望Microsoft以后不会将其更改为其他内容。我怀疑微软会很快改变它,但这仍然是无证的行为。 – 2009-12-03 19:42:03

0

您正在重新实现一个众所周知的难以控制的问题,以及许多许多人知道并在开始使用Windows之后使用过的控件。任何未能完全正确地使用它都会引起至少一部分用户恼火,并且'完全正确'的定义将从Windows版本改为Windows版本。

为什么你不能使用默认的?你在实施什么,为这个对话增加了如此多的价值,以至于标准的一个是不可能使用的?

+0

我希望我们能与标准的一棒。我们的应用程序提供了增强型地点栏,专有文件预览窗格以及更常见的文件对话框自定义。从Vista开始,微软当然改变了自定义和使用文件对话框的方式,该界面排除了我们增强的地方栏和我们专有的预览窗格。该接口进一步限制为Vista +,并且我们必须保持2K兼容性。但是,如果我们使用针对2K和XP的老化定制方法,我们的对话框将失败。完整的解释超出了这个范围。 – Mordachai 2009-12-03 00:02:05

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"); 
} 
相关问题