动机:创建我们自己的文件对话框,其中包含&行为很像std常用对话框
问题:如何获取当前文件夹/ shell容器的视图下拉列表
明显的死亡结束:
我花了一些时间阅读Implementing a Folder View和How 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 实施的文档/示例可能会对这个阴暗的主题有所了解?
哎呀!@ - 我觉得我必须亲近 - 但还不够近!答案 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版本。
为什么你不能使用默认的?您正在实施什么,为这个对话框增加了很多价值,以至于无法使用标准的对话框?