Implementieren der IContextMenu-Schnittstelle

IContextMenu ist die leistungsstärkste, 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 die drei Methoden GetCommandString, InvokeCommand und 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ückzugeben. Diese Methode ist optional. Wenn Windows Explorer in Windows XP und früheren Versionen von 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 Aufruf von IContextMenu::QueryContextMenu definiert wurde. Wenn eine Hilfezeichenfolge angefordert wird, wird uFlags auf GCS_HELPTEXTW festgelegt. Kopieren Sie die Hilfezeichenfolge in den Puffer pszName , und fügen Sie sie in einen PWSTR um. Die Verbzeichenfolge wird angefordert, indem uFlags auf GCS_VERBW festgelegt wird. Kopieren Sie die entsprechende Zeichenfolge wie die Hilfezeichenfolge in pszName. Die flags GCS_VALIDATEA und GCS_VALIDATEW werden von Kontextmenühandlern nicht 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 die Größe des durch cchName angegebenen Puffers nicht überschreitet. In diesem Beispiel wird die Unterstützung nur für die Unicode-Werte von uFlags implementiert, da seit Windows 2000 nur diese in Windows Explorer verwendet werden.

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 anweisen, den zugehörigen Befehl auszuführen. Der pici-Parameter verweist auf eine Struktur, die die zum Ausführen des Befehls erforderlichen Informationen enthält.

Obwohl pici in Shlobj.h als CMINVOKECOMMANDINFO-Struktur deklariert wird, 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 das Übergeben von Unicode-Zeichenfolgen ermöglichen.

Überprüfen Sie den cbSize-Member von pici , um zu ermitteln, welche Struktur übergeben wurde. Wenn es sich um eine CMINVOKECOMMANDINFOEX-Struktur handelt und das fMask-Element das CMIC_MASK_UNICODE-Flag festgelegt hat, wandeln Sie pici in CMINVOKECOMMANDINFOEX um. Dadurch kann Ihre Anwendung die Unicode-Informationen verwenden, die in den letzten fünf Membern der Struktur enthalten sind.

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

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

Um zwischen diesen beiden Fällen zu unterscheiden, überprüfen Sie das hochgeordnete Wort lpVerb für den ANSI-Fall oder lpVerbW für den Unicode-Fall. Wenn das Wort mit hoher Ordnung nonzero ist, enthält lpVerb oder lpVerbW eine Verbzeichenfolge. Wenn das Wort mit hoher Reihenfolge 0 ist, befindet sich der Befehlsoffset im Wort "lpVerb" in niedriger Reihenfolge.

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 zunächst, 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 Einen gültigen 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 den Kontextmenühandler zum Hinzufügen seiner Menüelemente zum Menü zu aktivieren. Es wird im HMENU-Handle im hmenu-Parameter übergeben. Der indexMenu-Parameter ist auf den Index festgelegt, der für das erste hinzuzufügende Menüelement verwendet werden soll.

Alle Menüelemente, die vom Handler hinzugefügt werden, müssen Bezeichner aufweisen, 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 einen (1) erhöht wird. Diese Vorgehensweise hilft Ihnen, eine Überschreitung von idCmdLast zu vermeiden und die Anzahl der verfügbaren Bezeichner zu maximieren, falls die Shell mehr als einen Handler aufruft.

Der Befehlsoffset eines Elementbezeichners ist der Unterschied zwischen dem Bezeichner und dem Wert in idCmdFirst. Speichern Sie den Offset jedes Elements, das Ihr Handler dem Kontextmenü hinzufügt, da die Shell möglicherweise den Offset verwendet, um das Element zu identifizieren, wenn sie anschließend IContextMenu::GetCommandString oder IContextMenu::InvokeCommand aufruft.

Außerdem sollten Sie jedem hinzugefügten Befehl ein Verb zuweisen. Ein Verb ist eine Zeichenfolge, die anstelle des Offsets verwendet werden kann, um den Befehl zu identifizieren, wenn InvokeCommand aufgerufen wird. Es 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 dem Menü ihre Befehle hinzufügen.
CMF_NORMAL Das Kontextmenü wird normal angezeigt. Die -Methode sollte dem Menü ihre Befehle 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 SEVERITY_SUCCESS festgelegt ist. Legen Sie den Codewert auf den Offset des größten zugewiesenen Befehlsbezeichners plus eins (1) fest. Angenommen, idCmdFirst ist auf 5 festgelegt, und Sie fügen dem Menü drei Elemente mit Befehlsbezeichnern von 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ügt. Der Bezeichneroffset für den Befehl ist IDM_DISPLAY, der auf Null festgelegt ist. Die variablen m_pszVerb und m_pwszVerb sind private Variablen, die verwendet werden, um die zugeordnete sprachunabhängige Verbzeichenfolge sowohl im ANSI- als auch im Unicode-Format zu speichern.

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

Bemerkungen

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