IContextMenu インターフェイスを実装する方法

IContextMenu は最も強力ですが、実装する最も複雑なインターフェイスでもあります。 静的動詞メソッドのいずれかを使用して動詞を実装することを強くお勧めします。 詳細については、「 静的または動的ショートカット メニュー メソッドの選択」を参照してください。 IContextMenu には 、GetCommandStringInvokeCommandQueryContextMenu の 3 つのメソッドがあります。これについては、ここで詳しく説明します。

知っておくべきこと

テクノロジ

  • C++

前提条件

  • 静的動詞
  • ショートカット メニュー

Instructions

IContextMenu::GetCommandString メソッド

ハンドラーの IContextMenu::GetCommandString メソッドは、動詞の正規名を返すために使用されます。 このメソッドは省略可能です。 Windows XP 以前のバージョンの Windows では、Windows エクスプローラーにステータス バーがある場合、このメソッドを使用して、メニュー項目のステータス バーに表示されるヘルプ テキストを取得します。

idCmd パラメーターは、IContextMenu::QueryContextMenu が呼び出されたときに定義されたコマンドの識別子オフセットを保持します。 ヘルプ文字列が要求された場合、 uFlagsGCS_HELPTEXTW に設定されます。 ヘルプ文字列を pszName バッファーにコピーし、 PWSTR にキャストします。 動詞文字列は、 uFlags を GCS_VERBW に設定することによって要求 されます。 ヘルプ文字列と同様に、適切な文字列を pszName にコピーします。 GCS_VALIDATEAフラグとGCS_VALIDATEW フラグは、ショートカット メニュー ハンドラーでは使用されません。

次の例は、このトピックの「IContextMenu::QueryContextMenu メソッド」セクションにある QueryContextMenu の例に対応する GetCommandString の簡単な実装を示しています。 ハンドラーはメニュー項目を 1 つだけ追加するため、返すことができる文字列のセットは 1 つだけです。 メソッドは idCmd が有効かどうかをテストし、有効な場合は要求された文字列を返します。

StringCchCopy 関数を使用して、要求された文字列を pszName にコピーし、コピーした文字列が cchName で指定されたバッファーのサイズを超えないようにします。 この例では、uFlags の Unicode 値に対してのみサポートが実装されています。これは、Windows 2000 以降の Windows エクスプローラーで使用されている値のみであるためです。

IFACEMETHODIMP CMenuExtension::GetCommandString(UINT idCommand, 
                                                UINT uFlags, 
                                                UINT *pReserved, 
                                                PSTR pszName, 
                                                UINT cchName)
{
    HRESULT hr = E_INVALIDARG;

    if (idCommand == IDM_DISPLAY)
    {
        switch (uFlags)
        {
            case GCS_HELPTEXTW:
                // Only useful for pre-Vista versions of Windows that 
                // have a Status bar.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"Display File Name");
                break; 

            case GCS_VERBW:
                // GCS_VERBW is an optional feature that enables a caller
                // to discover the canonical name for the verb that is passed in
                // through idCommand.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"DisplayFileName");
                break; 
        }
    }
    return hr;
}

IContextMenu::InvokeCommand メソッド

このメソッドは、ユーザーがメニュー項目をクリックして、関連付けられたコマンドを実行するようにハンドラーに指示すると呼び出されます。 pici パラメーターは、コマンドの実行に必要な情報を含む構造体を指します。

pici は Shlobj.h で CMINVOKECOMMANDINFO 構造体として宣言されていますが、実際には CMINVOKECOMMANDINFOEX 構造体を指すことがよくあります。 この構造体は CMINVOKECOMMANDINFO の拡張バージョンであり、Unicode 文字列を渡すために追加のメンバーがいくつかあります。

picicbSize メンバーを調べて、渡された構造体を確認します。 CMINVOKECOMMANDINFOEX 構造体で、fMask メンバーに CMIC_MASK_UNICODE フラグが設定されている場合は、piciCMINVOKECOMMANDINFOEX にキャストします。 これにより、アプリケーションは構造体の最後の 5 つのメンバーに含まれる Unicode 情報を使用できます。

構造体の lpVerb または lpVerbW メンバーは、実行するコマンドを識別するために使用されます。 コマンドは、次の 2 つの方法のいずれかで識別されます。

  • コマンドの動詞文字列
  • コマンドの識別子オフセット

これら 2 つのケースを区別するには、ANSI ケースの場合は lpVerb、Unicode の場合は lpVerbW という高次ワードをチェックします。 上位ワードが 0 以外の場合、 lpVerb または lpVerbW は動詞文字列を保持します。 上位ワードが 0 の場合、コマンド オフセットは lpVerb の下位ワードになります。

次の例は、このセクションの前後に指定された IContextMenu::QueryContextMenu および IContextMenu::GetCommandString の例に対応する IContextMenu::InvokeCommand の簡単な実装を示しています。 メソッドは、最初に渡される構造体を決定します。 次に、コマンドがオフセットまたはその動詞によって識別されるかどうかを判断します。 lpVerb または lpVerbW が有効な動詞またはオフセットを保持している場合、メソッドはメッセージ ボックスを表示します。

STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
    BOOL fEx = FALSE;
    BOOL fUnicode = FALSE;

    if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
    {
        fEx = TRUE;
        if((lpcmi->fMask & CMIC_MASK_UNICODE))
        {
            fUnicode = TRUE;
        }
    }

    if( !fUnicode && HIWORD(lpcmi->lpVerb))
    {
        if(StrCmpIA(lpcmi->lpVerb, m_pszVerb))
        {
            return E_FAIL;
        }
    }

    else if( fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW))
    {
        if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb))
        {
            return E_FAIL;
        }
    }

    else if(LOWORD(lpcmi->lpVerb) != IDM_DISPLAY)
    {
        return E_FAIL;
    }

    else
    {
        MessageBox(lpcmi->hwnd,
                   "The File Name",
                   "File Name",
                   MB_OK|MB_ICONINFORMATION);
    }

    return S_OK;
}

IContextMenu::QueryContextMenu メソッド

シェルは IContextMenu::QueryContextMenu を呼び出して、ショートカット メニュー ハンドラーがメニューにメニュー項目を追加できるようにします。 hmenu パラメーターの HMENU ハンドルを渡します。 indexMenu パラメーターは、追加する最初のメニュー項目に使用するインデックスに設定されます。

ハンドラーによって追加されるメニュー項目には、 idCmdFirst パラメーターと idCmdLast パラメーターの値の間に含まれる識別子が必要です。 通常、最初のコマンド識別子は idCmdFirst に設定され、追加のコマンドごとに 1 ずつインクリメントされます。 この方法は 、idCmdLast を 超えないようにするのに役立ち、シェルが複数のハンドラーを呼び出した場合に使用できる識別子の数を最大化します。

項目識別子の コマンド オフセット は、 idCmdFirst 内の識別子と値の違いです。 ハンドラーがショートカット メニューに追加する各項目のオフセットを格納します。これは、その後 IContextMenu::GetCommandString または IContextMenu::InvokeCommand を呼び出す場合に、シェルがオフセットを使用して項目を識別する可能性があるためです。

また、追加する各コマンドに 動詞 を割り当てる必要もあります。 動詞は、 InvokeCommand が呼び出されたときにコマンドを識別するためにオフセットの代わりに使用できる文字列です。 また、 ShellExecuteEx などの関数でショートカット メニュー コマンドを実行するためにも使用されます。

ショートカット メニュー ハンドラーに関連する uFlags パラメーターを介して渡すことができる 3 つのフラグがあります。 これらについては、次の表で説明します。

フラグ 説明
CMF_DEFAULTONLY ユーザーは既定のコマンドを選択しました。通常は、 オブジェクトをダブルクリックします。 IContextMenu::QueryContextMenu は、メニューを変更せずにシェルにコントロールを返す必要があります。
CMF_NODEFAULT メニュー内の項目を既定の項目にすることはできません。 メソッドは、そのコマンドをメニューに追加する必要があります。
CMF_NORMAL ショートカット メニューが正常に表示されます。 メソッドは、そのコマンドをメニューに追加する必要があります。

 

リストにメニュー項目を追加するには、 InsertMenu または InsertMenuItem を使用します。 次に、重大度が SEVERITY_SUCCESS に設定された HRESULT 値を返します。 コード値を、割り当てられた最大のコマンド識別子のオフセットに 1 を加えた値に設定します。 たとえば、 idCmdFirst が 5 に設定されていて、コマンド識別子が 5、7、8 の 3 つの項目をメニューに追加するとします。 戻り値は MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 + 1) にする必要があります。

次の例は、1 つのコマンドを挿入する QueryContextMenu の簡単な実装を示しています。 コマンドの識別子オフセットがIDM_DISPLAYされ、0 に設定されます。 m_pszVerb変数とm_pwszVerb変数は、関連付けられた言語に依存しない動詞文字列を ANSI 形式と Unicode 形式の両方で格納するために使用されるプライベート変数です。

#define IDM_DISPLAY 0

STDMETHODIMP CMenuExtension::QueryContextMenu(HMENU hMenu,
                                              UINT indexMenu,
                                              UINT idCmdFirst,
                                              UINT idCmdLast,
                                              UINT uFlags)
{
    HRESULT hr;
    
    if(!(CMF_DEFAULTONLY & uFlags))
    {
        InsertMenu(hMenu, 
                   indexMenu, 
                   MF_STRING | MF_BYPOSITION, 
                   idCmdFirst + IDM_DISPLAY, 
                   "&Display File Name");

    
        
        hr = StringCbCopyA(m_pszVerb, sizeof(m_pszVerb), "display");
        hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"display");

        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_DISPLAY + 1));
    }

    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));}

注釈

その他の動詞実装タスクについては、「 ショートカット メニュー ハンドラーの作成」を参照してください。