Condividi tramite


Personalizzazione di un menu di scelta rapida tramite verbi dinamici

I gestori di menu di scelta rapida sono noti anche come gestori di menu contestuale 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" in Creating Context Menu Handlers. Per informazioni dettagliate sull'implementazione dei 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 .exe in un percorso che non viene reindirizzato o archiviare una versione stub del .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 seguenti interfacce aggiuntive per gestire la messaggistica necessaria per implementare le voci di menu personalizzate.

Per ulteriori informazioni sulle voci di menu personalizzate, vedere la sezione Creazione di voci di menu Owner-Drawn in Uso di menu.

Shell usa l'interfaccia di IShellExtInit per inizializzare il gestore. Quando la shell chiama IShellExtInit::Initialize, passa un oggetto di dati contenente il nome dell'oggetto e un puntatore a un elenco di identificatori di elementi (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 di tipo 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 collisioni con più fornitori di software indipendenti (ISV) che scelgono lo stesso 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 mappatura dell'estensione del nome file a un ProgID fornito dall'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 dei 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, prima di tutto creare una sottochiave sotto la chiave 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 FolderType sottochiave 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 delle Estensioni della Shell.

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

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 il MayChangeDefaultMenu sottochiave 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 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, InvokeCommande QueryContextMenu, descritti qui in dettaglio.

Metodo IContextMenu::GetCommandString

Il metodo IContextMenu::GetCommandString del gestore viene usato per restituire il nome canonico per un verbo. Questo metodo è facoltativo. In Windows XP e nelle versioni precedenti di Windows, quando Esplora File dispone di una barra di stato, questo metodo viene utilizzato per recuperare il testo di aiuto 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. Copia la stringa di aiuto nel buffer pszName, convertendola in un PWSTR. La stringa del verbo viene richiesta impostando uFlags su GCS_VERBW. Copiare la stringa appropriata in pszName, proprio come con la stringa di aiuto. I flag GCS_VALIDATEA e GCS_VALIDATEW non vengono usati dai gestori di menu di scelta rapida.

Nell'esempio seguente viene illustrata una semplice implementazione di IContextMenu::GetCommandString che corrisponde all'esempio IContextMenu::QueryContextMenu illustrato nella sezione IContextMenu::QueryContextMenu Method 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 funzioneStringCchCopyviene 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 file sin 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.

Sebbene pici sia dichiarato in Shlobj.h come struttura CMINVOKECOMMANDINFO, in pratica spesso punta 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 quale struttura è stata passata. Se si tratta di una struttura CMINVOKECOMMANDINFOEX e il membro fMask ha impostato il flag CMIC_MASK_UNICODE, esegui il cast di pici a CMINVOKECOMMANDINFOEX. In questo modo l'applicazione può usare le informazioni Unicode contenute negli ultimi cinque membri della struttura.

Il membro lpVerb o lpVerbW 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 tra questi due casi, controllare la parola di 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 di verbi. Se la parola di 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 all'IContextMenu::QueryContextMenu e IContextMenu::GetCommandString esempi specificati prima e dopo questa sezione. Il metodo determina per primo quale struttura viene 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 di menu di scelta rapida di aggiungere le relative voci di menu al menu. Passa l'handle HMENU nel parametro hmenu. Il parametro indexMenu viene 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 consigliabile 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. Sono descritte nella tabella seguente.

Bandiera 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 SEVERITY_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 5, 7 e 8. Il valore restituito deve essere MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1).

Nell'esempio seguente viene illustrata 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 dei verbi, vedere Creazione dei gestori del menu contestuale.

Menu di scelta rapida (contesto) 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 Contestuale e Verbi di Selezione Multipla

Creazione di gestori di menu di scelta rapida

Riferimento al menu di scelta rapida