Implementieren der IContextMenu-Schnittstelle

IContextMenu ist die leistungsfähigste, aber auch die komplizierteste Zu implementierende Schnittstelle. Es wird dringend empfohlen, ein Verb mithilfe einer der statischen Verbmethoden zu implementieren. Weitere Informationen finden Sie unter Auswählen einer statischen oder dynamischen Kontextmenümethode. IContextMenu verfügt über drei Methoden, GetCommandString, InvokeCommandund QueryContextMenu,die hier ausführlich erläutert werden.

Wichtige Informationen

Technologien

  • C++

Voraussetzungen

  • Statisches Verb
  • Kontextmenü

Anweisungen

IContextMenu::GetCommandString-Methode

Die IContextMenu::GetCommandString-Methode des Handlers wird verwendet, um den kanonischen Namen für ein Verb zurück zu geben. Diese Methode ist optional. Wenn Windows XP und frühere Versionen von Windows Windows über eine Statusleiste verfügt, wird diese Methode verwendet, um den Hilfetext abzurufen, der in der Statusleiste für ein Menüelement angezeigt wird.

Der idCmd-Parameter enthält den Bezeichneroffset des Befehls, der beim Aufrufen von IContextMenu::QueryContextMenu definiert wurde. Wenn eine Hilfezeichenfolge angefordert wird, werden uFlags auf GCS _ HELPTEXTW festgelegt. Kopieren Sie die Hilfezeichenfolge in den Puffer pszName, und geben Sie sie in pwstr um. Die Verbzeichenfolge wird durch Festlegen von uFlags auf GCS _ VERBW angefordert. Kopieren Sie die entsprechende Zeichenfolge wie bei der Hilfezeichenfolge in pszName. Die GCS _ VALIDATEA- und GCS _ VALIDATEW-Flags werden nicht von Kontextmenühandlern verwendet.

Das folgende Beispiel zeigt eine einfache Implementierung von GetCommandString, die dem QueryContextMenu-Beispiel entspricht, das im Abschnitt IContextMenu::QueryContextMenu-Methode dieses Themas angegeben ist. Da der Handler nur ein Menüelement hinzufügt, kann nur ein Satz von Zeichenfolgen zurückgegeben werden. Die -Methode testet, ob idCmd gültig ist, und gibt die angeforderte Zeichenfolge zurück.

Die StringCchCopy-Funktion wird verwendet, um die angeforderte Zeichenfolge in pszName zu kopieren, um sicherzustellen, dass die kopierte Zeichenfolge nicht die größe des puffers überschreitet, die von cchName angegeben wird. In diesem Beispiel wird die Unterstützung nur für die Unicode-Werte von uFlags implementiert, da seit Windows 2000 nur diese im Windows-Explorer verwendet wurden.

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-Methode

Diese Methode wird aufgerufen, wenn ein Benutzer auf ein Menüelement klickt, um den Handler anweise, den zugeordneten Befehl auszuführen. Der pici-Parameter verweist auf eine -Struktur, die die informationen enthält, die zum Ausführen des Befehls erforderlich sind.

Obwohl pici in Shlobj.h als CMINVOKECOMMANDINFO-Struktur deklariert ist, verweist sie in der Praxis häufig auf eine CMINVOKECOMMANDINFOEX-Struktur. Diese Struktur ist eine erweiterte Version von CMINVOKECOMMANDINFO und verfügt über mehrere zusätzliche Member, die es ermöglichen, Unicode-Zeichenfolgen zu übergeben.

Überprüfen Sie das cbSize-Member von pici, um zu bestimmen, welche Struktur übergeben wurde. Wenn es sich um eine CMINVOKECOMMANDINFOEX-Struktur handelt und für das fMask-Element das UNICODE-Flag CMIC _ MASK _ festgelegt ist, cast pici in CMINVOKECOMMANDINFOEX. Dadurch kann Ihre Anwendung die Unicode-Informationen verwenden, die in den letzten fünf Membern der -Struktur enthalten sind.

Der lpVerb- oder lpVerbW-Member der -Struktur wird verwendet, um den auszuführenden Befehl zu identifizieren. Befehle werden auf eine der beiden folgenden Arten identifiziert:

  • Durch die Verbzeichenfolge des Befehls
  • Durch den Bezeichneroffset des Befehls

Um zwischen diesen beiden Fällen zu unterscheiden, überprüfen Sie das obere Wort lpVerb für den ANSI-Fall oder lpVerbW für den Unicode-Fall. Wenn das hohe Wort ungleich null ist, enthält lpVerb oder lpVerbW eine Verbzeichenfolge. Wenn das hohe Wort 0 (null) ist, befindet sich der Befehlsoffset im niedrig geordneten Wort lpVerb.

Das folgende Beispiel zeigt eine einfache Implementierung von IContextMenu::InvokeCommand, die den Beispielen IContextMenu::QueryContextMenu und IContextMenu::GetCommandString entspricht, die vor und nach diesem Abschnitt angegeben wurden. Die -Methode bestimmt zuerst, welche Struktur übergeben wird. Anschließend wird bestimmt, ob der Befehl durch seinen Offset oder sein Verb identifiziert wird. Wenn lpVerb oder lpVerbW ein gültiges Verb oder offset enthält, zeigt die Methode ein Meldungsfeld an.

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-Methode

Die Shell ruft IContextMenu::QueryContextMenu auf, um dem Kontextmenühandler das Hinzufügen seiner Menüelemente zum Menü zu ermöglichen. Er übergibt das HMENU-Handle im hmenu-Parameter. Der indexMenu-Parameter wird auf den Index festgelegt, der für das erste Menüelement verwendet werden soll, das hinzugefügt werden soll.

Alle Vom Handler hinzugefügten Menüelemente müssen über Bezeichner verfügen, die zwischen den Werten in den Parametern idCmdFirst und idCmdLast liegen. In der Regel wird der erste Befehlsbezeichner auf idCmdFirst festgelegt, der für jeden zusätzlichen Befehl um eins (1) erhöht wird. Diese Vorgehensweise hilft Ihnen, eine Überschreitung von idCmdLast zu vermeiden, und maximiert die Anzahl der verfügbaren Bezeichner, falls die Shell mehr als einen Handler aufruft.

Der Befehlsoffset eines Elementbezeichners ist der Unterschied zwischen dem Bezeichner und dem Wert in idCmdFirst. Store offset jedes Elements, das der Handler dem Kontextmenü hinzufügt, da die Shell möglicherweise den Offset zum Identifizieren des Elements verwendet, wenn sie anschließend IContextMenu::GetCommandString oder IContextMenu::InvokeCommand aufruft.

Außerdem sollten Sie jedem befehl, den Sie hinzufügen, ein Verb zuweisen. Ein Verb ist eine Zeichenfolge, die anstelle des Offsets verwendet werden kann, um den Befehl zu identifizieren, wenn InvokeCommand aufgerufen wird. Sie wird auch von Funktionen wie ShellExecuteEx verwendet, um Kontextmenübefehle auszuführen.

Es gibt drei Flags, die über den uFlags-Parameter übergeben werden können, die für Kontextmenühandler relevant sind. Diese werden in der folgenden Tabelle beschrieben.

Flag Beschreibung
CMF _ DEFAULTONLY Der Benutzer hat den Standardbefehl ausgewählt, in der Regel durch Doppelklicken auf das Objekt. IContextMenu::QueryContextMenu sollte die Steuerung an die Shell zurückgeben, ohne das Menü zu ändern.
CMF _ NODEFAULT Kein Element im Menü sollte das Standardelement sein. Die -Methode sollte ihre Befehle zum Menü hinzufügen.
CMF _ NORMAL Das Kontextmenü wird normal angezeigt. Die -Methode sollte ihre Befehle zum Menü hinzufügen.

Verwenden Sie entweder InsertMenu oder InsertMenuItem, um der Liste Menüelemente hinzuzufügen. Geben Sie dann einen HRESULT-Wert zurück, bei dem der Schweregrad auf SCHWEREGRAD ERFOLGREICH _ festgelegt ist. Legen Sie den Codewert auf den Offset des größten zugewiesenen Befehlsbezeichners plus einen (1) fest. Angenommen, idCmdFirst ist auf 5 festgelegt, und Sie fügen dem Menü drei Elemente mit befehlsbezeichnern 5, 7 und 8 hinzu. Der Rückgabewert sollte MAKE _ HRESULT(SEVERITY _ SUCCESS, 0, 8 + 1) sein.

Das folgende Beispiel zeigt eine einfache Implementierung von QueryContextMenu, die einen einzelnen Befehl einfüge. Der Bezeichneroffset für den Befehl ist IDM _ DISPLAY, der auf 0 (null) festgelegt ist. Die Variablen m _ pszVerb und m _ pwszVerb sind private Variablen, die zum Speichern der zugeordneten sprachunabhängigen Verbzeichenfolge sowohl im ANSI- als auch im Unicode-Format verwendet werden.

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

Hinweise

Weitere Aufgaben zur Verbimplementierung finden Sie unter Erstellen von Kontextmenühandlern.