Integrare un'app desktop in pacchetto con Esplora file
Alcune app di Windows definiscono le estensioni di Esplora file che aggiungono voci di menu di scelta rapida, che consentono ai clienti di eseguire opzioni correlate all'app. Le tecnologie di distribuzione delle app di Windows meno recenti, ad esempio MSI e ClickOnce, definiscono le estensioni di Esplora file tramite il registro di sistema. Il registro di sistema include una serie di hive che controllano le estensioni di Esplora file e altri tipi di estensioni della shell. Questi programmi di installazione creano in genere una serie di chiavi del registro di sistema per configurare i vari elementi da includere nel menu di scelta rapida.
Se si crea un pacchetto dell'app di Windows usando MSIX, il registro di sistema viene virtualizzato e pertanto l'app non è in grado di registrare le estensioni di Esplora file tramite il registro di sistema. È invece necessario definire le estensioni di Esplora file tramite estensioni di pacchetto definite nel manifesto del pacchetto. Questo articolo descrive diversi modi per eseguire questa operazione.
È possibile trovare il codice di esempio completo usato in questo articolo su GitHub.
Aggiungere una voce di menu di scelta rapida che supporti i parametri di avvio
Uno dei modi più semplici per l'integrazione con Esplora file consiste nel definire un'estensione del pacchetto che aggiunge l'app all'elenco delle app disponibili nel menu di scelta rapida quando un utente fa clic con il pulsante destro del mouse su un tipo di file specifico in Esplora file. Se l'utente apre l'app, l'estensione può trasmettere i parametri all'app.
Questo scenario presenta diverse limitazioni:
- Funziona solo in combinazione con la funzionalità di associazione del tipo di file. Puoi visualizzare opzioni aggiuntive nel menu di scelta rapida solo per i tipi di file associati all'app principale (ad esempio, l'app supporta l'apertura di un file facendo doppio clic in Esplora file).
- Le opzioni nel menu di scelta rapida verranno visualizzate solo se l'app è impostata come predefinita per quel tipo di file.
- L'unica azione supportata consiste nell'avviare il file eseguibile principale dell'app, ovvero lo stesso eseguibile connesso alla voce di menu Start. Tuttavia, ogni azione può specificare parametri diversi, che è possibile usare quando le app iniziano a comprendere quale azione ha attivato l'esecuzione ed eseguire attività diverse.
Nonostante queste limitazioni, tale approccio è sufficiente per molti scenari. Ad esempio, se si sta creando un editor di immagini, è possibile aggiungere facilmente una voce nel menu di scelta rapida per ridimensionare un'immagine, che avvierà l'editor di immagini direttamente con una procedura guidata per avviare il processo di ridimensionamento.
Implementare la voce di menu di scelta rapida
Per supportare questo scenario, aggiungi un elemento Extension con la categoria windows.fileTypeAssociation
al manifesto del pacchetto. Questo elemento deve essere aggiunto come elemento figlio dell'elemento Extensions nell'elemento Application.
L'esempio seguente illustra una registrazione per un'app che abilita i menu di scelta rapida per i file con l'estensione .foo
. Questo esempio specifica l'estensione .foo
perché si tratta di un'estensione fittizia che in genere non è registrata in altre app in un determinato computer. Se devi gestire un tipo di file che potrebbe essere già acquisito (ad esempio .txt o .jpg), ricorda che non sarai in grado di visualizzare l'opzione fino a quando l'app non è impostata come predefinita per quel tipo di file. Questo esempio è un estratto del file Package.appxmanifest nell'esempio correlato in GitHub.
<Extensions>
<uap3:Extension Category="windows.fileTypeAssociation">
<uap3:FileTypeAssociation Name="foo" Parameters=""%1"">
<uap:SupportedFileTypes>
<uap:FileType>.foo</uap:FileType>
</uap:SupportedFileTypes>
<uap2:SupportedVerbs>
<uap3:Verb Id="Resize" Parameters=""%1" /p">Resize file</uap3:Verb>
</uap2:SupportedVerbs>
</uap3:FileTypeAssociation>
</uap3:Extension>
</Extensions>
In questo esempio si presuppone che gli spazi dei nomi e gli alias seguenti siano dichiarati nell'elemento radice <Package>
nel manifesto.
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap uap2 uap3 rescap">
...
</Package>
L'elemento FileTypeAssociation associa l'app ai tipi di file che vuoi supportare. Per altri dettagli, vedi Associare l'applicazione in pacchetto a un set di tipi di file. Ecco gli elementi più importanti correlati a tale elemento.
Attributo o elemento | Descrizione |
---|---|
Attributo Name |
Corrisponde al nome dell'estensione da registrare meno il punto (foo nell'esempio precedente). |
Attributo Parameters |
Contiene i parametri da trasmettere all'applicazione quando l'utente fa doppio clic su un file con tale estensione. Di solito, almeno, si trasmette %1 , che è un parametro speciale contenente il percorso del file selezionato. In questo modo, quando si fa doppio clic su un file, l'applicazione ne conosce il percorso completo e può caricarlo. |
Elemento SupportedFileTypes | Specifica i nomi dell'estensione da registrare, incluso il punto (.foo in questo esempio). È possibile specificare più voci <FileType> che si desidera supportare più tipi di file. |
Per definire l'integrazione del menu di scelta rapida, è necessario aggiungere anche l'elemento figlio SupportedVerbs. Questo elemento contiene uno o più elementi Verb che definiscono le opzioni che verranno elencate quando un utente fa clic con il pulsante destro del mouse su un file con estensione .foo in Esplora file. Per uteriori dettagli, vedi Aggiungere opzioni ai menu di scelta rapida dei file che dispongono di un determinato tipo di file. Ecco gli elementi più importanti correlati all'elemento Verb.
Attributo o elemento | Descrizione |
---|---|
Attributo Id |
Specifica l'identificatore univoco dell’azione. |
Attributo Parameters |
Analogamente all'elemento FileTypeAssociation, questo attributo per l'elemento Verb contiene i parametri trasmessi all'applicazione quando l'utente fa clic sulla voce di menu di scelta rapida. In genere, oltre al parametro speciale %1 per ottenere il percorso del file selezionato, si trasmettono anche uno o più parametri per ottenere il contesto. Ciò consente all'app di comprendere che è stata aperta da una voce di menu di scelta rapida. |
Element value | Il valore dell'elemento Verb contiene l'etichetta da visualizzare nella voce del menu di scelta rapida (in questo esempio, Ridimensiona file). |
Accedere ai parametri di avvio nel codice dell'app
Il modo in cui l'app riceve i parametri dipende dal tipo di app creata. Ad esempio, un'app WPF elabora in genere argomenti di evento di avvio nel metodo OnStartup
della classe App
. È possibile verificare se sono presenti parametri di avvio e, in base al risultato, eseguire l'azione più appropriata, ad esempio l'apertura di una finestra specifica dell'applicazione anziché quella principale.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
if (e.Args.Contains("Resize"))
{
// Open a specific window of the app.
}
else
{
MainWindow main = new MainWindow();
main.Show();
}
}
}
Lo screenshot seguente illustra la voce di menu di scelta rapida Ridimensiona file creata dall'esempio precedente.
Supportare file o cartelle generici ed eseguire attività complesse
Anche se l'uso dell'estensione FileTypeAssociation nel manifesto del pacchetto, come descritto nella sezione precedente, è sufficiente per molti scenari, è possibile che vi siano delle limitazioni. Le due sfide principali sono:
- È possibile gestire solo i tipi di file a cui si è associati. Ad esempio, non è possibile gestire una cartella generica.
- È possibile avviare l'app solo con una serie di parametri. Non è possibile eseguire operazioni avanzate, ad esempio l'avvio di un altro eseguibile o l'esecuzione di un'attività senza aprire l'app principale.
Per raggiungere questi obiettivi, è necessario creare una estensione Shell che offre modi più potenti per l'integrazione con Esplora file. In questo scenario si crea una DLL contenente tutti gli elementi necessari per gestire il menu di scelta rapida del file, tra cui l'etichetta, l'icona, lo stato e le attività da eseguire. Poiché questa funzionalità viene implementata in una DLL, è possibile eseguire quasi tutte le operazioni eseguibili con una normale app. Dopo aver implementato la DLL, è necessario registrarla tramite le estensioni definite nel manifesto del pacchetto.
Nota
Il processo descritto in questa sezione presenta una limitazione. Dopo l'installazione del pacchetto MSIX che contiene l'estensione in un computer di destinazione, Esplora file deve essere riavviato prima che l'estensione Shell possa essere caricata. A tale scopo, l'utente può riavviare il computer oppure riavviare il processo explorer.exe usando Gestione attività.
Implementare l'estensione Shell
Le estensioni della shell sono basate su COM (Component Object Model). La DLL espone uno o più oggetti COM registrati nel Registro di sistema. Windows individua questi oggetti COM e integra l'estensione con Esplora file. Poiché si sta integrando il codice con la shell di Windows, le prestazioni e il footprint della memoria sono importanti. Di conseguenza, questi tipi di estensioni vengono in genere compilati con C++.
Per il codice di esempio che illustra come implementare le estensioni della shell, vedi il progetto ExplorerCommandVerb nell'esempio correlato in GitHub. Questo progetto è basato su questo esempio riportato negli esempi desktop di Windows e include diverse revisioni per semplificarne l'uso con le versioni più recenti di Visual Studio.
Questo progetto contiene una grande quantità di codice boilerplate per diverse attività, ad esempio menu dinamici e statici e registrazione manuale della DLL. La maggior parte di questo codice non è necessaria se si crea il pacchetto dell'app usando MSIX, perché è il supporto per la creazione di pacchetti a occuparsi automaticamente di queste attività. Il file ExplorerCommandVerb.cpp contiene l'implementazione del menu di scelta rapida e questo è il file di codice di interesse principale per questo percorso.
La funzione chiave è CExplorerCommandVerb::Invoke
. Questa è la funzione richiamata quando un utente fa clic sulla voce nel menu di scelta rapida. Nell'esempio, per ridurre al minimo l'impatto sulle prestazioni, l'operazione viene eseguita su un altro thread; quindi, sarà effettivamente possibile rintracciare l'implementazione reale in CExplorerCommandVerb::_ThreadProc
.
DWORD CExplorerCommandVerb::_ThreadProc()
{
IShellItemArray* psia;
HRESULT hr = CoGetInterfaceAndReleaseStream(_pstmShellItemArray, IID_PPV_ARGS(&psia));
_pstmShellItemArray = NULL;
if (SUCCEEDED(hr))
{
DWORD count;
psia->GetCount(&count);
IShellItem2* psi;
HRESULT hr = GetItemAt(psia, 0, IID_PPV_ARGS(&psi));
if (SUCCEEDED(hr))
{
PWSTR pszName;
hr = psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pszName);
if (SUCCEEDED(hr))
{
WCHAR szMsg[128];
StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"%d item(s), first item is named %s", count, pszName);
MessageBox(_hwnd, szMsg, L"ExplorerCommand Sample Verb", MB_OK);
CoTaskMemFree(pszName);
}
psi->Release();
}
psia->Release();
}
return 0;
}
Quando un utente fa clic con il pulsante destro del mouse su un file o una cartella, tale funzione visualizza una finestra di messaggio con il percorso completo del file o della cartella selezionata. Se si vuole personalizzare l'estensione della shell in altri modi, è possibile estendere le funzioni seguenti nell'esempio:
- È possibile modificare la funzione GetTitle per personalizzare l'etichetta della voce nel menu di scelta rapida.
- È possibile modificare la funzione GetIcon per personalizzare l'icona visualizzata vicino alla voce nel menu di scelta rapida.
- È possibile modificare la funzione GetTooltip per personalizzare la tooltip visualizzata quando si passa il mouse sulla voce nel menu di scelta rapida.
Registrare l'estensione della shell
Poiché l'estensione della shell è basata su COM, la DLL di implementazione deve essere esposta come server COM in modo che Windows possa integrarla con Esplora file. In genere, questa operazione viene eseguita assegnando un ID univoco (denominato CLSID) al server COM e registrandolo in un hive specifico del registro di sistema. Nel progetto ExplorerCommandVerb il CLSID per l'CExplorerCommandVerb
estensione viene definito nel file Dll.h.
class __declspec(uuid("CC19E147-7757-483C-B27F-3D81BCEB38FE")) CExplorerCommandVerb;
Quando si crea il pacchetto di una DLL di estensione della shell in un pacchetto MSIX, si segue un approccio simile. Tuttavia, il GUID deve essere registrato all'interno del manifesto del pacchetto anziché nel registro di sistema, come illustrato qui.
Nel manifesto del pacchetto, inizia aggiungendo gli spazi dei nomi seguenti all'elemento Package.
<Package
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
IgnorableNamespaces="desktop desktop4 desktop5 com">
...
</Package>
Per registrare il CLSID, aggiungi un elemento com.Extension con la categoria windows.comServer
nel manifesto del pacchetto. Questo elemento deve essere aggiunto come elemento figlio dell'elemento Extensions nell'elemento Application. Questo esempio è un estratto del file Package.appxmanifest nell'esempio correlato in GitHub.
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="ContextMenuSample">
<com:Class Id="CC19E147-7757-483C-B27F-3D81BCEB38FE" Path="ExplorerCommandVerb.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
Esistono due attributi critici da configurare nell'elemento com:Class.
Attributo | Descrizione |
---|---|
Attributo Id |
Tale elemento deve corrispondere al CLSID dell'oggetto da registrare. In questo esempio, si tratta del CLSID dichiarato nel file Dll.h associato alla classe CExplorerCommandVerb . |
Attributo Path |
Deve contenere il nome della DLL che espone l'oggetto COM. Questo esempio include la DLL nella radice del pacchetto, quindi è possibile semplicemente specificare il nome della DLL generata dal progetto ExplorerCommandVerb . |
Successivamente, aggiungere un'altra estensione che registra il menu di scelta rapida del file. A tale scopo, aggiungi un elemento desktop4:Extension con la categoria windows.fileExplorerContextMenus
al tuo manifesto del pacchetto. Questo elemento deve essere aggiunto anche come elemento figlio dell'elemento Extensions sotto l'elemento Application.
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="Directory">
<desktop5:Verb Id="Command1" Clsid="CC19E147-7757-483C-B27F-3D81BCEB38FE" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
Esistono due attributi critici da configurare nell'elemento desktop4:Extension.
Attributo o elemento | Descrizione |
---|---|
Attributo Type di desktop5:ItemType |
In questo modo viene definito il tipo di elementi che si desidera associare al menu di scelta rapida. Potrebbe trattarsi di una stella (* ) se si desidera che venga visualizzata per tutti i file, di un'estensione di file specifica (.foo ) oppure può essere disponibile per le cartelle (Directory ). |
Attributo Clsid di desktop5:Verb |
Deve corrispondere al CLSID registrato in precedenza come server COM nel file del manifesto del pacchetto. |
Configurare la DLL nel pacchetto
Includere la DLL che implementa l'estensione della shell (in questo esempio, ExplorerCommandVerb.dll) nella radice del pacchetto MSIX. Se si usa il Progetto di creazione pacchetti per applicazioni Windows, la soluzione più semplice consiste nel copiare e incollare la DLL nel progetto e assicurarsi che l'opzione Copia nella directory di output per le proprietà del file DLL sia impostata su Copia se più recente.
Per assicurarsi che il pacchetto includa sempre la versione più recente della DLL, è possibile aggiungere un evento di post-compilazione al progetto di estensione della shell in modo che, ogni volta che lo si compila, la DLL venga copiata nel Progetto di creazione pacchetti per applicazioni Windows.
Riavviare Esplora file
Dopo aver installato il pacchetto di estensione della shell, è necessario riavviare Esplora file prima che l'estensione della shell possa essere caricata. Si tratta di una limitazione delle estensioni della shell distribuite e registrate tramite pacchetti MSIX.
Per testare l'estensione della shell, riavviare il PC o il processo explorer.exe usando Gestione attività. Dopo aver eseguito questa operazione, dovrebbe essere possibile visualizzare la voce nel menu di scelta rapida.
Se si fa clic su di esso, la funzione CExplorerCommandVerb::_ThreadProc
verrà richiamata per visualizzare la finestra di messaggio con il percorso della cartella selezionata.