Наверняка есть способ получить полное представление View для текущей папки? - PullRequest
2 голосов
/ 03 декабря 2009

Мотивация: Создание нашего собственного файлового диалога, который выглядит и действует как стандартный диалог * std

Проблема: Как получить раскрывающийся список для текущей папки / контейнера оболочки

Видимые Мертвые концы:

  • Запросите IShellFolder для его IContextMenu
  • Запросите IShellView для его IContextMenu
  • IShellFolder :: CreateViewObject (IID_IContextMenu ...) <очень ограниченное контекстное меню (новое). </em>
  • IShellFolder :: GetUIObjectOf (IID_IContextMenu ...) <ограниченное контекстное меню (открыть, исследовать, ...). </em>
  • Реализация IShellBrowser InsertMenusSB, RemoveMenusSB и SetMenuSB <Меню никогда не заполняется сверх того, что я заполняю с помощью </em>

Я потратил некоторое время на чтение Реализация представления папок и Как разместить IContextMenu . Кажется, это указывает на то, что последний подход (реализация InsertMenuSB, ...) должен работать. IShellView должен заполнять общее меню для IShellBrowser, включая его подменю View, соответствующими элементами. Однако, пока все, что я получаю от этого, - пустое меню (если я не заполняю его элементами - в этом случае, я просто получаю элементы, которые заполняю его).

Конечно, есть способ сделать это. Проводник Windows появляется в меню, которое он отображает (если вы нажмете ALT в Vista или выше) откуда-то. И я не могу себе представить, что это меню статически создается самим проводником - оно, безусловно, динамически каким-то образом создается вместе с отображаемым в настоящее время IShellView, чтобы расширения оболочки отображали правильный список параметров просмотра (и других параметров меню).

Но документация по InsertMenuSB , RemoveMenuSB и SetMenuSB сбивает с толку. Кажется, это указывает на то, что, как сервер-контейнер, я должен заполнить предоставленные OLEMENUGROUPWIDTHS , "в элементах 0, 2 и 4, чтобы отразить количество элементов меню, предоставленных в File, View и группы меню Window. "

Я реализовал следующее, чтобы попытаться правильно выполнить этот контракт:

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;
}

Кто-нибудь реализовал проект, подобный Explorer, который правильно отображает текущие меню IShellView для конечного пользователя?

Есть ли документация / примеры по IOLEInPlaceFrame реализациям, которые могут пролить свет на эту мутную тему?

Тьфу! @ - Я чувствую, что должен быть близко - но недостаточно близко!

Ответы [ 3 ]

3 голосов
/ 03 декабря 2009

используйте SVGIO_BACKGROUND, чтобы получить фоновое меню папки, которое должно иметь подменю вида.индекс, имя и идентификатор команды пункта меню «просмотр» могут различаться в зависимости от версии Windows и местных языков, так что это своего рода хак.

1 голос
/ 03 декабря 2009

Для тех, кто может быть заинтересован, вот реализация данного ответа, который я использую:

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");
}
0 голосов
/ 03 декабря 2009

Вы повторно реализуете заведомо сложный элемент управления, чтобы получить право, и тот, который многие, многие люди знают и используют с тех пор, как начали использовать Windows. Любая неудача в получении правильного результата будет раздражать, по крайней мере, некоторое подмножество ваших пользователей, и определение «совершенно правильное» изменится с выпуска Windows на выпуск Windows.

Почему вы не можете использовать по умолчанию? Что вы реализуете, что добавляет этому диалогу настолько большую ценность, что его невозможно использовать стандартным?

...