2

動機: std コモン ダイアログによく似た外観と動作をする独自のファイル ダイアログを作成する

問題:現在のフォルダー/シェル コンテナーのビュー プルダウンを取得する方法

明らかな行き止まり:

  • IContextMenu < NULL インターフェイス ポインターの IShellFolder をクエリします。
  • IContextMenu < NULL インターフェイス ポインターの IShellView をクエリします。
  • IShellFolder::CreateViewObject(IID_IContextMenu...) < 非常に限られたコンテキスト メニュー (新規)。
  • IShellFolder::GetUIObjectOf(IID_IContextMenu...) < 限定されたコンテキスト メニュー (開く、探索する...)。
  • IShellBrowser の InsertMenusSB、RemoveMenusSB、および SetMenuSB を実装する

私は、Folder View の実装IContextMenu をホストする方法を読むのに時間を費やしました。これは、上記の最終的なアプローチ (InsertMenuSB の実装など) が機能することを示しているようです。IShellView は、View サブメニューを含む IShellBrowser の共有メニューに適切な項目を設定する必要があります。ただし、これまでのところ、そこから得られるのは空のメニューだけです (アイテムを入力しない限り、その場合は、入力したアイテムを取得するだけです)。

確かにこれを行う方法があります。Windows エクスプローラーは、(Vista 以降で Alt キーを押した場合) 表示されるメニューにどこかから到着します。そして、このメニューがエクスプローラー自体によって静的に構築されているとは想像できません。現在表示されている IShellView と連携して何らかの形で動的に作成され、シェル拡張機能がビュー オプション (およびその他のメニュー オプション) の正しいリストを表示できるようになっていることは確かです。

しかし、InsertMenuSBRemoveMenuSB、およびSetMenuSBに関するドキュメントは紛らわしいです。コンテナー サーバーとして、提供されたOLEMENUGROUPWIDTHS"ファイル、ビュー、およびウィンドウ メニュー グループで提供されるメニュー要素の数を反映するために、要素 0、2、および 4 に" 設定する必要があることを示しているようです。

この契約を適切に履行するために、次のことを実装しました。

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 のメニューをエンドユーザーに適切に公開する Explorer のようなプロジェクトを実装した人はいますか?

このあいまいな主題に光を当てる可能性のあるIOLEInPlaceFrame実装に関するドキュメント/例はありますか?

うーん!@ - 近くにいるに違いない気がしますが、まだ十分ではありません!

4

3 に答える 3

3

SVGIO_BACKGROUNDを使用して、フォルダーのバックグラウンドメニューを取得します。このメニューには、ビューサブメニューが必要です。「表示」メニュー項目のインデックス、名前、およびコマンドIDは、Windowsのバージョンとローカル言語によって異なる場合があるため、これは一種のハックです。

于 2009-12-03T03:21:27.953 に答える
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");
}
于 2009-12-03T16:52:53.217 に答える
0

Windows を使い始めて以来、非常に多くの人が知っていて使用してきたコントロールを正しく実装するのが難しいことで有名なコントロールを再実装しようとしています。それを正確に正しく行わないと、少なくとも一部のユーザーを悩ませることになり、「正確に正しい」という定義は、Windows リリースごとに変更されます。

デフォルトのものを使用できないのはなぜですか?このダイアログに非常に多くの価値を追加して、標準のダイアログを使用できないものを実装していますか?

于 2009-12-02T23:40:36.550 に答える