L'integrazione con la shell di Windows oggi ── menu contestuali, associazioni di file e cosa è cambiato in Windows 11
· Go Komura · Windows, Estensioni della shell, Menu contestuale, Associazione di file, COM, Windows 11, Esplora file, MSIX, Sviluppo Windows
Mi è stato chiesto: «abbiamo sostituito i PC con Windows 11 e il menu contestuale dell’app che ci avete costruito anni fa è scomparso». Ascoltando meglio, non era scomparso. Clic destro su un file, scegliere «Mostra altre opzioni» in fondo al menu, e il menu familiare compare esattamente come sempre. In altre parole, le voci di menu dell’app interna erano state nascoste di un clic più in dentro. Dal campo sentiamo «è un clic in più» e «sono aumentate le richieste di chi non trova la voce».
Non è un guasto né una configurazione sbagliata; è un cambio di progettazione di Windows 11. Il menu contestuale di Esplora file è diventato una struttura a due strati, vecchio e nuovo, e le condizioni per mettere una voce nel nuovo menu sono diventate una cosa del tutto diversa da prima.
Nel frattempo, il meccanismo di associazione file e di estensioni della shell sotto è ancora il vecchio mondo di COM e del registro. Una chiave di estensione punta a un ProgID, il verb del ProgID contiene una riga di comando, e un’estensione più elaborata gira come server COM in-process (DLL) caricato in Esplora risorse — quella struttura non è cambiata da più di vent’anni. Se non conoscete insieme il fondamento invariato e il menu che Windows 11 ha diviso in due, non potete isolare «il menu non compare», «è nascosto» o «compare due volte».
Questo articolo è rivolto al personale IT di piccole e medie imprese e agli sviluppatori Windows che curano app aziendali. Collega, in un solo quadro, la struttura a tre strati dell’associazione file, le cautele delle estensioni della shell classiche, come puntare al nuovo menu contestuale di Windows 11, e registrazione, pulizia e risoluzione dei problemi dell’installer.
1. Prima la conclusione
- Il fondamento del menu contestuale e dell’associazione file è la struttura a tre strati del registro «chiave di estensione → ProgID → verb». La chiave di estensione è un puntatore a un ProgID, il ProgID è la sostanza, e
shell\<verb>\commandsotto di esso contiene la riga di comando.1 - HKEY_CLASSES_ROOT (HKCR) non è un hive indipendente; è una vista unita di HKLM\Software\Classes e HKCU\Software\Classes. Scrivete la registrazione per tutti gli utenti in HKLM e quella per utente in HKCU, e trattate HKCR come sola lettura.2
- L’app predefinita (quella che si apre con il doppio clic) è progettata perché la scelga l’utente, e un programma non può rubarla. Il sistema operativo protegge la scelta dell’utente; ciò che un installer può fare è registrarsi come candidato.3
- Un’estensione della shell classica è una DLL COM in-process caricata in Esplora risorse. Un arresto anomalo o un ritardo dell’estensione si propaga a Esplora risorse nel suo insieme (e ad altre app che usano la shell); un ambiente a 64 bit richiede una DLL a 64 bit; e un’implementazione in codice gestito non è supportata.45
- In Windows 11 il menu contestuale si è diviso in due. Gli unici comandi che compaiono nel nuovo menu sono quelle registrate con IExplorerCommand più identità di pacchetto; le estensioni IContextMenu classiche sono spostate nel vecchio menu sotto «Mostra altre opzioni» (Maiusc+F10).67
- La via ufficiale per mettere un comando personalizzato nel nuovo menu è registrare una DLL nativa che implementa IExplorerCommand in un manifesto MSIX (desktop4:FileExplorerContextMenus). Un’app che non può diventare MSIX può ricevere solo l’identità con uno sparse package (MSIX con posizione esterna).78
- Se tutto ciò che volete è «aprire con questa app», un’associazione e un verb statico bastano ancora. Non serve una DLL di estensione della shell, e Microsoft stessa dice chiaramente «scegliere il metodo più semplice che soddisfa i requisiti (un verb statico)».9
- Dopo registrazione o modifica, notificate con SHChangeNotify(SHCNE_ASSOCCHANGED); alla disinstallazione eliminate il ProgID ma non eliminate il valore predefinito della chiave di estensione — questa è la guida ufficiale. L’integrazione con la shell include la progettazione della pulizia.110
In una frase: il mondo delle associazioni e dei verb è invariato; solo come si mostra il menu si è diviso in due in Windows 11. Di seguito lo percorriamo dal fondamento.
2. Come funziona l’associazione file — la struttura a tre strati chiave di estensione → ProgID → verb
2.1. Leggere la struttura a tre strati da un esempio
Cosa succede quando fate doppio clic su un file di una data estensione lo decidono tre strati di chiavi del registro.1
HKEY_CLASSES_ROOT
.kmrpt ← (1) Chiave di estensione
(Default) = KomuraSoft.Report.1 ← Un puntatore che nomina solo il ProgID
OpenWithProgids
KomuraSoft.Report.1 ← Un candidato in «Apri con»
KomuraSoft.Report.1 ← (2) ProgID (la sostanza dell'associazione)
(Default) = Komura Report document
DefaultIcon
(Default) = "C:\Program Files\KomuraSoft\Report.exe",0
shell ← (3) Elenco dei verb
open
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
- (1) La chiave di estensione (
.kmrpt) punta solo a un nome ProgID come valore predefinito. Scrivere qui un comando direttamente è un errore. - (2) Il ProgID (
KomuraSoft.Report.1) è la sostanza dell’associazione; contiene il nome visualizzato, l’icona e l’elenco dei verb. - (3) Un verb è un’azione come «apri» o «stampa», e il valore predefinito di
shell\open\commandè la riga di comando effettivamente avviata.
Questa separazione è il motivo per cui potete puntare più estensioni (.kmrpt e .kmrpt-file, per esempio) allo stesso ProgID, o scambiare il ProgID quando aggiornate l’app.
flowchart TB
accTitle: La struttura a tre strati dell'associazione file
accDescr: La chiave di estensione è un puntatore il cui valore predefinito nomina un ProgID; il ProgID è la sostanza che contiene nome visualizzato, icona ed elenco dei verb; e il valore predefinito di command sotto il verb è la riga di comando effettivamente avviata
ext["Chiave di estensione .kmrpt"] -->|nomina il ProgID come predefinito| pid["ProgID KomuraSoft.Report.1"]
pid --> vb["verb(open e altri sotto shell)"]
vb --> cmd["valore predefinito di command"]
cmd --> exe["Report.exe viene avviato"]
pid -.-> attr["Contiene anche il nome visualizzato e DefaultIcon"]
Figura 1: La chiave di estensione è un puntatore, il ProgID è la sostanza, e il command del verb è la riga di comando effettivamente avviata.
2.2. HKCR è una «vista unita» — dove scrivete cambia il significato
L’esempio sopra è mostrato sotto HKEY_CLASSES_ROOT (HKCR), ma HKCR non è una posizione di archiviazione fisica; è una vista unita di HKLM\Software\Classes e HKCU\Software\Classes. Se la stessa chiave esiste in entrambi, vince il lato HKCU.2
flowchart TB
accTitle: HKCR è una vista unita
accDescr: HKCR è HKLM e HKCU Classes sovrapposti; se la stessa chiave esiste in entrambi, vince HKCU; scrivete la registrazione in HKLM o HKCU in modo esplicito e trattate HKCR come sola lettura
hklm["HKLM\\Software\\Classes(tutti gli utenti)"] --> hkcr["HKCR(vista unita)"]
hkcu["HKCU\\Software\\Classes(per utente)"] --> hkcr
hkcu -.-> win["Se esiste la stessa chiave, vince HKCU"]
hkcr -.-> ro["Trattatelo come sola lettura(per conferma)"]
Figura 2: HKCR è come appaiono HKLM e HKCU Classes quando sono sovrapposti; nominate sempre l’uno o l’altro come destinazione di scrittura.
| Destinazione di scrittura | Significato | Diritti richiesti |
|---|---|---|
HKLM\Software\Classes |
Registrazione comune a tutti gli utenti | Amministratore |
HKCU\Software\Classes |
Registrazione solo per quell’utente | Nessuno |
Scrivere direttamente in HKCR |
Instradato a seconda di dove vive già la chiave esistente | Dipende |
In pratica, la scissione sicura è scrivere sempre la registrazione in HKLM o HKCU in modo esplicito, e trattare HKCR come sola lettura (per conferma). Vale anche la pena ordinare il rapporto con il reindirizzamento del registro WOW64. I dati di associazione direttamente sotto HKLM\Software\Classes come chiavi di estensione e ProgID sono condivisi tra le viste del registro a 32 bit e a 64 bit da Windows 7, quindi un installer a 32 bit che li scrive non fugge sul lato Wow6432Node. Alcune sottochiavi di registrazione COM come Classes\CLSID, invece, sono reindirizzate, e quando registrate un’estensione della shell (COM in-process) la scissione di scrittura 32 bit / 64 bit conta. I dettagli sono in «Registry 32-bit/64-bit Redirection and Virtualization Pitfalls — Wow6432Node and the “The Value I Wrote Isn’t There” Problem».
2.3. Registrazione sul lato app — App Paths, Applications, RegisteredApplications
Ci sono anche tre tipi di registrazione sul lato app, in coppia con il lato file (estensione e ProgID).11
- App Paths (
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths): registrazione che consente aShellExecuteExdi avviare solo con il nome del file eseguibile. Microsoft la raccomanda perché non dovete inquinare la variabile d’ambiente PATH. - Applications (
HKCR\Applications\<app.exe>): definisce il modo predefinito di aprire quando un file arbitrario viene consegnato in «Apri con», e il nome visualizzato dell’app (FriendlyAppName). - RegisteredApplications + Capabilities: dichiara le estensioni e i tipi MIME che l’app può gestire, ed è la registrazione che la fa comparire come candidato nella pagina Impostazioni delle app predefinite di Windows.
La maggior parte delle consultazioni «la nostra app non compare nell’elenco delle app predefinite» sono casi in cui il ProgID è stato registrato e questa registrazione Capabilities è stata omessa.
flowchart TB
accTitle: I tre tipi di registrazione sul lato app
accDescr: La registrazione sul lato app ha tre tipi — App Paths, Applications e RegisteredApplications — responsabili rispettivamente dell'avvio solo con il nome file, del modo predefinito di aprire in Apri con, e della comparsa nella pagina delle app predefinite
app["Registrazione sul lato app"] --> ap["App Paths"]
app --> apps["Applications"]
app --> ra["RegisteredApplications"]
ap --> r1["Avvio solo con il nome file"]
apps --> r2["Predefinito in Apri con"]
ra --> r3["Compare nella pagina delle app predefinite"]
r3 -.-> cap["È richiesta una dichiarazione Capabilities"]
Figura 3: Ci sono tre tipi di registrazione sul lato app, e comparire come candidato delle app predefinite richiede una registrazione Capabilities.
2.4. L’app predefinita appartiene all’utente — protezione UserChoice
Scrivere un ProgID come valore predefinito della chiave di estensione non la rende da sola l’app predefinita. Il risultato della scelta esplicita dell’utente in «Apri con» e simili è conservato in HKCU\...\Explorer\FileExts\<extension>\UserChoice, e la risoluzione dell’associazione preferisce quel lato.
E il punto importante è che Windows non supporta il cambio programmatico dell’app predefinita. Le impostazioni dell’app predefinita sono progettate perché le faccia l’utente tramite l’interfaccia Impostazioni di sistema; i dati UserChoice sono offuscati, e un driver filtro (UCPD.sys) blocca le scritture dalle app. In un ambiente gestito, Criteri di gruppo / criterio MDM è il mezzo ufficiale.3
Che strumenti come SetUserFTA, che «imitano l’hash e lo riscrivono», siano stati usati è l’altro lato di questa protezione. Ciò che dovete mettere nell’installer di un’app interna non è rubare il predefinito, ma i tre (a) registrazione corretta del ProgID e dei verb, (b) aggiungersi a OpenWithProgIds, e (c) se serve, indirizzare alla pagina Impostazioni.
flowchart TB
accTitle: Risoluzione dell'app predefinita e protezione UserChoice
accDescr: Il risultato di una scelta esplicita dell'utente è conservato in UserChoice e preferito nella risoluzione dell'associazione; UCPD.sys blocca le riscritture dalle app, quindi ciò che un installer può fare è registrarsi come candidato e indirizzare alla pagina Impostazioni
uc["UserChoice(la scelta dell'utente)"] -->|preferito| res["Risoluzione dell'associazione"]
ext["Valore predefinito della chiave di estensione"] --> res
wr["Riscrittura da un'app"] -.->|UCPD.sys la blocca| uc
res ~~~ inst["Il lavoro dell'installer"]
inst --> a1["Registrare il ProgID e i verb"]
inst --> a2["Aggiungere a OpenWithProgIds"]
inst --> a3["Indirizzare alla pagina Impostazioni"]
Figura 4: La risoluzione dell’associazione preferisce la scelta dell’utente (UserChoice), e il sistema operativo la protegge dalle riscritture delle app.
3. Verb diversi da «Apri» — print, edit, runas, verb personalizzati
Un verb non è solo open. I verb standard di cui il sistema operativo conosce il significato includono edit, print, play e preview oltre a open, e un verb standard ottiene automaticamente un nome visualizzato che segue le impostazioni locali del sistema. Il verb predefinito usato al doppio clic è deciso nell’ordine: valore predefinito della chiave shell → primo verb nel registro → open → openwith.12
flowchart TB
accTitle: Ordine in cui si decide il verb predefinito
accDescr: Il verb predefinito usato al doppio clic è il primo trovato nell'ordine valore predefinito della chiave shell, primo verb nel registro, open, openwith
s1["valore predefinito della chiave shell"] -->|se nessuno| s2["Primo verb nel registro"]
s2 -->|se nessuno| s3["open"]
s3 -->|se nessuno| s4["openwith"]
Figura 5: Il verb predefinito al doppio clic è il primo trovato in questo ordine.
Quando volete aggiungere un’azione vostra, registrate un verb personalizzato.
KomuraSoft.Report.1
shell
open
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
print
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" /print "%1"
verify ← verb personalizzato
(Default) = Verify report (&V) ← nome visualizzato nel menu
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" /verify "%1"
Tre piccoli fatti che aiuta conoscere.
- Registrate un verb di nome runas e definite un avvio con elevazione equivalente a «Esegui come amministratore», usato anche quando un’API della famiglia
ShellExecutespecificarunas. - Mettete un valore vuoto di nome
Extendedsulla chiave del verb e diventa un verb esteso mostrato solo con Maiusc+clic destro. Comodo per nascondere un’operazione pericolosa usata di rado.12 - Alcune associazioni di app più vecchie hanno ancora una configurazione che invia un documento in un processo esistente con DDE (la chiave
ddeexec), ma avviare un verb via DDE è già un retaggio Deprecated. Non c’è motivo di scriverlo di nuovo.12
Un altro incidente frequente è le virgolette sulla riga di comando. Se un elemento della stringa di comando può contenere uno spazio, dovete avvolgerlo tra virgolette. Vale ovviamente per un percorso EXE come C:\Program Files\..., e %1 (il percorso del file selezionato) va sempre scritto "%1". Non potete garantire che il percorso di un file utente non contenga uno spazio. Un My Program.exe senza virgolette è interpretato come «avvia My con l’argomento Program.exe».13
flowchart TB
accTitle: L'incidente delle virgolette sulla riga di comando
accDescr: Un comando senza virgolette viene spezzato allo spazio e frainteso come avvio di My con l'argomento Program.exe, quindi un percorso EXE che può contenere uno spazio e %1, che rappresenta il percorso del file selezionato, vanno sempre avvolti tra virgolette
c1["Comando senza virgolette"] -->|spezzato allo spazio| bad["Frainteso come avvio di un altro EXE"]
c2["Comando con virgolette"] --> good["Si avvia come previsto"]
c2 -.-> q1["Avvolgete il percorso EXE tra virgolette"]
q1 -.-> q2["Avvolgete sempre anche %1 tra virgolette"]
Figura 6: Un comando senza virgolette viene spezzato male allo spazio, quindi avvolgete sempre il percorso EXE e %1 tra virgolette.
Il meccanismo solo-registro finora (un verb statico) si può realizzare senza scrivere una sola DLL, e non rischia di rendere instabile Esplora risorse. Microsoft stessa ripete «prima di scrivere un’estensione della shell, considerate se il verb statico più semplice che soddisfa i requisiti basta».9
4. Estensioni della shell classiche — una DLL che gira dentro Esplora risorse
4.1. Tipi di estensione della shell
I requisiti che un verb statico non può soddisfare — «cambiare il menu in modo dinamico a seconda della selezione», «sostituire l’icona o il foglio proprietà» — usano un gestore di estensione della shell. I tipi rappresentativi sono i seguenti.4
| Gestore | Interfaccia principale | Cosa può fare |
|---|---|---|
| Gestore di menu contestuale | IContextMenu + IShellExtInit | Aggiungere e controllare dinamicamente le voci di menu |
| Gestore di icone / overlay di icone | IExtractIcon / IShellIconOverlayIdentifier | Icona per file e overlay |
| Gestore di foglio proprietà | IShellPropSheetExt | Aggiungere una scheda al foglio proprietà |
| Miniatura / infotip | IThumbnailProvider / IQueryInfo | Vista miniatura e descrizione al passaggio |
| Gestore drag-and-drop / copy-hook | IDropTarget / ICopyHook | Intervenire al rilascio o a copia/spostamento |
Tutti sono implementati come classi COM e registrati nel registro per CLSID. L’idea di COM in sé è in «COM, ActiveX e OCX — Distinzioni pratiche per chi eredita sistemi Windows».
4.2. Cosa significa essere un server COM in-process
L’essenza di un’estensione della shell classica è che è un server COM in-process (DLL) caricato in Esplora risorse (o in qualsiasi app che ha aperto una finestra di dialogo file comune). Ogni cautela ne consegue.4
- Se l’estensione va in crash, Esplora risorse viene portato giù con essa. Se si blocca, un clic destro si congela per diversi secondi. Il danno non si limita a Esplora risorse; raggiunge ogni app che ha mostrato una finestra di apertura file.
- La costruzione del menu avviene sul thread UI, quindi non dovete fare lavoro lento come accesso di rete o I/O di file al momento della visualizzazione del menu.
- Registrate il modello di threading come
Apartmentdi regola.
flowchart TB
accTitle: Struttura dei danni collaterali di un'estensione in-process
accDescr: Una DLL di estensione della shell viene caricata non solo in Esplora risorse ma anche nel processo di qualsiasi app che ha aperto una finestra di dialogo file, quindi un crash o un blocco dell'estensione si propaga a tutto il processo ospite
dll["DLL di estensione della shell"] -->|caricata in-process| exp["Esplora risorse"]
dll -->|caricata in-process| any["Qualsiasi app che apre una finestra di dialogo"]
exp --> dmg["Un crash o un blocco si propaga"]
any --> dmg
dmg -.-> rule["Non fare lavoro lento in visualizzazione"]
Figura 7: La DLL dell’estensione gira dentro il processo ospite, quindi un crash o un blocco si propaga all’ospite nel suo insieme.
Indagate una consultazione come «Esplora risorse si congela quando apro una cartella particolare» o «un clic destro impiega cinque secondi» e non è raro che la causa sia un’estensione della shell di terze parti piuttosto che l’app interna. I metodi di isolamento sono nel capitolo 8.
4.3. Allineare la bitness — un ambiente a 64 bit richiede una DLL a 64 bit
Una DLL in-process deve coincidere con la bitness del processo che la carica. Esplora risorse su Windows a 64 bit è un processo a 64 bit, quindi una DLL di estensione della shell compilata solo a 32 bit non viene mai caricata e non compare affatto nel menu. Non c’è nemmeno un errore, quindi è una causa classica di «l’ho registrata ma non compare». Combinare un corpo app a 32 bit con una DLL di estensione della shell a 64 bit è una configurazione legittima, ma dovete osservare il fatto che la registrazione COM si divide per bitness (Wow6432Node). L’avvio dal command di un verb è un EXE in processo separato, quindi non è soggetto a questo vincolo (lasciarlo un EXE a 32 bit va bene).
flowchart TB
accTitle: Allineare la bitness di una DLL di estensione della shell
accDescr: L'unica DLL di estensione della shell che Esplora risorse a 64 bit può caricare è una a 64 bit; una DLL solo a 32 bit non compare nel menu e non produce errore; un EXE avviato da un command di verb è un processo separato e non è soggetto al vincolo
exp["Esplora risorse a 64 bit"] -->|può caricare| d64["DLL di estensione della shell a 64 bit"]
exp -.->|non può caricare| d32["DLL solo a 32 bit"]
d32 -.-> sym["Non compare nel menu, senza errore"]
exe["EXE avviato da un verb"] -->|processo separato| ok32["Va bene lasciato a 32 bit"]
Figura 8: L’unica DLL caricata in Esplora risorse a 64 bit è una DLL a 64 bit; un EXE avviato da un verb non è soggetto a questo vincolo.
4.4. Perché non dovete scriverla in codice gestito
Mi fanno spesso la domanda «posso scrivere un’estensione della shell in C#», ma Microsoft ha detto chiaramente che scrivere un’estensione della shell in-process in codice gestito (.NET) non è raccomandato ed è fuori dal supporto.5
Il motivo è la natura dell’estensione caricata in un processo arbitrario. Collisioni di versione del CLR (soprattutto sotto .NET Framework 4), il problema del CLR che rientra nel ciclo dei messaggi mentre attende un lock, e la durata degli oggetti non deterministica della garbage collection che collide con il contratto di conteggio dei riferimenti di COM sono ragioni strutturali per cui l’app ospite diventa instabile. Alcuni punti sono stati attenuati su .NET Framework 4 e successivi e sul .NET moderno, ma la posizione ufficiale non è cambiata.
La linea pratica è semplice. Scrivete un’estensione in-process in C++ nativo. Se volete usare codice gestito, fatene un EXE normale avviato dal command di un verb, o un’estensione out-of-process che gira in un processo separato (un gestore di anteprima e simili).5
flowchart TB
accTitle: Giudicare se il codice gestito è consentito
accDescr: Un'estensione in-process che gira dentro Esplora risorse si scrive in C++ nativo di regola; se volete codice gestito, fatene un EXE normale avviato da un command di verb o un'estensione out-of-process che gira in un processo separato
q1{"Gira in-process?"} -->|sì| cpp["Scrivetela in C++ nativo"]
q1 -->|no| mg["Il codice gestito va bene"]
cpp -.-> why["Rischio CLR / rientranza rende l'ospite instabile"]
mg --> e1["EXE avviato da un verb"]
mg --> e2["Anteprima out-of-process"]
Figura 9: Un’estensione in-process è C++ nativo di regola; il codice gestito è limitato a una configurazione che gira in un processo separato.
5. Il nuovo menu contestuale di Windows 11 — il menu diviso in due
5.1. Cosa è successo
Windows 11 ha rinnovato il menu contestuale di Esplora file. Taglia, copia e simili sono diventati una riga di icone in alto; «Apri» e «Apri con» sono stati raggruppati in alto; e i comandi che un’app aggiunge sono raggruppati sotto i comandi standard della shell. Quando un’app aggiunge più comandi, vengono raccolti in un flyout (sottomenu) con il nome dell’app.6
E il punto cruciale è questo. Le estensioni della shell classiche basate su IContextMenu non sono state eliminate; sono state spostate sul lato del vecchio menu che si apre con «Mostra altre opzioni» (Maiusc+F10) e carica il menu di Windows 10 così com’è.6 L’identità della consultazione iniziale «il menu è stato nascosto» è questa divisione.
flowchart TB
accTitle: Il menu contestuale che Windows 11 ha diviso in due
accDescr: Ciò che si apre per primo al clic destro è il nuovo menu; le uniche comandi che vi compaiono sono quelle registrate con IExplorerCommand e identità di pacchetto; le estensioni IContextMenu classiche sono spostate nel vecchio menu che si apre con Mostra altre opzioni
rc["Clic destro su un file"] --> newm["Nuovo menu(Windows 11)"]
newm --> newi["Comandi IExplorerCommand + identità"]
newm -->|Mostra altre opzioni Maiusc+F10| oldm["Vecchio menu(il menu di Windows 10)"]
oldm --> oldi["Estensioni IContextMenu classiche"]
newi -.-> fly["Più comandi vengono raccolti in un flyout"]
Figura 10: Gli unici comandi che compaiono nel nuovo menu sono i comandi IExplorerCommand + identità; le estensioni classiche sono spostate sul lato del vecchio menu.
5.2. La via ufficiale nel nuovo menu — IExplorerCommand + registrazione nel manifesto
C’è un modo per mettere un comando personalizzato nel nuovo menu. Preparate una DLL nativa che implementa l’interfaccia IExplorerCommand, e dichiarate il server COM e l’estensione del menu contestuale in un manifesto di pacchetto MSIX.7
<!-- Manifesto del pacchetto (estratto) -->
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="Komura commands">
<com:Class Id="01234567-89AB-CDEF-0123-456789ABCDEF"
Path="KomuraCommand.dll" ThreadingModel="STA" />
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type=".kmrpt">
<desktop5:Verb Id="VerifyReport"
Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
Il Type di ItemType può specificare una particolare estensione, o * (tutti i file), Directory (cartelle) o Directory\Background (uno sfondo di cartella). Allineate la DLL all’architettura di Esplora risorse (64 bit / ARM64).7
IExplorerCommand stessa è un’interfaccia esistente dall’epoca di Windows 7; implementate il titolo (GetTitle), l’icona (GetIcon), lo stato abilitato / disabilitato / nascosto (GetState) e l’esecuzione (Invoke). I metodi sono chiamati dal thread UI, quindi l’accesso a risorse di rete è vietato, e i metodi di costruzione del menu devono tornare in fretta. Il lavoro pesante dopo Invoke.147
flowchart TB
accTitle: Struttura del manifesto di una registrazione nel nuovo menu
accDescr: La dichiarazione del server COM del manifesto MSIX mappa un CLSID a una DLL, e la dichiarazione di estensione del menu contestuale lega destinazione e implementazione con ItemType e Verb, così un comando personalizzato compare nel nuovo menu
man["Manifesto MSIX"] --> com["Dichiarazione del server COM"]
man --> ctx["Dichiarazione di estensione del menu"]
com -->|mappa il CLSID alla DLL| impl["DLL di implementazione IExplorerCommand"]
ctx -->|specifica con ItemType e Verb| impl
impl --> shown["Il comando compare nel nuovo menu"]
ctx -.-> tgt["La destinazione è un'estensione, tutti i file e simili"]
Figura 11: Due dichiarazioni nel manifesto legano la DLL di implementazione alla destinazione, e il comando compare nel nuovo menu.
5.3. L’opzione per un’app non impacchettata — ottenere solo l’identità con uno sparse package
La via di fuga quando «la nostra app non può essere distribuita se non come MSI; MSIX è impossibile» è uno sparse package (MSIX con posizione esterna). Firmate un piccolo MSIX che è solo un manifesto, senza corpo dell’app, e lo registrate alla fine dell’installer esistente. L’app acquisisce allora identità di pacchetto, e la registrazione nel manifesto sopra (= comparsa nel nuovo menu) diventa possibile. È disponibile da Windows 10 versione 2004 in poi, e il pacchetto necessita di una firma con un certificato attendibile sulla macchina di destinazione.8
flowchart TB
accTitle: Il flusso per ottenere l'identità con uno sparse package
accDescr: Dopo che l'installer esistente ha collocato il corpo dell'app, registrare uno sparse package di solo manifesto con una posizione esterna dà all'app identità di pacchetto e rende possibile la registrazione nel manifesto del nuovo menu
inst["Installer esistente"] --> files["Collocare il corpo dell'app"]
sp["Sparse package"] -.-> only["Solo manifesto, nessun corpo"]
files --> reg["Registrare con una posizione esterna"]
sp --> reg
reg --> id["Acquisire identità di pacchetto"]
id --> ok["La registrazione nel nuovo menu diventa possibile"]
sp -.-> sign["È richiesta una firma attendibile"]
Figura 12: Registrate uno sparse package che non contiene il corpo, con una posizione esterna, e l’app acquisisce identità di pacchetto.
Il vantaggio maggiore è che non dovete sostituire l’installer; è la risposta realistica per un’app che ha già un asset di installer MSI/EXE. Per un confronto con un passaggio completo a MSIX, vedete anche «Scegliere un metodo di distribuzione per app Windows - MSI/MSIX/ClickOnce/xcopy/Updater personalizzato».
5.4. Come i verb di associazione compaiono nel nuovo menu
Un punto facile da fraintendere: le associazioni dei capitoli 2 e 3 (ProgID e verb) sono ancora vive nel nuovo menu. Il verb predefinito al doppio clic, «Apri» e i candidati «Apri con» sono risolti dall’associazione e mostrati in cima al nuovo menu. Quindi se tutto ciò che volete è «poter aprire con questa app», Windows 11 non richiede lavoro extra. D’altra parte, un’associazione non è un’estensione di menu per uso generale, quindi se volete un comando personalizzato arbitrario nel primo strato del nuovo menu serve IExplorerCommand più identità — questa è la divisione dei ruoli.7
flowchart TB
accTitle: La divisione dei ruoli tra associazioni e nuovo menu
accDescr: Un'associazione ProgID-e-verb è ancora usata nel nuovo menu per risolvere il verb predefinito, Apri e Apri con, ed è mostrata in cima; mettere un comando personalizzato arbitrario nel primo strato del nuovo menu richiede IExplorerCommand e identità
assoc["Assoc.(ProgID + verb)"] --> sol["Risolvere predefinito / Apri"]
sol --> top["Cima del nuovo menu"]
assoc -.-> keep["Nessun lavoro extra su Win11"]
cmd["Un comando personalizzato"] --> need["IExplorerCommand+identità"]
need --> first["Primo strato del nuovo menu"]
Figura 13: Le associazioni gestiscono ancora la risoluzione della famiglia «Apri» nel nuovo menu; solo un comando personalizzato richiede IExplorerCommand più identità.
6. Una tabella di decisione pratica — quale delle tre opzioni prendere
Organizziamo quanto visto finora in una scelta pratica a tre vie.
| Cosa volete ottenere | Mezzo raccomandato | Come appare in Windows 11 | Lavoro e costo richiesti |
|---|---|---|---|
| (a) Avviare l’app interna al doppio clic o «Apri» | Associazione + verb statico (solo registrazione nel registro) | Integrato in «Apri» e «Apri con» nel nuovo menu | Solo registrazione nel registro dell’installer. Nessuna DLL, nessun requisito extra di firma |
| (b) Mettere un comando personalizzato per il file/cartella selezionato nel nuovo menu | Implementazione IExplorerCommand + registrazione nel manifesto MSIX. Un’app non impacchettata riceve identità con uno sparse package | Primo strato del nuovo menu (più comandi raccolti in un flyout con il nome dell’app) | DLL C++ nativa + identità di pacchetto + firma del codice |
| (c) Continuare a usare un’estensione IContextMenu classica esistente | Tenerla com’è per ora (non sceglierla per un nuovo sviluppo) | Solo lato del vecchio menu, sotto «Mostra altre opzioni» (Maiusc+F10) | Mantenere una build a 64 bit e la registrazione COM. Pianificare un passaggio successivo a (b) |
Ci sono due punti di giudizio. Primo, non portate (b) o (c) per un requisito che (a) soddisfa. Nel momento in cui scrivete un’estensione della shell vi assumete la responsabilità della stabilità di Esplora risorse. Secondo, (c) è solo «non rotto»; come esperienza utente resta un passo peggiore. Più un comando è usato di frequente nell’esercizio quotidiano, maggiore è il ritorno di un passaggio a (b).
flowchart TB
accTitle: Come scegliere tra le tre opzioni
accDescr: Se tutto ciò che volete è l'avvio al doppio clic o Apri, bastano un'associazione e un verb statico; per mettere un comando personalizzato nel nuovo menu usate IExplorerCommand e la registrazione nel manifesto MSIX; se non potete diventare MSIX, concedete l'identità con uno sparse package; tenete un'estensione IContextMenu classica esistente sul lato del vecchio menu per ora
q1{"Basta Apri?"} -->|sì| pa["Assoc. + verb statico"]
q1 -->|no| q2{"Personalizzato nel nuovo menu?"}
q2 -->|sì| q3{"Potete diventare MSIX?"}
q3 -->|sì| pb1["IExplorerCommand+MSIX"]
q3 -->|no| pb2["Identità sparse-pkg"]
q2 -->|no| pc["Tenere il classico per ora"]
pc -.-> old["Solo lato del vecchio menu"]
pa -.-> dllfree["Nessuna DLL, rischio piccolo"]
Figura 14: Scegliete tra un verb statico, IExplorerCommand più identità e il tenere il classico, secondo il requisito.
7. Distribuzione e registrazione in pratica — installer, sparse package, pulizia
7.1. HKLM o HKCU
Allineatelo alla forma dell’installer. Tutti gli utenti (collocato sotto Program Files, diritti di amministratore) è HKLM\Software\Classes; installazione per utente (senza elevazione) è HKCU\Software\Classes. Mischiateli e produce la richiesta del tipo «A può aprirlo ma B no». Per un’estensione della shell che implica registrazione CLSID, Reg-Free COM — che elimina il bisogno della registrazione nel registro stessa — è un’opzione valida per l’uso COM in-app, ma non si può applicare a un’estensione della shell che Esplora risorse carica, quindi serve la registrazione frontale («Cos’è Reg-Free COM - Utilizzo di COM senza registrazione»).
7.2. Dopo una modifica, notificate — SHChangeNotify
Dopo aver registrato, modificato o eliminato un’associazione, notificate l’evento SHCNE_ASSOCCHANGED con SHChangeNotify. Saltate questo e Esplora risorse può non accorgersi della modifica fino a un riavvio.110
// Chiamare una volta dopo aver modificato le associazioni, p. es. da un'azione personalizzata dell'installer
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
7.3. Registrare e rimuovere uno sparse package
Registrare e rimuovere uno sparse package è il lavoro dell’installer. Registrate dopo aver collocato i file; rimuovete prima di eliminare i file.8
# In installazione: dopo aver collocato i file, registrare la cartella di installazione come posizione esterna
Add-AppxPackage -Path "C:\Program Files\KomuraSoft\KomuraReport.identity.msix" `
-ExternalLocation "C:\Program Files\KomuraSoft"
# In disinstallazione: rimuovere la registrazione del pacchetto prima di eliminare i file
Remove-AppxPackage <package full name>
Un punto da osservare: Add-AppxPackage registra per l’utente che l’ha eseguito. Se lo chiamate da un’azione personalizzata di un MSI per macchina, eseguirlo sotto LocalSystem non concede identità all’utente che ha installato, quindi lo configurate per girare sotto impersonation dell’utente. Anche allora, la registrazione sotto impersonation è solo per l’utente che ha eseguito quella installazione. Su un PC usato da più utenti, gli altri utenti e gli utenti creati dopo non hanno identità di pacchetto, e il comando non compare nel nuovo menu. Perché ogni utente lo usi, fornite un meccanismo come controllare la propria registrazione del pacchetto al primo avvio e registrare se manca (registrazione per utente), e includete la rimozione da ogni utente che ha una registrazione nel piano di disinstallazione. Riflettere una registrazione nel manifesto può anche richiedere un riavvio di Esplora risorse (o una disconnessione).7
flowchart TB
accTitle: Ordine di registrazione e rimozione di uno sparse package
accDescr: In installazione registrate lo sparse package dopo aver collocato i file; in disinstallazione rimuovete la registrazione prima di eliminare i file; osservate il fatto che la registrazione è efficace solo per l'utente che l'ha eseguita
i1["Installazione"] --> i2["Collocare i file"]
i2 --> i3["Registrare lo sparse package"]
u1["Disinstallazione"] --> u2["Rimuovere la registrazione del pacchetto"]
u2 --> u3["Eliminare i file"]
i3 -.-> pu["La registrazione è efficace solo per l'utente in esecuzione"]
Figura 15: Registrate dopo aver collocato i file, rimuovete prima di eliminarli, e osservate il fatto che la registrazione è per utente in esecuzione.
7.4. Pulizia alla disinstallazione — cosa eliminare e cosa lasciare
La pulizia alla disinstallazione ha una linea di guida ufficiale chiara.1
- Eliminare: l’intera chiave ProgID interna, la registrazione Capabilities/RegisteredApplications, la registrazione CLSID dell’estensione della shell, lo sparse package (Remove-AppxPackage).
- Lasciare: il valore predefinito della chiave di estensione (
.kmrpt). La raccomandazione ufficiale è di non eliminarlo anche se punta ancora al ProgID interno. Giudicare dopo l’installazione se un’altra app ha preso il predefinito è difficile, e Windows ignora semplicemente un ProgID di valore predefinito che non è registrato, quindi lasciarlo non fa un danno reale. - Chiamate SHChangeNotify(SHCNE_ASSOCCHANGED) anche alla fine della pulizia.
La maggior parte dei problemi «abbiamo disinstallato e i resti compaiono ancora nel menu» è una perdita in questa progettazione della pulizia.
flowchart TB
accTitle: Progettazione della pulizia alla disinstallazione
accDescr: Alla disinstallazione eliminate la chiave ProgID interna, la registrazione CLSID e lo sparse package; lasciate il valore predefinito della chiave di estensione perché un ProgID non registrato viene ignorato; notificate la modifica con SHChangeNotify alla fine della pulizia
un["Disinstallazione"] --> del["Eliminare"]
un --> keep["Lasciare"]
del --> d1["Registrazione ProgID e CLSID"]
del --> d2["Sparse package"]
keep --> k1["Valore predefinito della chiave di estensione"]
k1 -.-> why["Un ProgID non registrato viene ignorato"]
d1 --> fin["Notificare con SHChangeNotify alla fine"]
k1 --> fin
Figura 16: Eliminate la registrazione interna, lasciate il valore predefinito della chiave di estensione e notificate la modifica alla fine della pulizia.
8. Risoluzione dei problemi — mancante, duplicato, pesante
8.1. Non compare nel menu
Isolate in questo ordine.
- Quale menu state guardando: una registrazione in stile classico compare solo sul lato del vecchio menu sotto Maiusc+F10. Controllate entrambi prima.
- Bitness: una DLL di estensione della shell solo a 32 bit non viene caricata in Esplora risorse a 64 bit (sezione 4.3).
- Destinazione di registrazione: HKLM/HKCU, una confusione Wow6432Node. Confermate la chiave reale con
reg query. - Registrazione del pacchetto: per il nuovo menu, confermate la presenza con
Get-AppxPackage, l’attendibilità del certificato di firma e il percorso-ExternalLocation, poi riavviate Esplora risorse.7 - Notifica dimenticata: se SHChangeNotify è stato dimenticato, potete dirlo da se un riavvio di Esplora risorse lo fa entrare in vigore.
flowchart TB
accTitle: Ordine di isolamento quando non compare nel menu
accDescr: Iniziate confermando quale menu state guardando, poi isolate la bitness della DLL, la destinazione di registrazione nel registro, la registrazione del pacchetto e la firma, e una notifica SHChangeNotify dimenticata, in quest'ordine
c1["Confermare quale menu, vecchio o nuovo"] --> c2["Confermare la bitness della DLL"]
c2 --> c3["Confermare la destinazione di registrazione HKLM e HKCU"]
c3 --> c4["Confermare registrazione del pacchetto e firma"]
c4 --> c5["Dire una notifica dimenticata riavviando"]
Figura 17: Quando «non compare», isolate nell’ordine menu che state guardando, bitness, destinazione di registrazione, registrazione del pacchetto, notifica dimenticata.
8.2. Compare due volte, o non scompare
Le cause tipiche sono la coesistenza di una registrazione classica nel registro e di una registrazione nel manifesto, una perdita nella pulizia della disinstallazione (sezione 7.4) o resti di un ProgID di versione precedente. Se compare due volte solo nel vecchio menu, pensate a resti; se compare su vecchio e nuovo, pensate a coesistenza.
flowchart TB
accTitle: Isolare una doppia visualizzazione
accDescr: Due volte solo nel vecchio menu punta a resti come una perdita di pulizia o un vecchio ProgID; due volte su vecchio e nuovo punta alla coesistenza di una registrazione classica nel registro e di una registrazione nel manifesto
q{"Su quale compare due volte?"} -->|solo vecchio menu| zan["Resti"]
q -->|vecchio e nuovo| hei["Coesistenza"]
zan -.-> z1["Perdita di pulizia o un vecchio ProgID rimasto"]
hei -.-> h1["Registrazione classica nel registro che coesiste con la nuova"]
Figura 18: Due volte solo nel vecchio menu punta a resti; due volte su vecchio e nuovo punta a coesistenza.
8.3. Esplora risorse è pesante o va in crash
Quando un clic destro è lento, o una cartella particolare va in crash, fate prima l’inventario delle estensioni della shell installate. Elencate le estensioni non Microsoft con uno strumento come ShellExView di NirSoft, disabilitate temporaneamente quelle sospette e identificate la DLL colpevole con una ricerca binaria. In un crash, il «Faulting module» del Visualizzatore eventi è anche un indizio. Se l’estensione interna era la causa, sospettate I/O sincrono o accesso di rete sul percorso di costruzione del menu (sezioni 4.2 e 5.2).
flowchart TB
accTitle: Identificare la DLL colpevole quando è pesante o va in crash
accDescr: Elencate le estensioni della shell non Microsoft in ShellExView, disabilitate temporaneamente quelle sospette e identificate la DLL colpevole con una ricerca binaria; in un crash, il faulting module del Visualizzatore eventi è anche un indizio
s1["Inventariare le estensioni della shell"] --> s2["Elencare quelle non Microsoft"]
s2 --> s3["Disabilitare temporaneamente e ricerca binaria"]
s3 --> s4["Identificare la DLL colpevole"]
crash["In un crash"] -.-> ev["Controllare il faulting module"]
ev -.-> s4
Figura 19: Disabilitate temporaneamente le estensioni non Microsoft e fate una ricerca binaria; in un crash usate anche il Visualizzatore eventi.
8.4. Windows Sandbox è comodo per la verifica
La verifica dell’integrazione con la shell si basa sul confermare «installare su un ambiente pulito → operare → disinstallare → resti zero». Comodo qui è Windows Sandbox (Pro/Enterprise/Education): ogni avvio porta in pochi secondi un Windows usa-e-getta nuovissimo, quindi potete eseguire i test di registrazione e pulizia dell’installer quante volte volete. Chiudetelo e tutto scompare, quindi va anche per l’indagine del registro residuo.15
9. Riassunto
- L’associazione file è la struttura a tre strati «chiave di estensione → ProgID → verb», e HKCR è una vista unita di HKLM/HKCU Classes. Nominate la destinazione di scrittura in modo esplicito e avvolgete sempre
%1tra virgolette. - L’app predefinita è progettata perché la scelga l’utente e non si può cambiare da un programma. Il lavoro dell’installer è registrarsi correttamente come candidato.
- Un’estensione della shell classica è una DLL COM in-process caricata in Esplora risorse. Un crash o un ritardo si propaga al tutto; servono 64 bit; il codice gestito non è supportato; l’implementazione in C++ nativo è la regola.
- In Windows 11 il menu contestuale si è diviso in due. Mettere un comando personalizzato nel nuovo menu richiede IExplorerCommand più un manifesto MSIX; IContextMenu classico è spostato sul lato «Mostra altre opzioni».
- Per un’app che non può diventare MSIX, ottenere l’identità con uno sparse package (MSIX con posizione esterna) è la risposta realistica.
- Se tutto ciò che volete è «aprire con questa app», un’associazione e un verb statico bastano ancora. Partire dal mezzo più semplice è anche la linea guida ufficiale.
- Dopo registrazione, modifica o eliminazione, notificate con SHChangeNotify; alla disinstallazione eliminate il ProgID ma lasciate il valore predefinito della chiave di estensione. Windows Sandbox è comodo per la verifica.
Se un ricambio di PC Windows 11 vi ha fatto notare che «il menu è stato nascosto», confermate prima quale di (a), (b) e (c) nella tabella di decisione del capitolo 6 è. Dovreste poter stimare la scala del lavoro sul posto.
Articoli correlati
- COM, ActiveX e OCX — Distinzioni pratiche per chi eredita sistemi Windows
- Cos’è Reg-Free COM - Utilizzo di COM senza registrazione
- Registry 32-bit/64-bit Redirection and Virtualization Pitfalls — Wow6432Node and the “The Value I Wrote Isn’t There” Problem
- Scegliere un metodo di distribuzione per app Windows - MSI/MSIX/ClickOnce/xcopy/Updater personalizzato
- DLL and COM Interface Backward Compatibility — A Decision Table for Which Changes Break Callers
- Come funziona la compatibilità delle app Windows — tenere in vita le app vecchie con la modalità di compatibilità, gli shim e Compatibility Administrator
Aree di consulenza correlate
KomuraSoft LLC si occupa della progettazione e dell’implementazione di associazione file, menu contestuali ed estensioni della shell per app aziendali; del puntare al nuovo menu contestuale di Windows 11 (passaggio a IExplorerCommand, introduzione di uno sparse package); della revisione di registrazione e pulizia di un installer esistente; e dell’indagine della causa di un Esplora risorse pesante o in crash. Va bene partire dal decidere cosa fare del «menu che è stato nascosto sotto Mostra altre opzioni».
- Sviluppo di applicazioni Windows
- Riutilizzo e migrazione delle risorse esistenti
- Consulenza tecnica e revisione del progetto
- Contattaci
Riferimenti
-
Microsoft Learn, File Types. Sulla struttura di una chiave di estensione che punta a un ProgID; OpenWithProgIds; la scissione della registrazione tra HKLM/HKCU\Software\Classes; la chiamata di SHChangeNotify(SHCNE_ASSOCCHANGED) dopo un cambio di associazione; e l’eliminazione del ProgID alla disinstallazione lasciando il valore predefinito della chiave di estensione. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, HKEY_CLASSES_ROOT Key. Sul fatto che HKEY_CLASSES_ROOT è una vista unita di HKLM\Software\Classes e HKCU\Software\Classes; le definizioni lato utente hanno priorità su quelle lato macchina; e le regole di instradamento in scrittura. ↩ ↩2
-
Microsoft Learn, Windows app defaults platform. Sul fatto che il cambio dell’app predefinita è progettato per essere fatto solo tramite l’interfaccia Impostazioni di sistema; i dati delle impostazioni utente sono offuscati e protetti in scrittura da un driver filtro (UCPD.sys); il cambio basato sul registro non è supportato; e l’uso di Criteri di gruppo / criterio MDM in un ambiente gestito. ↩ ↩2
-
Microsoft Learn, Working with Shell Extensions. Sui tipi di gestore di estensione della shell; un’estensione come DLL COM in-process caricata in Esplora risorse (e nei processi che ospitano la shell), così che un crash o un blocco si propaga a Esplora risorse nel suo insieme; la registrazione con ThreadingModel=Apartment; e il considerare un’alternativa più semplice prima di un’estensione della shell. ↩ ↩2 ↩3
-
Microsoft Learn, Guidance for Implementing In-Process Extensions. Sul fatto che Microsoft non raccomanda e non supporta un’implementazione di estensione della shell in-process in codice gestito; i motivi tra cui collisioni di versione del CLR, rientranza e durata degli oggetti non deterministica; e il codice gestito accettabile per un’estensione out-of-process (un gestore di anteprima, o un avvio da shell\verb\command). ↩ ↩2 ↩3
-
Windows Developer Blog, Extending the Context Menu and Share Dialog in Windows 11. Sulla progettazione del nuovo menu contestuale di Windows 11; l’estensione tramite IExplorerCommand più identità dell’app; il collocare «Apri» e «Apri con» in cima; il raccogliere più comandi in un flyout con il nome dell’app; e le estensioni IContextMenu classiche caricate come il menu di Windows 10 sotto «Mostra altre opzioni» (Maiusc+F10). ↩ ↩2 ↩3
-
Microsoft Learn, Add a File Explorer context menu command to a packaged desktop app. Sul fatto che la registrazione nel nuovo menu contestuale di Windows 11 avviene con un’implementazione IExplorerCommand più windows.comServer più una dichiarazione di manifesto desktop4:FileExplorerContextMenus; ItemType può specificare *, Directory o Directory\Background; l’allineamento dell’architettura della DLL; il mantenere veloci i metodi di costruzione del menu; la copertura di un’app non impacchettata con uno sparse package; un riavvio di Esplora risorse a volte richiesto perché la registrazione abbia effetto; e un’associazione file che non è un’estensione di menu per uso generale. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Grant package identity by packaging with external location. Sull’ottenere identità di pacchetto registrando un pacchetto a posizione esterna (sparse package) senza cambiare l’installer esistente; la disponibilità da Windows 10 versione 2004 in poi; e le funzioni Windows che richiedono identità (registrazione nel menu contestuale, notifiche e simili) che diventano usabili. ↩ ↩2 ↩3
-
Microsoft Learn, Choosing a Static or Dynamic Shortcut Menu Method. Sul scegliere il metodo di verb statico più semplice che soddisfa i requisiti; IContextMenu come il più potente ma anche il più complesso e classificato verso il lato non raccomandato; e IExplorerCommand/IExplorerCommandState come il metodo raccomandato. ↩ ↩2
-
Microsoft Learn, SHChangeNotify function. Su come sollevare l’evento SHCNE_ASSOCCHANGED che notifica al sistema un cambio di associazione file, e su usarlo perché la shell si accorga della modifica. ↩ ↩2
-
Microsoft Learn, Application Registration. Sul fatto che la registrazione di un eseguibile tramite la sottochiave App Paths è raccomandata; il ruolo della sottochiave Applications; la registrazione di verb tramite SystemFileAssociations; e la priorità del ProgID e delle informazioni correlate quando l’app predefinita cambia. ↩
-
Microsoft Learn, Verbs and File Associations. Sul fatto che un verb è un’azione usata anche da ShellExecuteEx; gli elementi di una stringa di comando che possono contenere uno spazio devono essere avvolti tra virgolette, e “%1” va sempre scritto tra virgolette; e la registrazione di una procedura predefinita sotto HKCR\Applications. ↩
-
Microsoft Learn, IExplorerCommand interface. Sulla composizione dei metodi GetTitle, GetIcon, GetState, Invoke, EnumSubCommands e simili; i metodi chiamati sul thread UI quindi non devono comunicare con risorse di rete; e la disponibilità da Windows Vista in poi. ↩
-
Microsoft Learn, Windows Sandbox. Sul poter avviare un ambiente Windows isolato e usa-e-getta in pochi secondi, tutti i cambiamenti vengono scartati quando lo chiudete, la sua idoneità per test software e verifica dell’installer, e la disponibilità su Pro/Enterprise/Education. ↩
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Come funzionano gli Appunti e il trascinamento della selezione — Gestire correttamente il trasferimento dati OLE nelle app aziendali
Incollate una tabella Excel e la formattazione si sfascia; chiudete l'app di origine e non potete più incollare — entrambi vengono dal fa...
Outsourcing e sviluppo su commissione di app Windows: cosa chiarire prima di affidare l'incarico
Prima di affidare in outsourcing o su commissione lo sviluppo di un'app Windows, ecco i punti da chiarire: revisione del software esisten...
Il curioso amore di uno sviluppatore, ovvero: come ho imparato a non preoccuparmi e ad amare Windows
Windows è complicato. Ma questa complicazione è anche quella di un sistema operativo che da decenni porta sulle spalle il lavoro reale.
L'API thread pool Win32 — Concorrenza senza creare thread, tramite CreateThreadpoolWork
State spargendo chiamate CreateThread per tutto il codice nativo? Questo articolo spiega l'API thread pool Win32 ridisegnata in Vista — i...
Named pipe in pratica — L'IPC standard di Windows, dalla progettazione alla sicurezza
Guida pratica alle named pipe, il meccanismo standard di comunicazione tra processi su Windows. L'articolo organizza, a partire dalle fon...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Migrazione ActiveX
Scelte per mantenere, incapsulare o sostituire componenti COM / ActiveX / OCX.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
Applicazioni aziendali, integrazione di dispositivi e strumenti di comunicazione, dai requisiti allo sviluppo.
Manutenzione e modernizzazione del software Windows
Aggiunte di funzionalità, manutenzione e modernizzazione graduale di software Windows esistente.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- Perché la voce del menu contestuale della nostra app in Windows 11 compare solo sotto «Mostra altre opzioni»?
- Perché in Windows 11 il menu contestuale di Esplora file si è diviso in due strati, vecchio e nuovo. Gli unici comandi che possono comparire nel nuovo menu sono quelle che implementano l'interfaccia IExplorerCommand e sono registrate nel manifesto di un pacchetto MSIX (= hanno identità di pacchetto). Le estensioni della shell classiche basate su IContextMenu sono state spostate nel vecchio menu che si apre con «Mostra altre opzioni» (Maiusc+F10). L'estensione in sé non è rotta, quindi per ora continua a funzionare, ma se la si vuole nel nuovo menu serve una migrazione a IExplorerCommand e il packaging come MSIX oppure l'identità con uno sparse package.
- L'installer può impostare la nostra app come app predefinita per un file (quella che si apre con il doppio clic)?
- No. La scelta dell'app predefinita è progettata perché la faccia l'utente, e Windows non supporta il cambio dell'app predefinita da nessun altro posto se non l'interfaccia Impostazioni di sistema. Le informazioni UserChoice che conservano la scelta di ogni utente sono offuscate, e un driver filtro (UCPD.sys) protegge anche in scrittura dalle app. Ciò che un installer può fare è registrare un ProgID e i verb, aggiungersi a OpenWithProgIds per comparire come candidato in «Apri con» e indirizzare l'utente alla pagina App predefinite. L'implementazione corretta non è rubare il predefinito, ma prepararsi a essere scelti.
- Posso scrivere un'estensione della shell in codice gestito come C#?
- Microsoft ha detto chiaramente che scrivere un'estensione della shell in-process (un gestore di menu contestuale, un gestore di icone e simili) in codice gestito non è raccomandato e non è supportato. L'estensione viene caricata in Esplora risorse e nel processo di qualsiasi app che apre una finestra di dialogo file comune, quindi collisioni di versione del CLR, rientranza e durata degli oggetti non deterministica rendono instabile l'app ospite. La regola è l'implementazione in C++ nativo. Un EXE normale avviato dal command di un verb, o un'estensione out-of-process come un gestore di anteprima che gira in un processo separato, va bene in codice gestito.
- Che cos'è uno sparse package (MSIX con posizione esterna)?
- Un piccolo pacchetto MSIX che non contiene file dell'app, solo un manifesto (informazioni di identità). Per un'app installata in modo ordinario con un installer esistente (MSI, Inno Setup e simili), lo si registra con Add-AppxPackage -ExternalLocation che punta alla cartella di installazione, e l'app acquisisce identità di pacchetto e può usare funzioni che la richiedono, come la registrazione nel nuovo menu contestuale di Windows 11 e le notifiche toast. È disponibile da Windows 10 versione 2004 in poi, e il pacchetto necessita di una firma del codice attendibile sulla macchina di destinazione. È l'opzione realistica quando si vuole il supporto del nuovo menu senza spostare l'intera distribuzione su MSIX.
- Cosa fare quando una voce del menu contestuale compare due volte, o non scompare?
- Per prima cosa isolate la causa controllando su quale menu compare: il nuovo o il vecchio (Mostra altre opzioni). La doppia visualizzazione tipica è che coesistono una registrazione classica nel registro e una registrazione nel manifesto MSIX, o che una registrazione ProgID o CLSID dell'estensione è rimasta alla disinstallazione. Dopo un cambio di associazione sospettate anche un SHChangeNotify(SHCNE_ASSOCCHANGED) dimenticato; subito dopo la registrazione del pacchetto, un riavvio di Esplora risorse dimenticato. Se ancora non si risolve, disabilitate temporaneamente le estensioni non Microsoft in ShellExView e identificate la DLL colpevole con una ricerca binaria.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.