Share via


Comment implémenter l’interface IContextMenu

IContextMenu est l’interface la plus puissante, mais aussi la plus complexe à implémenter. Nous vous recommandons vivement d’implémenter un verbe à l’aide de l’une des méthodes de verbe statique. Pour plus d’informations, consultez Choix d’une méthode de menu contextuel statique ou dynamique. IContextMenu a trois méthodes, GetCommandString, InvokeCommand et QueryContextMenu, qui sont décrites ici en détail.

Bon à savoir

Technologies

  • C++

Prérequis

  • Verbe statique
  • Menu contextuel

Instructions

IContextMenu::GetCommandString, méthode

La méthode IContextMenu::GetCommandString du gestionnaire est utilisée pour renvoyer le nom canonique d’un verbe. Cette méthode est facultative. Dans Windows XP et les versions antérieures de Windows, lorsque Windows Explorer a une barre d’état, cette méthode est utilisée pour récupérer le texte d’aide affiché dans la barre d’état d’un élément de menu.

Le paramètre idCmd contient le décalage de l’identificateur de la commande qui a été définie lorsque IContextMenu::QueryContextMenu a été appelé. Si une chaîne d’aide est demandée, uFlags est défini sur GCS_HELPTEXTW. Copiez la chaîne d’aide dans la mémoire tampon pszName en la castant en PWSTR. La chaîne verbale est demandée en définissant uFlagssur GCS_VERBW. Copiez la chaîne appropriée dans pszName, comme avec la chaîne d’aide. Les indicateurs GCS_VALIDATEA et GCS_VALIDATEW ne sont pas utilisés par les gestionnaires de menus contextuels.

L’exemple suivant montre une implémentation simple de GetCommandString qui correspond à l’exemple QueryContextMenu donné dans la section IContextMenu::QueryContextMenu, méthode de cette rubrique. Étant donné que le gestionnaire ajoute un seul élément de menu, il n’y a qu’un seul ensemble de chaînes qui peut être retourné. La méthode teste si idCmd est valide et, le cas échéant, retourne la chaîne demandée.

La fonction StringCchCopy permet de copier la chaîne demandée dans pszName afin de s’assurer que la chaîne copiée ne dépasse pas la taille de la mémoire tampon spécifiée par cchName. Cet exemple implémente la prise en charge uniquement des valeurs Unicode des uFlags, car seules celles-ci ont été utilisées dans Windows Explorer depuis 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, méthode

Cette méthode est appelée lorsqu’un utilisateur clique sur un élément de menu pour indiquer au gestionnaire d’exécuter la commande associée. Le paramètre pici pointe vers une structure qui contient les informations requises pour exécuter la commande.

Bien que pici soit déclaré dans Shlobj.h en tant que structure CMINVOKECOMMANDINFO , dans la pratique, il pointe souvent vers une structure CMINVOKECOMMANDINFOEX . Cette structure est une version étendue de CMINVOKECOMMANDINFO et a plusieurs membres supplémentaires qui permettent de passer des chaînes Unicode.

Vérifiez le membre cbSize de pici pour déterminer la structure qui a été passée. S’il s’agit d’une structure CMINVOKECOMMANDINFOEX et que le membre fMask a l’indicateur CMIC_MASK_UNICODE défini, cast pici en CMINVOKECOMMANDINFOEX. Cela permet à votre application d’utiliser les informations Unicode contenues dans les cinq derniers membres de la structure.

Le membre lpVerb ou lpVerbW de la structure est utilisé pour identifier la commande à exécuter. Les commandes sont identifiées de l’une des deux manières suivantes :

  • Par la chaîne de verbe de la commande
  • Par décalage de l’identificateur de la commande

Pour faire la distinction entre ces deux cas, case activée le mot d’ordre supérieur lpVerb pour le cas ANSI ou lpVerbW pour le cas Unicode. Si le mot d’ordre supérieur est différent de zéro, lpVerb ou lpVerbW contient une chaîne de verbe. Si le mot d’ordre supérieur est égal à zéro, le décalage de commande est dans le mot d’ordre inférieur de lpVerb.

L’exemple suivant montre une implémentation simple de IContextMenu::InvokeCommand qui correspond aux exemples IContextMenu::QueryContextMenu et IContextMenu::GetCommandString donnés avant et après cette section. La méthode détermine d’abord quelle structure est passée. Il détermine ensuite si la commande est identifiée par son décalage ou son verbe. Si lpVerb ou lpVerbW contient un verbe ou un décalage valide, la méthode affiche une boîte de message.

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, méthode

L’interpréteur de commandes appelle IContextMenu::QueryContextMenu pour permettre au gestionnaire de menu contextuel d’ajouter ses éléments de menu au menu. Il passe le handle HMENU dans le paramètre hmenu . Le paramètre indexMenu est défini sur l’index à utiliser pour le premier élément de menu à ajouter.

Tous les éléments de menu ajoutés par le gestionnaire doivent avoir des identificateurs qui se situent entre les valeurs des paramètres idCmdFirst et idCmdLast . En règle générale, le premier identificateur de commande est défini sur idCmdFirst, qui est incrémenté d’un (1) pour chaque commande supplémentaire. Cette pratique vous permet d’éviter de dépasser idCmdLast et d’optimiser le nombre d’identificateurs disponibles au cas où l’interpréteur de commandes appelle plusieurs gestionnaires.

Le décalage de commande d’un identificateur d’élément est la différence entre l’identificateur et la valeur dans idCmdFirst. Stockez le décalage de chaque élément que votre gestionnaire ajoute au menu contextuel, car l’interpréteur de commandes peut utiliser le décalage pour identifier l’élément s’il appelle ensuite IContextMenu::GetCommandString ou IContextMenu::InvokeCommand.

Vous devez également affecter un verbe à chaque commande que vous ajoutez. Un verbe est une chaîne qui peut être utilisée à la place du décalage pour identifier la commande lorsque InvokeCommand est appelé. Il est également utilisé par des fonctions telles que ShellExecuteEx pour exécuter des commandes de menu contextuel.

Il existe trois indicateurs qui peuvent être transmis via le paramètre uFlags qui sont pertinents pour les gestionnaires de menus contextuels. Ils sont décrits dans le tableau suivant.

Indicateur Description
CMF_DEFAULTONLY L’utilisateur a sélectionné la commande par défaut, généralement en double-cliquant sur l’objet . IContextMenu::QueryContextMenu doit retourner le contrôle à l’interpréteur de commandes sans modifier le menu.
CMF_NODEFAULT Aucun élément du menu ne doit être l’élément par défaut. La méthode doit ajouter ses commandes au menu.
CMF_NORMAL Le menu contextuel s’affiche normalement. La méthode doit ajouter ses commandes au menu.

 

Utilisez InsertMenu ou InsertMenuItem pour ajouter des éléments de menu à la liste. Retournez ensuite une valeur HRESULT dont la gravité est définie sur SEVERITY_SUCCESS. Définissez la valeur de code sur le décalage du plus grand identificateur de commande affecté, plus un (1). Par exemple, supposons que idCmdFirst est défini sur 5 et que vous ajoutez trois éléments au menu avec des identificateurs de commande de 5, 7 et 8. La valeur de retour doit être MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 + 1).

L’exemple suivant montre une implémentation simple de QueryContextMenu qui insère une seule commande. Le décalage de l’identificateur pour la commande est IDM_DISPLAY, qui est défini sur zéro. Les variables m_pszVerb et m_pwszVerb sont des variables privées utilisées pour stocker la chaîne de verbe indépendante du langage associée aux formats ANSI et 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));}

Notes

Pour d’autres tâches d’implémentation de verbes, consultez Création de gestionnaires de menu contextuel.