共用方式為


如何實作 IContextMenu 介面

IContextMenu 是最強大的,也是實作最複雜的介面。 強烈建議您使用其中一個靜態動詞方法實作動詞。 如需詳細資訊,請參閱 選擇靜態或動態快捷方式功能表方法 IContextMenu 有三種方法:GetCommandStringInvokeCommand,以及 QueryContextMenu,這裡會詳細討論。

您需要知道的事項

技術

  • C++

先決條件

  • 靜態動詞
  • 捷徑選單

指示

IContextMenu::GetCommandString 方法

處理程式的 IContextMenu::GetCommandString 方法可用來傳回動詞的規範名稱。 這個方法是選擇性的。 在 Windows XP 和舊版 Windows 中,當 Windows 檔案總管具有狀態列時,這個方法會用來擷取功能表項 [狀態] 列中顯示的說明文字。

idCmd 參數會保存呼叫 IContextMenu::QueryContextMenu 時所定義的命令標識符位移。 如果要求說明字串,uFlags 會設定為 GCS_HELPTEXTW。 將幫助字串複製到 pszName 緩衝區,將其類型轉換為 PWSTR。 通過將 uFlags 設定為 GCS_VERBW來請求動詞字串。 將適當的字串複製到 pszName ,就像說明字串一樣。 快捷方式功能表處理程式不會使用 GCS_VALIDATEAGCS_VALIDATEW 旗標。

下列範例示範 GetCommandString 的簡單實作,其對應於本主題 IContextMenu::QueryContextMenu 方法 一節中提供的 QueryContextMenu 範例。 因為處理程式只會新增一個功能表項,因此只能傳回一組字串。 方法會測試 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 字串。

檢查 cbSize 成員在 pici 中,以判斷傳入哪一個結構。 如果它是 CMINVOKECOMMANDINFOEX 結構,且 fMask 成員已設定 CMIC_MASK_UNICODE 旗標,請將 pici 轉換成 CMINVOKECOMMANDINFOEX。 這可讓您的應用程式使用結構最後五個成員中包含的 Unicode 資訊。

結構的 lpVerblpVerbW 成員可用來識別要執行的命令。 下列兩種方式之一會識別命令:

  • 根據命令的動詞字串
  • 依命令的識別碼位移

若要區分這兩個案例,請檢查 ANSI 案例的 lpVerb 的高階字,或檢查 Unicode 案例的 lpVerbW 。 如果高階單字不是零字,lpVerblpVerbW 保留動詞字串。 如果高序字為零,則命令位移為低序字組,lpVerb

下列範例示範 IContextMenu::InvokeCommand 的簡單實作,其對應於本節前後提供的 IContextMenu::QueryContextMenu::QueryContextMenuIContextMenu::GetCommandString 範例。 方法會先決定傳入的是哪一個結構。 然後,它會判斷命令是由它的位移或動詞所識別。 如果 lpVerblpVerbW 保留有效的動詞或位移,則方法會顯示消息框。

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 方法

Shell 會呼叫 IContextMenu::QueryContextMenu,讓快捷方式功能表處理程式將其功能表項新增至功能表。 它會在 hmenu 參數中傳遞 HMENU 句柄。 indexMenu 參數會設定為要用於要加入之第一個功能表項的索引。

處理程式新增的任何功能表項都必須有標識符,這些標識碼落在 idCmdFirstidCmdLast 參數之間。 一般而言,第一個命令標識符會設定為 idCmdFirst,而此標識符針對每個額外的命令會增加一(1)。 這種做法可協助您避免超過 idCmdLast,並在 Shell 呼叫多個處理器時,確保有更多可用的識別碼。

項目標識碼的 命令位移 是標識碼與 idCmdFirst 中的值之間的差異。 儲存處理常式新增到捷徑選單的每個項目的偏移量,因為殼層在後續呼叫 IContextMenu::GetCommandStringIContextMenu::InvokeCommand時,可能會使用偏移量來識別該項目。

您也應該將 動詞 分配給您新增的每個命令。 在呼叫 InvokeCommand 時,動詞是一個字串,能用來代替位移來識別命令。 ShellExecuteEx等函式也用於執行捷徑選單命令。

有三個旗標可以透過與快捷方式功能表處理程式相關的 uFlags 參數傳入。 下表說明它們。

描述
CMF_DEFAULTONLY 用戶已選取預設命令,通常是按兩下物件。 IContextMenu::QueryContextMenu 應該將控制權傳回 Shell,而不需修改功能表。
CMF_NODEFAULT 選單中的任何項目都不應該是預設的項目。 方法應該將其命令加入選單。
CMF_NORMAL 快捷鍵選單會正常顯示。 方法應該將其命令新增至功能表。

 

使用 InsertMenuInsertMenuItem,將功能表項新增至清單。 然後傳回 HRESULT 值,並將嚴重性設定為 SEVERITY_SUCCESS。 將代碼值設定為已指派的最大命令識別符的位移量,再加上一(1)。 例如,假設 idCmdFirst 設定為 5,然後您將三個項目新增到功能表,這些項目的命令標識碼為 5、7 和 8。 傳回值應該是MAKE_HRESULT(SEVERITY_SUCCESS,0,8 + 1)。

下列範例示範插入單一命令的簡單 QueryContextMenu 實作。 命令的標識碼位移量為IDM_DISPLAY,且被設定為零。 m_pszVerbm_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));}

備註

如需其他動詞實作工作,請參閱 建立快捷方式功能表處理程式