Personalizzazione di un menu di scelta rapida tramite verbi dinamici

I gestori di menu di scelta rapida sono noti anche come gestori di menu di scelta rapida o gestori di verbi. Un gestore di menu di scelta rapida è un tipo di gestore dei tipi di file.

Questo argomento è organizzato come segue:

Informazioni sui verbi statici e dinamici

È consigliabile implementare un menu di scelta rapida usando uno dei metodi dei verbi statici. È consigliabile seguire le istruzioni fornite nella sezione "Personalizzazione di un menu di scelta rapida con verbi statici" di Creazione di gestori di menu di scelta rapida. Per ottenere il comportamento dinamico per i verbi statici in Windows 7 e versioni successive, vedere "Getting Dynamic Behavior for Static Verbs" (Recupero del comportamento dinamico per verbi statici) in Creazione di gestori di menu di scelta rapida. Per informazioni dettagliate sull'implementazione di verbi statici e sui verbi dinamici da evitare, vedere Scelta di un verbo statico o dinamico per il menu di scelta rapida.

Se è necessario estendere il menu di scelta rapida per un tipo di file registrando un verbo dinamico per il tipo di file, seguire le istruzioni fornite più avanti in questo argomento.

Nota

Quando si registrano gestori che funzionano nel contesto di applicazioni a 32 bit, è necessario tenere presenti considerazioni speciali per Windows a 64 bit: quando i verbi shell vengono richiamati nel contesto di un'applicazione a 32 bit, il sottosistema WOW64 reindirizza l'accesso al file system ad alcuni percorsi. Se il gestore .exe viene archiviato in uno di questi percorsi, non è accessibile in questo contesto. Pertanto, come soluzione alternativa, archiviare il file con estensione exe in un percorso che non viene reindirizzato o archiviare una versione stub del file exe che avvia la versione reale.

 

Funzionamento dei gestori di menu di scelta rapida con verbi dinamici

Oltre a IUnknown, i gestori di menu di scelta rapida esportano le interfacce aggiuntive seguenti per gestire la messaggistica necessaria per implementare le voci di menu disegnate dal proprietario:

Per altre informazioni sulle voci di menu disegnate dal proprietario, vedere la sezione Creazione di voci di menu disegnate dal proprietario in Uso dei menu.

Shell usa l'interfaccia IShellExtInit per inizializzare il gestore. Quando shell chiama IShellExtInit::Initialize, passa un oggetto dati con il nome dell'oggetto e un puntatore a un elenco di identificatori di elemento (PIDL) della cartella che contiene il file. Il parametro hkeyProgID è il percorso del Registro di sistema in cui è registrato l'handle del menu di scelta rapida. Il metodo IShellExtInit::Initialize deve estrarre il nome file dall'oggetto dati e archiviare il nome e il puntatore della cartella a un elenco di identificatori di elemento (PIDL) per un uso successivo. Per altre informazioni sull'inizializzazione del gestore, vedere Implementazione di IShellExtInit.

Quando i verbi vengono presentati in un menu di scelta rapida, vengono prima individuati, quindi presentati all'utente e infine richiamati. L'elenco seguente descrive questi tre passaggi in modo più dettagliato:

  1. Shell chiama IContextMenu::QueryContextMenu, che restituisce un set di verbi che possono essere basati sullo stato degli elementi o del sistema.
  2. Il sistema passa un handle HMENU che il metodo può usare per aggiungere elementi al menu di scelta rapida.
  3. Se l'utente fa clic su uno degli elementi del gestore, shell chiama IContextMenu::InvokeCommand. Il gestore può quindi eseguire il comando appropriato.

Evitare conflitti a causa di nomi di verbi non qualificati

Poiché i verbi vengono registrati per tipo, è possibile usare lo stesso nome verbo per i verbi su elementi diversi. In questo modo, le applicazioni possono fare riferimento a verbi comuni indipendentemente dal tipo di elemento. Sebbene questa funzionalità sia utile, l'uso di nomi non qualificati può causare conflitti con più fornitori di software indipendenti (ISV) che scelgono lo stesso nome verbo. Per evitare questo problema, anteporre sempre i verbi con il nome ISV come indicato di seguito:

ISV_Name.verb

Usare sempre un ProgID specifico dell'applicazione. L'adozione della convenzione di mapping dell'estensione del nome file a un ProgID fornito da ISV evita potenziali conflitti. Tuttavia, poiché alcuni tipi di elementi non usano questo mapping, è necessario specificare nomi univoci del fornitore. Quando si aggiunge un verbo a un ProgID esistente che potrebbe avere già registrato tale verbo, è necessario prima rimuovere la chiave del Registro di sistema per il verbo precedente prima di aggiungere il proprio verbo. È necessario eseguire questa operazione per evitare di unire le informazioni sul verbo dai due verbi. In caso contrario, si verifica un comportamento imprevedibile.

Registrazione di un gestore di menu di scelta rapida con un verbo dinamico

I gestori di menu di scelta rapida sono associati a un tipo di file o a una cartella. Per i tipi di file, il gestore viene registrato nella sottochiave seguente.

HKEY_CLASSES_ROOT
   Program ID
      shellex
         ContextMenuHandlers

Per associare un gestore di menu di scelta rapida a un tipo di file o a una cartella, creare prima di tutto una sottochiave sottochiave ContextMenuHandlers . Denominare la sottochiave per il gestore e impostare il valore predefinito della sottochiave sul formato stringa del GUID (CLSID) dell'identificatore di classe del gestore.

Quindi, per associare un gestore di menu di scelta rapida a diversi tipi di cartelle, registrare il gestore allo stesso modo per un tipo di file, ma sotto la sottochiave FolderType , come illustrato nell'esempio seguente.

HKEY_CLASSES_ROOT
   FolderType
      shellex
         ContextMenuHandlers

Per altre informazioni sui tipi di cartella per cui è possibile registrare i gestori, vedere Registrazione dei gestori dell'estensione della shell.

Se a un tipo di file è associato un menu di scelta rapida, fare doppio clic su un oggetto avvia normalmente il comando predefinito e il metodo IContextMenu::QueryContextMenu del gestore non viene chiamato. Per specificare che il metodo IContextMenu::QueryContextMenu del gestore deve essere chiamato quando si fa doppio clic su un oggetto, creare una sottochiave sottochiave CLSID del gestore, come illustrato di seguito.

HKEY_CLASSES_ROOT
   CLSID
      {00000000-1111-2222-3333-444444444444}
         shellex
            MayChangeDefaultMenu

Quando si fa doppio clic su un oggetto associato al gestore, viene chiamato IContextMenu::QueryContextMenu con il flag CMF_DEFAULTONLY impostato nel parametro uFlags.

I gestori di menu di scelta rapida devono impostare la sottochiave MayChangeDefaultMenu solo se potrebbero dover modificare il verbo predefinito del menu di scelta rapida. L'impostazione di questa sottochiave forza il sistema a caricare la DLL del gestore quando si fa doppio clic su un elemento associato. Se il gestore non modifica il verbo predefinito, non è consigliabile impostare questa sottochiave perché in questo modo il sistema carica la DLL inutilmente.

Nell'esempio seguente vengono illustrate le voci del Registro di sistema che abilitano un gestore di menu di scelta rapida per un tipo di file con estensione myp. La sottochiave CLSID del gestore include una sottochiave MayChangeDefaultMenu per garantire che il gestore venga chiamato quando l'utente fa doppio clic su un oggetto correlato.

HKEY_CLASSES_ROOT
   .myp
      (Default) = MyProgram.1
   CLSID
      {00000000-1111-2222-3333-444444444444}
         InProcServer32
            (Default) = C:\MyDir\MyCommand.dll
            ThreadingModel = Apartment
         shellex
            MayChangeDefaultMenu
   MyProgram.1
      (Default) = MyProgram Application
      shellex
         ContextMenuHandler
            MyCommand = {00000000-1111-2222-3333-444444444444}

Implementazione dell'interfaccia IContextMenu

IContextMenu è il metodo più potente ma anche il metodo più complicato da implementare. È consigliabile implementare un verbo usando uno dei metodi del verbo statico. Per altre informazioni, vedere Scelta di un verbo statico o dinamico per il menu di scelta rapida. IContextMenu include tre metodi, GetCommandString, InvokeCommand e QueryContextMenu, illustrati qui in dettaglio.

Metodo IContextMenu::GetCommandString

Il metodo IContextMenu::GetCommandString del gestore viene usato per restituire il nome canonico per un verbo. È facoltativo. In Windows XP e versioni precedenti di Windows, quando Esplora risorse dispone di una barra di stato, questo metodo viene utilizzato per recuperare il testo della Guida visualizzato nella barra di stato per una voce di menu.

Il parametro idCmd contiene l'offset dell'identificatore del comando definito quando è stato chiamato IContextMenu::QueryContextMenu . Se viene richiesta una stringa della Guida, uFlags verrà impostato su GCS_HELPTEXTW. Copiare la stringa della Guida nel buffer pszName , eseguendo il cast in un file PWSTR. La stringa del verbo viene richiesta impostando uFlags su GCS_VERBW. Copiare la stringa appropriata in pszName, esattamente come nella stringa della Guida. I flag GCS_VALIDATEA e GCS_VALIDATEW non vengono utilizzati dai gestori di menu di scelta rapida.

Nell'esempio seguente viene illustrata una semplice implementazione di IContextMenu::GetCommandString che corrisponde all'esempio IContextMenu::QueryContextMenu fornito nella sezione Metodo IContextMenu::QueryContextMenu di questo argomento. Poiché il gestore aggiunge una sola voce di menu, è possibile restituire un solo set di stringhe. Il metodo verifica se idCmd è valido e, in caso affermativo, restituisce la stringa richiesta.

La funzione StringCchCopy viene usata per copiare la stringa richiesta in pszName per assicurarsi che la stringa copiata non superi le dimensioni del buffer specificato da cchName. Questo esempio implementa solo il supporto per i valori Unicode di uFlags, perché solo quelli sono stati usati in Esplora risorse a partire da 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 passed in
                // through idCommand.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"DisplayFileName");
                break; 
        }
    }
    return hr;
}

Metodo IContextMenu::InvokeCommand

Questo metodo viene chiamato quando un utente fa clic su una voce di menu per indicare al gestore di eseguire il comando associato. Il parametro pici punta a una struttura che contiene le informazioni necessarie.

Anche se pici è dichiarato in Shlobj.h come struttura CMINVOKECOMMANDINFO, in pratica punta spesso a una struttura CMINVOKECOMMANDINFOEX. Questa struttura è una versione estesa di CMINVOKECOMMANDINFO e include diversi membri aggiuntivi che consentono di passare stringhe Unicode.

Controllare il membro cbSize di pici per determinare la struttura passata. Se si tratta di una struttura CMINVOKECOMMANDINFOEX e il membro fMask ha il flag CMIC_MASK_UNICODE impostato, eseguire il cast pici in CMINVOKECOMMANDINFOEX. In questo modo l'applicazione può usare le informazioni Unicode contenute negli ultimi cinque membri della struttura.

Il membro lpVerb o lpVerbW della struttura viene usato per identificare il comando da eseguire. I comandi vengono identificati in uno dei due modi seguenti:

  • In base alla stringa del verbo del comando
  • In base all'offset dell'identificatore del comando

Per distinguere questi due casi, controllare la parola dell'ordine elevato di lpVerb per il caso ANSI o lpVerbW per il caso Unicode. Se la parola di ordine elevato è diversa da zero, lpVerb o lpVerbW contiene una stringa verbo. Se la parola dell'ordine elevato è zero, l'offset del comando si trova nella parola in ordine basso di lpVerb.

Nell'esempio seguente viene illustrata una semplice implementazione di IContextMenu::InvokeCommand che corrisponde agli esempi IContextMenu::QueryContextMenu e IContextMenu::GetCommandString forniti prima e dopo questa sezione. Il metodo determina innanzitutto la struttura passata. Determina quindi se il comando viene identificato dall'offset o dal relativo verbo. Se lpVerb o lpVerbW contiene un verbo o un offset valido, il metodo visualizza una finestra di messaggio.

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

Metodo IContextMenu::QueryContextMenu

Shell chiama IContextMenu::QueryContextMenu per consentire al gestore del menu di scelta rapida di aggiungere le voci di menu al menu. Passa l'handle HMENU nel parametro hmenu . Il parametro indexMenu è impostato sull'indice da utilizzare per la prima voce di menu da aggiungere.

Tutte le voci di menu aggiunte dal gestore devono avere identificatori che rientrano tra i valori nei parametri idCmdFirst e idCmdLast . In genere, il primo identificatore di comando è impostato su idCmdFirst, che viene incrementato di uno (1) per ogni comando aggiuntivo. Questa procedura consente di evitare di superare idCmdLast e massimizzare il numero di identificatori disponibili nel caso in cui shell chiami più di un gestore.

L'offset del comando di un identificatore di elemento è la differenza tra l'identificatore e il valore in idCmdFirst. Archiviare l'offset di ogni elemento aggiunto dal gestore al menu di scelta rapida perché shell potrebbe usarlo per identificare l'elemento se successivamente chiama IContextMenu::GetCommandString o IContextMenu::InvokeCommand.

È anche necessario assegnare un verbo a ogni comando aggiunto. Un verbo è una stringa che può essere usata invece dell'offset per identificare il comando quando viene chiamato IContextMenu::InvokeCommand. Viene usato anche da funzioni come ShellExecuteEx per eseguire i comandi di menu di scelta rapida.

Esistono tre flag che possono essere passati tramite il parametro uFlags rilevanti per i gestori di menu di scelta rapida. descritti nella tabella seguente.

Contrassegno Descrizione
CMF_DEFAULTONLY L'utente ha selezionato il comando predefinito, in genere facendo doppio clic sull'oggetto. IContextMenu::QueryContextMenu deve restituire il controllo alla shell senza modificare il menu.
CMF_NODEFAULT Nessuna voce nel menu deve essere l'elemento predefinito. Il metodo deve aggiungere i comandi al menu.
CMF_NORMAL Il menu di scelta rapida verrà visualizzato normalmente. Il metodo deve aggiungere i comandi al menu.

 

Utilizzare InsertMenu o InsertMenuItem per aggiungere voci di menu all'elenco. Restituire quindi un valore HRESULT con la gravità impostata su edizione StandardVERITY_SUCCESS. Impostare il valore del codice sull'offset dell'identificatore di comando più grande assegnato, più uno (1). Si supponga, ad esempio, che idCmdFirst sia impostato su 5 e si aggiungono tre voci al menu con identificatori di comando di 5, 7 e 8. Il valore restituito deve essere MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1).

L'esempio seguente illustra una semplice implementazione di IContextMenu::QueryContextMenu che inserisce un singolo comando. L'offset dell'identificatore per il comando è IDM_DISPLAY, impostato su zero. Le variabili m_pszVerb e m_pwszVerb sono variabili private usate per archiviare la stringa verbo indipendente dal linguaggio associata in formati ANSI e 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));
}

Per altre attività di implementazione verbo, vedere Creazione di gestori di menu di scelta rapida.

Menu di scelta rapida e gestori di menu di scelta rapida

Verbi e associazioni di file

Scelta di un verbo statico o dinamico per il menu di scelta rapida

Procedure consigliate per i gestori di menu di scelta rapida e più verbi di selezione

Creazione di gestori di menu di scelta rapida

Informazioni di riferimento sul menu di scelta rapida