Condividi tramite


Procedura: eseguire la migrazione a /clr

Aggiornamento: novembre 2007

In questo argomento vengono illustrati i problemi che sorgono durante la compilazione di codice nativo utilizzando /clr (per ulteriori informazioni, vedere /clr (Compilazione Common Language Runtime)). /clr consente ai moduli Visual C++ di richiamare ed essere richiamati dagli assembly .NET pur rimanendo compatibili con i moduli non gestiti. Per ulteriori informazioni sui vantaggi offerti dalla compilazione con /clr, vedere Assembly misti (nativi e gestiti) e Interoperabilità .NET e nativa.

Problemi noti relativi alla compilazione di progetti di librerie con /clr

Visual C++ 2005 presenta alcuni problemi noti durante la compilazione di progetti di librerie con /clr:

  • Quando si compila un progetto del controllo ActiveX MFC utilizzando /clr nell'ambiente di sviluppo**,** il sistema di generazione tenterà di registrare la dll utilizzando regasm anziché regsvr32. Il controllo deve essere registrato manualmente tramite regsvr32.

  • Quando si crea un progetto ATL e si attiva /clr, i file con estensione c generano un errore, poiché questi non possono essere compilati utilizzando /clr. Se tuttavia si modificano le impostazioni del file in modo da compilarlo con /TP, verranno generati errori del linker. La soluzione consiste nel compilare i file con estensione c come nativi (senza /clr).

  • Il codice può eseguire query nei tipi in fase di esecuzione con CRuntimeClass::FromName. Tuttavia, se un tipo è incluso in un file con estensione dll MSIL (compilato con /clr), la chiamata a CRuntimeClass::FromName potrebbe avere esito negativo se si verifica prima dei costruttori statici eseguiti nel file con estensione dll gestito (questo problema non si verifica se la chiamata a FromName si verifica dopo che il codice è stato eseguito nel file con estensione dll gestito). Per aggirare questo problema è possibile imporre la costruzione del costruttore statico gestito definendo una funzione nel file con estensione dll gestito, esportandolo e richiamandolo dall'applicazione MFC nativa. Esempio:

    // Extention DLL Header file:
    __declspec( dllexport ) void EnsureManagedInitialization () {
       // managed code that won't be optimized away
       System::GC::KeepAlive(System::Int32::MaxValue);
    }
    

Eseguire la compilazione con Visual C++ 2005

Prima di utilizzare /clr per un qualsiasi modulo del progetto, compilare e collegare il progetto nativo tramite Visual C++ 2005.

I passaggi riportati di seguito, da eseguire nell'ordine indicato, rappresentano la procedura più semplice per una compilazione con /clr. È importante che il progetto venga compilato ed eseguito dopo ognuno di questi passaggi.

Versioni precedenti a Visual C++ 2003

Se si esegue l'aggiornamento in Visual C++ 2005 da una versione precedente a Visual C++ 2003, è possibile riscontrare errori del compilatore connessi alla conformità standard C++ avanzata di Visual C++ 2003. Per ulteriori informazioni, vedere Ultime modifiche al compilatore Visual C++.

Aggiornamento da Visual C++ 2003

È consigliabile che i progetti compilati in precedenza con Visual C++ 2003 vengano inizialmente compilati senza /clr, poiché in Visual C++ 2005 è stata incrementata la conformità agli standard ANSI/ISO e sono state introdotte alcune modifiche che possono determinare interruzioni. Per ulteriori informazioni, vedere Ultime modifiche al compilatore Visual C++. La modifica che sembra richiedere maggiore attenzione è illustrata nell'argomento Security Enhancements in the CRT. È estremamente probabile che il codice che utilizza CRT produca avvisi negativi. Sebbene sia possibile eliminare tali avvisi, è tuttavia preferibile eseguire una migrazione alle nuove Security-Enhanced Versions of CRT Functions, che sono in grado di fornire una maggiore sicurezza e di individuare problemi di sicurezza all'interno del codice.

Aggiornamento dalle estensioni gestite per C++

I progetti creati con Visual C++ .NET o Visual C++ 2003 che hanno utilizzato le estensioni gestite per C++ richiederanno almeno una modifica alle impostazioni di progetto, poiché tali estensioni sono ormai obsolete. Di conseguenza, il codice scritto con le estensioni gestite per C++ non verrà compilato in /clr. Utilizzare invece /clr:oldSyntax.

Convertire codice C in C++

Sebbene Visual C++ 2005 sia in grado di compilare i file C, per una compilazione con /clr è tuttavia necessario convertirli in C++. La modifica del nome file effettivo non è richiesta ed è possibile utilizzare /Tp (vedere /Tc, /Tp, /TC, /TP (Specifica il tipo di file di origine)). Nonostante /clr richieda i file di codice sorgente C++, non è tuttavia necessario effettuare il refactoring del codice per utilizzare paradigmi orientati a oggetti.

È estremamente probabile che il codice C richieda modifiche se compilato come file C++. Le regole di indipendenza dai tipi C++ sono rigorose, pertanto le conversioni dei tipi devono essere rese esplicite con i cast. Ad esempio, malloc restituisce un puntatore void, ma può essere assegnato a un puntatore a qualsiasi tipo in C con un cast:

int* a = malloc(sizeof(int));   // C code
int* b = (int*)malloc(sizeof(int));   // C++ equivalent

Anche i puntatori a funzione sono rigorosamente indipendenti dai tipi in C++ e quindi il codice C riportato di seguito richiede alcune modifiche. In C++ è consigliabile creare un typedef che definisca il tipo di puntatore a funzione e quindi utilizzare tale tipo per eseguire il cast dei puntatori a funzione:

NewFunc1 = GetProcAddress( hLib, "Func1" );   // C code
typedef int(*MYPROC)(int);   // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );

C++ richiede inoltre che tali funzioni siano con prototipo o completamente definite per potervi fare riferimento o per essere richiamate.

Gli identificatori utilizzati nel codice C che risultano essere parole chiave in C++ (ad esempio virtual, new, delete, bool, true, false e così via) devono essere rinominati. Per eseguire questa operazione, è generalmente sufficiente eseguire semplici operazioni di ricerca e sostituzione.

Infine, mentre le chiamate COM di tipo C richiedono l'utilizzo esplicito di v-table e del puntatore this, in C++ questi non risultano necessari:

COMObj1->lpVtbl->Method(COMObj, args);  // C code
COMObj2->Method(args);  // C++ equivalent

Riconfigurare le impostazioni del progetto

Dopo aver compilato ed eseguito il progetto in Visual C++ 2005, è consigliabile creare nuove configurazioni di progetto per /clr anziché modificare quelle predefinite. /clr non è compatibile con alcune opzioni del compilatore e la creazione di configurazioni separate consente di compilare il progetto come nativo o gestito. Quando si seleziona /clr nella finestra di dialogo delle pagine delle proprietà, le impostazioni del progetto non compatibili con /clr vengono disattivate (e il ripristino delle opzioni disattivate non avviene automaticamente quando si deseleziona /clr in un secondo momento).

Creare nuove configurazioni del progetto

È possibile utilizzare l'opzione Copia impostazioni da della Finestra di dialogo Nuova configurazione progetto per creare una configurazione del progetto basata sulle relative impostazioni esistenti. Questa operazione deve essere eseguita una volta per la configurazione per il debug e una per la configurazione per il rilascio. Le modifiche successive possono quindi essere applicate esclusivamente alle configurazioni specifiche di /clr, lasciando inalterate quelle originali relative al progetto.

I progetti che utilizzano regole di generazione personalizzate potrebbero richiedere particolare attenzione.

Questo passaggio presenta implicazioni diverse per i progetti che utilizzano i makefile. In questo caso è possibile configurare una destinazione di generazione separata o creare una versione specifica della compilazione /clr a partire da una copia dell'originale.

Modificare le impostazioni del progetto

Per selezionare /clr nell'ambiente di sviluppo, è sufficiente seguire le istruzioni fornite in /clr (Compilazione Common Language Runtime). Come accennato in precedenza, questo passaggio consente di disattivare automaticamente le impostazioni di progetto in conflitto.

Nota:

Quando si aggiorna una libreria gestita o un progetto di servizi Web da Visual C++ 2003 a Visual C++ 2005, l'opzione del compilatore /Zl viene aggiunta alla pagina delle proprietà Riga di comando. Ciò determina l'errore LNK2001. Per risolverlo, rimuovere /Zl dalla pagina delle proprietà Riga di comando. Per ulteriori informazioni, vedere /Zl (Omette il nome della libreria predefinita) e Procedura: aprire le pagine delle proprietà dei progetti. In alternativa, aggiungere msvcrt.lib e msvcmrt.lib alla proprietà Dipendenze aggiuntive del linker.

Nei progetti creati con makefile, le opzioni non compatibili del compilatore devono essere disattivate manualmente dopo aver aggiunto /clr. Per informazioni sulle opzioni del compilatore non compatibili con /clr, vedere /Limitazioni di /clr.

Intestazioni precompilate

Le intestazioni precompilate sono supportate in /clr. Tuttavia, se si compilano alcuni dei file CPP con /clr e i restanti come nativi, sarà necessario apportare determinate modifiche, poiché le intestazioni precompilate generate con /clr non sono compatibili con quelle generate senza /clr. Tale incompatibilità è dovuta al fatto che /clr genera e richiede metadati. I moduli /clr compilati non possono quindi utilizzare intestazioni precompilate che non includono metadati e i moduli non /clr non possono utilizzare file di intestazione precompilati che contengono metadati.

Il modo più semplice per compilare un progetto in cui alcuni moduli sono /clr compilati consiste nel disattivare completamente le intestazioni precompilate (nella finestra di dialogo Pagine delle proprietà del progetto aprire il nodo C/C++ e selezionare Intestazioni precompilate, quindi modificare la proprietà Crea/usa intestazioni precompilate in "Senza intestazioni precompilate").

Tuttavia, soprattutto per quanto riguarda i progetti di grandi dimensioni, le intestazioni precompilate garantiscono una più elevata velocità di compilazione e pertanto disattivare questa funzionalità non è sempre consigliabile. In questo caso la soluzione migliore consiste nel configurare i file /clr e non /clr in modo da utilizzare intestazioni precompilate separate. Questo risultato può essere ottenuto con un unico passaggio, selezionando i moduli /clr da compilare in Esplora soluzioni, facendo clic con il pulsante destro del mouse sul gruppo e scegliendo Proprietà. A questo punto modificare entrambe le proprietà "Crea/Usa PCH tramite file" e "File di intestazione precompilato" in modo da ricorrere a un diverso nome del file di intestazione e a un altro file PCH, rispettivamente.

Correzione degli errori

La compilazione con /clr potrebbe provocare errori del compilatore, del linker o di runtime. In questa sezione vengono illustrati i problemi più comuni.

Unione di metadati

Versioni diverse dei tipi di dati possono causare errori del linker dovuti al fatto che i metadati generati per i due tipi non corrispondono (questo si verifica, in genere, quando i membri di un tipo vengono definiti in base a determinate condizioni, che tuttavia non sono le stesse per tutti i file CPP che utilizzano il tipo). Questo provoca un errore del linker, che segnala solo il nome del simbolo e il nome del secondo file OBJ in cui il tipo è stato definito. Spesso risulta utile alternare l'ordine di invio dei file OBJ al linker in modo da individuare la posizione dell'altra versione del tipo di dati.

Deadlock del blocco del caricatore

In Visual C++ .NET e Visual C++ 2003, l'inizializzazione in /clr era suscettibile di deadlock non deterministico. Il problema è noto come "deadlock del blocco del caricatore". In Visual C++ 2005 il deadlock è più semplice da evitare, viene rilevato e segnalato al momento del runtime e non è più non deterministico. Riscontrare il problema del blocco del caricatore è ancora possibile, ma ora risulta più facile evitarlo e risolverlo. Per informazioni dettagliate, istruzioni e soluzioni, vedere Inizializzazione di assembly misti.

Esportazioni di dati

L'esportazione di dati DLL è suscettibile di errori e non è pertanto consigliabile. Questo si verifica perché non esiste alcuna garanzia che la sezione di dati di una DLL venga inizializzata fino a quando una parte gestita della DLL stessa risulta completamente eseguita. Per fare riferimento ai metadati, utilizzare la The #using Directive.

Visibilità del tipo

I tipi nativi sono ora privati per impostazione predefinita, mentre in Visual C++ .NET 2002 e Visual C++ 2003 erano pubblici. Per questo motivo, un tipo nativo potrebbe non risultare visibile al di fuori della DLL. L'errore può essere risolto aggiungendo public a tali tipi. Per ulteriori informazioni, vedere Type and Member Visibility.

Problemi di allineamento e virgola mobile

__controlfp non è supportato in Common Language Runtime (per ulteriori informazioni, vedere _control87, _controlfp, __control87_2). CLR non rispetta inoltre align (C++).

Inizializzazione COM

Common Language Runtime inizializza COM automaticamente quando viene inizializzato un modulo (l'inizializzazione automatica di COM ne comporta la trasformazione in MTA). Di conseguenza, l'inizializzazione esplicita di COM genera codici restituiti a indicare che COM è già stato inizializzato. Se si tenta di inizializzare COM in modo esplicito con un modello di threading quando CLR lo ha già inizializzato con un altro modello di threading, può verificarsi l'arresto dell'applicazione.

L'inizializzazione COM e il codice di errore associato devono prevedere sia il caso in cui COM risulti già inizializzato, sia il caso in cui le chiamate a CoInitialize e CoUninitialize possano semplicemente essere rimosse. Common Language Runtime avvia COM come MTA per impostazione predefinita. Per modificare questa situazione, utilizzare /CLRTHREADATTRIBUTE (Imposta l'attributo thread CLR).

Problemi relativi alle prestazioni

Le prestazioni potrebbero registrare un peggioramento quando i metodi C++ nativi generati per MSIL vengono chiamati indirettamente (chiamate di funzione virtuale o utilizzo di puntatori a funzione). Per ulteriori informazioni, vedere Doppio thunk (C++).

Nel passaggio dal formato nativo a MSIL, è possibile che le dimensioni del working set aumentino. Questo si verifica perché il Common Language Runtime fornisce numerose funzionalità che consentono di garantire la corretta esecuzione del programma. Se l'applicazione /clr non viene eseguita correttamente, è possibile attivare C4793 (disattivato per impostazione predefinita). Per ulteriori informazioni, vedere Avviso del compilatore (livelli 1 e 3) C4793.

Arresti anomali al momento della chiusura

In alcuni casi CLR potrebbe chiudersi prima che il codice gestito abbia completato l'esecuzione. Questo problema può verificarsi quando si utilizzano std::set_terminate e SIGTERM. Per ulteriori informazioni, vedere signal Constants e set_terminate (<exception>).

Utilizzo di nuove funzionalità Visual C++

Quando l'applicazione risulta compilata, collegata ed eseguita, è possibile iniziare a utilizzare le funzionalità .NET in qualsiasi modulo compilato con /clr. Per ulteriori informazioni, vedere Language Features for Targeting the CLR.

Se sono state applicate le estensioni gestite per C++, è possibile convertire il codice in modo da utilizzare la nuova sintassi. Per un riepilogo delle differenze sintattiche, vedere Elenco di controllo degli aggiornamenti della sintassi delle estensioni gestite per C++. Per informazioni dettagliate sulla conversione delle estensioni gestite per C++, vedere Nozioni di base della migrazione in C++/CLI.

Per informazioni sulla programmazione .NET in Visual C++, vedere:

Vedere anche

Concetti

Assembly misti (nativi e gestiti)