Linee guida per l'implementazione di estensioni In-Process

Le estensioni in-process vengono caricate in tutti i processi che li attivano. Ad esempio, un'estensione dello spazio dei nomi shell può essere caricata in qualsiasi processo che accede allo spazio dei nomi shell direttamente o indirettamente. Lo spazio dei nomi Shell viene usato da molte operazioni shell, ad esempio la visualizzazione di una finestra di dialogo di file comune, l'avvio di un documento tramite l'applicazione associata o l'acquisizione dell'icona usata per rappresentare un file. Poiché le estensioni in-process possono essere caricate in processi arbitrari, è necessario prestare attenzione a non influire negativamente sull'applicazione host o su altre estensioni in-process.

Un runtime di particolare nota è Common Language Runtime (CLR), noto anche come codice gestito o .NET Framework. Microsoft consiglia di non scrivere estensioni in-process gestite in Windows Explorer o Windows Internet Explorer e non considerarle uno scenario supportato.

In questo argomento vengono illustrati i fattori da considerare quando si determina se un runtime diverso da CLR è adatto per l'uso da parte delle estensioni in-process. Esempi di altri runtime includono Java, Visual Basic, JavaScript/ECMAScript, Delphi e la libreria di runtime C/C++. Questo argomento fornisce anche alcuni motivi per cui il codice gestito non è supportato nelle estensioni in-process.

Conflitti di versione

Un conflitto di versione può verificarsi tramite un runtime che non supporta il caricamento di più versioni di runtime all'interno di un singolo processo. Le versioni di CLR precedenti alla versione 4.0 rientrano in questa categoria. Se il caricamento di una versione di un runtime impedisce il caricamento di altre versioni dello stesso runtime, questo può creare un conflitto se l'applicazione host o un'altra estensione in-process usa una versione in conflitto. Nel caso di un conflitto di versione con un'altra estensione in-process, il conflitto può essere difficile da riprodurre perché l'errore richiede le estensioni in conflitto corrette e la modalità di errore dipende dall'ordine in cui vengono caricate le estensioni in conflitto.

Si consideri un'estensione in-process scritta usando una versione di CLR precedente alla versione 4.0. Ogni applicazione nel computer che usa una finestra di dialogo Apri file potrebbe avere potenzialmente il codice gestito della finestra di dialogo e la relativa dipendenza CLR caricata nel processo dell'applicazione. L'applicazione o l'estensione che deve prima caricare una versione precedente alla 4.0 di CLR nel processo dell'applicazione limita le versioni di CLR che possono essere usate successivamente da tale processo. Se un'applicazione gestita con una finestra di dialogo Apri è basata su una versione in conflitto di CLR, l'estensione potrebbe non essere eseguita correttamente e potrebbe causare errori nell'applicazione. Viceversa, se l'estensione è la prima a essere caricata in un processo e una versione in conflitto del codice gestito tenta di avviarsi dopo tale operazione (ad esempio un'applicazione gestita o un'applicazione in esecuzione carica CLR su richiesta), l'operazione non riesce. Per l'utente, sembra che alcune funzionalità dell'applicazione interrompono in modo casuale il funzionamento o l'applicazione si arresta in modo misterioso in modo anomalo.

Si noti che le versioni di CLR uguali o successive alla versione 4.0 non sono generalmente soggette al problema di controllo delle versioni perché sono progettate per coesistere tra loro e con la maggior parte delle versioni precedenti 4.0 di CLR (ad eccezione della versione 1.0, che non può coesistere con altre versioni). Tuttavia, i problemi diversi dai conflitti di versione possono verificarsi come descritto nel resto di questo argomento.

Problemi di prestazioni

I problemi di prestazioni possono verificarsi con i runtime che impongono una riduzione significativa delle prestazioni quando vengono caricati in un processo. La riduzione delle prestazioni può essere in forma di utilizzo della memoria, utilizzo della CPU, tempo trascorso o persino utilizzo dello spazio degli indirizzi. CLR, JavaScript/ECMAScript e Java sono noti come runtime ad alto impatto. Poiché le estensioni in-process possono essere caricate in molti processi e vengono spesso eseguite in momenti sensibili alle prestazioni (ad esempio durante la preparazione di un menu da visualizzare all'utente), i runtime a impatto elevato possono influire negativamente sulla velocità di risposta complessiva.

Un runtime ad impatto elevato che utilizza risorse significative può causare un errore nel processo host o in un'altra estensione in-process. Ad esempio, un runtime ad alto impatto che utilizza centinaia di megabyte di spazio indirizzi per il relativo heap può causare l'impossibilità di caricare un set di dati di grandi dimensioni nell'applicazione host. Inoltre, poiché le estensioni in-process possono essere caricate in più processi, l'utilizzo elevato delle risorse in una singola estensione può moltiplicarsi rapidamente in un elevato consumo di risorse nell'intero sistema.

Se un runtime rimane caricato o continua a utilizzare le risorse anche quando l'estensione che usa tale runtime è scaricata, tale runtime non è adatto per l'uso in un'estensione.

Problemi specifici di .NET Framework

Le sezioni seguenti illustrano esempi di problemi riscontrati con l'uso del codice gestito per le estensioni. Non sono un elenco completo di tutti i possibili problemi che potrebbero verificarsi. I problemi descritti in questo articolo sono entrambi i motivi per cui il codice gestito non è supportato nelle estensioni e punta a considerare quando si valuta l'uso di altri runtime.

Re-entrancy

Quando CLR blocca un thread a thread singolo (STA), ad esempio a causa di un oggetto Monitor.Enter, WaitHandle.WaitOne o di un'istruzione di blocco a thread singolo , CLR, nella configurazione standard, immette un ciclo di messaggi annidato durante l'attesa. Molti metodi di estensione non sono consentiti per l'elaborazione dei messaggi e questa reentrancy imprevedibile e imprevista può causare un comportamento anomalo che è difficile da riprodurre e diagnosticare.

L'appartamento multithreaded

CLR crea wrapper chiamabili in fase di esecuzione per oggetti COM (Component Object Model). Questi stessi wrapper chiamabili di runtime vengono eliminati definitivamente in un secondo momento dal finalizzatore CLR, che fa parte dell'apartment multithreading (MTA). Lo spostamento del proxy da STA a MTA richiede il marshalling, ma non tutte le interfacce usate dalle estensioni possono essere sottoposto a marshalling.

Durate di oggetti non deterministici

CLR ha garanzie di durata degli oggetti più deboli rispetto al codice nativo. Molte estensioni hanno requisiti di conteggio dei riferimenti per oggetti e interfacce e il modello di Garbage Collection usato da CLR non può soddisfare questi requisiti.

  • Se un oggetto CLR ottiene un riferimento a un oggetto COM, il riferimento all'oggetto COM mantenuto da Runtime Callable Wrapper non viene rilasciato finché il runtime Callable Wrapper non viene sottoposto a Garbage Collection. Il comportamento di rilascio non deterministico può essere in conflitto con alcuni contratti di interfaccia. Ad esempio, il metodo IPersistPropertyBag::Load richiede che nessun riferimento al contenitore delle proprietà venga mantenuto dall'oggetto quando il metodo Load restituisce.
  • Se un riferimento a un oggetto CLR viene restituito al codice nativo, runtime Callable Wrapper rinuncia al riferimento all'oggetto CLR quando viene eseguita la chiamata finale di Runtime Callable Wrapper a Release , ma l'oggetto CLR sottostante non viene finalizzato fino a quando non viene sottoposto a Garbage Collection. La finalizzazione non deterministica può essere in conflitto con alcuni contratti di interfaccia. Ad esempio, i gestori di anteprima sono necessari per rilasciare immediatamente tutte le risorse quando il conteggio dei riferimenti scende a zero.

Usi accettabili di codice gestito e altri runtime

È accettabile usare codice gestito e altri runtime per implementare estensioni out-of-process. Di seguito sono riportati alcuni esempi di estensioni shell out-of-process:

  • Gestori di anteprima
  • Azioni basate su riga dicomando, ad esempio quelle registrate nelle sottochiavi delcomando verbo\ della shell\.
  • Oggetti COM implementati in un server locale, per i punti di estensione shell che consentono l'attivazione out-of-process.

Alcune estensioni possono essere implementate come estensioni in-process o out-of-process. È possibile implementare queste estensioni come estensioni out-of-process se non soddisfano questi requisiti per le estensioni in-process. L'elenco seguente mostra esempi di estensioni che possono essere implementate come estensioni in-process o out-of-process:

  • IExecuteCommand associato a una voce DelegateExecute registrata in una sottochiave delcomandoverbo\della shell\.
  • IDropTarget associato a CLSID registrato in una sottochiaveDropTargetdel verbo\shell\.
  • IExplorerCommandState associato a una voce CommandStateHandler registrata in una sottochiaveverbodella shell\.