Поделиться через


Реализация интерфейса IContextMenu

IContextMenu — это самый мощный, но и самый сложный интерфейс для реализации. Настоятельно рекомендуется реализовать глагол с помощью одного из методов статических команд. Дополнительные сведения см. в разделе Выбор статического или динамического метода контекстного меню. В IContextMenu есть три метода: GetCommandString, InvokeCommand и QueryContextMenu, которые подробно рассматриваются здесь.

Это важно знать

Технологии

  • C++

Предварительные требования

  • Статический глагол
  • Контекстное меню

Инструкции

Метод IContextMenu::GetCommandString

Метод IContextMenu::GetCommandString обработчика используется для возврата канонического имени команды. Этот метод является необязательным. В Windows XP и более ранних версиях Windows, когда в Windows Обозреватель есть строка состояния, этот метод используется для получения текста справки, отображаемого в строке состояния для пункта меню.

Параметр idCmd содержит смещение идентификатора команды, которая была определена при вызове IContextMenu::QueryContextMenu . Если запрашивается строка справки, для uFlags будет задано значение GCS_HELPTEXTW. Скопируйте строку справки в буфер pszName и приведите ее к PWSTR. Строка команды запрашивается путем установки uFlagsGCS_VERBW. Скопируйте соответствующую строку в pszName, как и в случае со строкой справки. Флаги GCS_VALIDATEA и GCS_VALIDATEW не используются обработчиками контекстного меню.

В следующем примере показана простая реализация GetCommandString , соответствующая примеру QueryContextMenu , приведенному в разделе Метод IContextMenu::QueryContextMenu этого раздела. Так как обработчик добавляет только один пункт меню, существует только один набор строк, которые могут быть возвращены. Метод проверяет, является ли idCmd допустимым , и, если это так, возвращает запрошенную строку.

Функция StringCchCopy используется для копирования запрошенной строки в pszName , чтобы убедиться, что скопированная строка не превышает размер буфера, заданного параметром cchName. В этом примере реализована поддержка только для значений Юникода uFlags, так как только они используются в Windows Обозреватель начиная с Windows 2000.

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 и содержит несколько дополнительных элементов, которые позволяют передавать строки Юникода.

Проверьте элемент cbSizeв pici , чтобы определить, какая структура была передана. Если это структура CMINVOKECOMMANDINFOEX и для элемента fMask установлен флаг CMIC_MASK_UNICODE , приведите pici к CMINVOKECOMMANDINFOEX. Это позволяет приложению использовать сведения Юникода, содержащиеся в последних пяти элементах структуры.

Элемент lpVerb или lpVerbW структуры используется для идентификации выполняемой команды. Команды определяются одним из следующих двух способов:

  • По строке команды
  • По смещению идентификатора команды

Чтобы различать эти два случая, проверка слово высокого порядка lpVerb для варианта ANSI или lpVerbW для дела Юникода. Если слово высокого порядка не равно нулю, lpVerb или lpVerbW содержит строку глагола. Если слово высокого порядка равно нулю, смещение команды будет в нижнем порядке в слове lpVerb.

В следующем примере показана простая реализация IContextMenu::InvokeCommand , которая соответствует примерам IContextMenu::QueryContextMenu и IContextMenu::GetCommandString , приведенным до и после этого раздела. Сначала метод определяет, какая структура передается. Затем он определяет, определяется ли команда по смещению или по ее команде. Если 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 , которые относятся к обработчикам контекстного меню. Они описаны в следующей таблице.

Flag Описание
CMF_DEFAULTONLY Пользователь выбрал команду по умолчанию, обычно дважды щелкнув объект . IContextMenu::QueryContextMenu должен возвращать управление оболочке без изменения меню.
CMF_NODEFAULT Ни один элемент в меню не должен быть элементом по умолчанию. Метод должен добавить свои команды в меню.
CMF_NORMAL Контекстное меню будет отображаться в обычном режиме. Метод должен добавить свои команды в меню.

 

Используйте insertMenu или InsertMenuItem для добавления пунктов меню в список. Затем верните значение HRESULT с уровнем серьезности, равным SEVERITY_SUCCESS. Задайте для значения кода смещение максимального назначенного идентификатора команды плюс один (1). Например, предположим, что idCmdFirst имеет значение 5 и вы добавляете в меню три элемента с идентификаторами команд 5, 7 и 8. Возвращаемое значение должно быть MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 + 1).

В следующем примере показана простая реализация QueryContextMenu , которая вставляет одну команду. Смещение идентификатора для команды IDM_DISPLAY, для которого задано значение 0. Переменные m_pszVerb и m_pwszVerb являются частными переменными, которые используются для хранения связанной независимой от языка строки глаголов в форматах ANSI и Юникоде.

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

Комментарии

Сведения о других задачах реализации команд см. в разделе Создание обработчиков контекстного меню.