Partager via


Comment : effectuer une migration vers /clr

Mise à jour : novembre 2007

Cette rubrique traite des problèmes qui surviennent lors de la compilation de code natif avec /clr (voir /clr (Compilation pour le Common Language Runtime) pour plus d'informations). /clr permet aux modules Visual C++ d'appeler et d'être appelés par des assemblys .NET tout en restant compatibles avec les modules non managés. Voir Assemblys mixtes (natif et managé) et Interopérabilité native et .NET pour plus d'informations sur les avantages de la compilation avec /clr.

Problèmes connus s'agissant de compilation de projets de bibliothèques avec /clr

Visual C++ 2005 comporte quelques problèmes connus lors de la compilation de projets de bibliothèques à l'aide de /clr :

  • Lors de la compilation d'un projet de contrôle ActiveX MFC avec /clr dans l'environnement de développement ,, le système de génération tentera d'enregistrer la .dll avec regasm, et non avec regsvr32. Vous devez enregistrer manuellement le contrôle avec regsvr32.

  • Lorsque vous créez un projet ATL, puis activez /clr, les fichiers .c généreront une erreur, car ils ne peuvent pas être compilés avec /clr. Toutefois, si vous modifiez les paramètres de fichier pour compiler le fichier avec /TP, vous générerez des erreurs d'éditeur de liens. La solution est de compiler les fichiers .c en natif (sans /clr).

  • Votre code peut interroger des types pendant l'exécution avec CRuntimeClass::FromName. Toutefois, si un type est contenu dans un .dll MSIL (compilé avec /clr), l'appel à CRuntimeClass::FromName peut échouer s'il se produit avant l'exécution des constructeurs statiques dans le .dll managé (ce problème ne se produit pas si l'appel FromName est effectué après l'exécution du code dans le .dll managé). Pour contourner ce problème, vous pouvez forcer la construction du constructeur statique managé en définissant une fonction dans le .dll managé, en l'exportant, puis en l'appelant à partir de l'application MFC native. Par exemple :

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

Compilation avec Visual C++ 2005

Avant toute utilisation de /clr sur un module quelconque de votre projet, vous devez d'abord compiler et lier votre projet natif avec Visual C++ 2005.

Les étapes indiquées ci-dessous, à suivre dans l'ordre, montrent le moyen le plus simple d'effectuer une compilation /clr. Il est important de compiler et d'exécuter votre projet après chacune de ces étapes.

Versions antérieures à Visual C++ 2003

Si vous effectuez une mise à niveau vers Visual C++ 2005 à partir d'une version antérieure à Visual C++ 2003, des erreurs de compilation liées à une meilleure conformité de Visual C++ 2003 à la norme C++ risquent d'apparaître. Consultez Modifications avec rupture dans le compilateur Visual C++ pour plus d'informations.

Mise à niveau à partir de Visual C++ 2003

Les projets antérieurs générés avec Visual C++ 2003 doivent également être compilés d'abord sans /clr, étant donné que Visual C++ 2005 bénéficie d'une meilleure conformité aux normes ANSI/ISO, et en raison de plusieurs nouveautés. Consultez Modifications avec rupture dans le compilateur Visual C++ pour plus d'informations. La modification sans doute la plus digne d'attention est Security Enhancements in the CRT. Il est très probable que du code utilisant le CRT produise des avertissements de désapprobation. Ces avertissements peuvent être supprimés, mais il est préférable d'effectuer une migration vers les nouvelles Security-Enhanced Versions of CRT Functions, celles-ci apportant des améliorations en termes de sécurité et pouvant éventuellement révéler des problèmes de sécurité dans votre code.

Mise à niveau à partir d'Extensions managées pour C++

Pour les projets générés avec Visual C++ .NET ou Visual C++ 2003 qui utilisaient les Extensions managées pour C++, il sera nécessaire d'apporter au moins une modification aux paramètres du projet, puisque ces extensions sont maintenant désapprouvées. En conséquence, le code écrit avec Extensions managées pour C++ ne compilera pas sous /clr. Utilisez /clr:oldSyntax à la place.

Conversion du code C en C++

Bien que Visual C++ 2005 puisse compiler des fichiers C, il est nécessaire de les convertir en C++ pour une compilation /clr. Le nom de fichier actuel n'a pas à être modifié, vous pouvez utiliser /Tp (consultez /Tc, /Tp, /TC, /TP (Spécifier le type de fichier source)). Notez que, bien que /clr requière des fichiers de code source C++, il n'est pas nécessaire de reconfigurer votre code pour utiliser des paradigmes orientés objet.

Il est très probable que le code C nécessitera des modifications une fois compilé sous la forme d'un fichier C++. Les règles de sécurité de type C++ sont strictes, il faut donc que les conversions de types soient effectuées de façon explicite à l'aide de casts. Par exemple, malloc retourne un pointeur void, mais peut être assigné à un pointeur vers n'importe quel type en C avec un cast :

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

Les pointeurs fonction sont aussi strictement de type sécurisé en C++, si bien qu'il faut modifier le code C suivant. En C++, le mieux est de créer un typedef qui définit le type du pointeur fonction, puis d'utiliser ce type pour effectuer un cast des pointeurs fonction :

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

En C++, une fonction doit être soit prototypée soit complètement définie pour pouvoir être référencée ou appelée.

Les identificateurs utilisés en code C qui se trouvent être des mots clés en C++ (tels que virtual, new, delete, bool, true, false, etc.) doivent être renommés. Pour ce faire, on peut en général utiliser des opérations simples de recherche/remplacement.

Enfin, les appels COM de style C requièrent l'utilisation explicite de la v-table et du pointeur this, ce qui n'est pas le cas en C++ :

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

Reconfiguration des paramètres du projet

Une fois votre projet compilé et exécuté dans Visual C++ 2005, vous devez créer de nouvelles configurations de projet pour /clr plutôt que de modifier les configurations par défaut. /clr est incompatible avec certaines options du compilateur et créer des configurations séparées vous permettra de générer votre projet sous forme native ou managée. Lorsque /clr est sélectionné dans la boîte de dialogue Pages de propriétés, les paramètres du projet non compatibles avec /clr sont désactivés (et les options désactivées ne sont pas restaurées automatiquement si /clr est désélectionné par la suite).

Création des configurations d'un nouveau projet

Vous pouvez utiliser l'option Copier les paramètres à partir de dans la Nouvelle configuration de projet, boîte de dialogue pour créer une configuration de projet basée sur vos paramètres de projet existants. Faites-le une fois pour la configuration Debug et une fois également pour la configuration Release. Les modifications suivantes peuvent alors être appliquées aux configurations spécifiques à /clr uniquement, ce qui laisse intactes les configurations de projet d'origine.

Les projets qui utilisent des règles de génération personnalisées doivent faire l'objet d'une plus grande attention.

Cette étape a diverses conséquences sur les projets qui utilisent des makefiles. Dans ce cas, une cible de génération distincte peut être configurée, ou une version spécifique destinée à la compilation sous /clr peut être créée à partir d'une copie de l'original.

Modification des paramètres du projet

On peut sélectionner /clr dans l'environnement de développement en suivant les instructions de /clr (Compilation pour le Common Language Runtime). Comme mentionné précédemment, cette étape désactivera automatiquement les paramètres du projet incompatibles.

Remarque :

Lors de la mise à niveau d'une bibliothèque managée ou d'un projet de service Web de Visual C++ 2003 à Visual C++ 2005, l'option du compilateur /Zl viendra s'ajouter à la page de propriétés Ligne de commande. Cela provoquera une erreur LNK2001. La solution est de supprimer /Zl de la page de propriétés Ligne de commande. Pour plus d'informations, consultez /Zl (Omettre le nom de la bibliothèque par défaut) et Comment : ouvrir les pages de propriétés d'un projet. Ou ajoutez msvcrt.lib et msvcmrt.lib à la propriété Dépendances supplémentaires de l'éditeur de liens.

Pour les projets générés avec des makefiles, les options du compilateur incompatibles doivent être manuellement désactivées une fois /clr ajouté. Consultez /Restrictions de /clr pour plus d'informations sur les options du compilateur incompatibles avec /clr.

En-têtes précompilés

Les en-têtes précompilés sont pris en charge sous /clr. Toutefois, si vous ne compilez que quelques-uns de vos fichiers CPP avec /clr (en compilant le reste en natif), il faudra procéder à certaines modifications car les en-têtes précompilés générés avec /clr ne sont pas compatibles avec ceux qui sont générés sans /clr. Cette incompatibilité est due au fait que /clr génère et requiert des métadonnées. Les modules compilés avec /clr ne peuvent donc pas utiliser d'en-têtes précompilés qui n'incluent pas de métadonnées, et inversement les modules non /clr ne peuvent pas utiliser de fichiers d'en-tête précompilés qui contiennent des métadonnées.

La façon la plus simple de compiler un projet dont certains modules sont compilés avec /clr est de désactiver complètement les en-têtes précompilés. (Dans la boîte de dialogue Pages de Propriétés du projet, ouvrez le nœud C/C++ et sélectionnez « En-têtes précompilés ». Puis modifiez la propriété Création/utilisation d'un en-tête précompilé en « Sans utiliser les en-têtes précompilés »).

Cependant, les en-têtes précompilés offrant, en particulier pour les grands projets, une bien meilleure vitesse de compilation, la désactivation de cette fonctionnalité n'est pas souhaitable. Dans ce cas, le mieux est de configurer les fichiers /clr et non /clr de façon à utiliser séparément les en-têtes précompilés. Cela peut être fait en une étape : effectuez une sélection multiple des modules à compiler avec /clr à l'aide de l'Explorateur de solutions, cliquez avec le bouton droit sur le groupe et sélectionnez Propriétés. Puis modifiez à la fois la propriété Création/utilisation d'un en-tête précompilé en spécifiant un nom de fichier et la propriété Création/utilisation d'un en-tête précompilé pour utiliser respectivement un nom de fichier d'en-tête et un fichier PCH différents.

Résolution d'Erreurs

La compilation avec /clr peut provoquer des erreurs de compilateur, d'éditeur de liens ou d'exécution. Cette section expose les problèmes les plus courants.

Fusion des métadonnées

Utiliser des versions différentes de types de données peut provoquer une erreur de l'éditeur de liens si les métadonnées générées pour les deux types ne correspondent pas. (Cela arrive généralement lorsque les membres d'un type sont définis de façon conditionnelle et que les conditions ne sont pas les mêmes pour tous les fichiers CPP qui utilisent le type). Dans ce cas, l'éditeur de liens échoue, en ne rapportant que le nom de symbole et le nom du deuxième fichier OBJ dans lequel le type a été défini. Il est souvent utile d'inverser l'ordre dans lequel les fichiers OBJ sont envoyés à l'éditeur de liens pour découvrir l'emplacement de l'autre version du type de données.

Blocage du verrouillage du chargeur

Dans Visual C++ .NET et Visual C++ 2003, l'initialisation sous /clr était susceptible de produire un blocage non déterministe. Ce problème est connu sous le nom de « blocage du verrouillage du chargeur ». Dans Visual C++ 2005, ce blocage est plus facile à éviter, il est détecté et rapporté à l'exécution et n'est plus non déterministe. Ce problème de verrouillage du chargeur peut encore se rencontrer, mais il est désormais beaucoup plus facile à éviter et à résoudre. Consultez Initialisation d'assemblys mixtes pour des informations détaillées, une aide et des solutions.

Export de données

Exporter des données DLL est source d'erreurs et n'est pas recommandé. En effet, il n'est pas certain que la section Données d'une DLL puisse être initialisée avant qu'une certaine partie managée de la DLL ait été exécutée. Référencez les métadonnées avec The #using Directive.

Visibilité du type

Les types natifs sont désormais privés par défaut. Dans Visual C++ .NET 2002 et Visual C++ 2003, les types natifs étaient publics par défaut. Un type natif peut donc se retrouver invisible en dehors de la DLL. Vous pouvez résoudre cette erreur en ajoutant public à ces types. Consultez Type and Member Visibility pour plus d'informations.

Virgule flottante et problèmes d'alignement

__controlfp n'est pas pris en charge par le Common Language Runtime (consultez _control87, _controlfp, __control87_2 pour plus d'informations). Le CLR ne respectera pas non plus align (C++).

Initialisation de COM

Le Common Language Runtime initialise automatiquement COM lorsqu'un module est initialisé (lorsque COM est initialisé automatiquement, il est exécuté en tant que MTA). En conséquence, initialiser COM explicitement génère des codes de retour qui indiquent que COM est déjà initialisé. Toute tentative d'initialisation explicite de COM sur un modèle de thread alors que le CLR a déjà initialisé COM sur un autre modèle de thread peut provoquer le blocage de votre application.

L'initialisation de COM et le code d'erreur associé doivent tenir compte du cas où COM est déjà initialisé. Les appels à CoInitialize et CoUninitialize peuvent aussi en général être simplement supprimés. Le Common Language Runtime démarre par défaut COM en tant que MTA ; utilisez /CLRTHREADATTRIBUTE (Définir l'attribut de thread CLR) pour modifier cela.

Problèmes de performances

Il est possible de constater une diminution des performances lorsque les méthodes C++ natives générées en MSIL sont appelées indirectement (par appels de fonction virtuelle ou à l'aide de pointeurs fonction). Pour en savoir plus à ce sujet, consultez Double médiateur (thunking) (C++).

En passant de natif à MSIL, vous remarquerez une augmentation de la taille de votre jeu de travail. C'est parce que le Common Language Runtime fournit de nombreuses fonctionnalités visant à garantir le bon fonctionnement des programmes. Si votre application /clr ne s'exécute pas correctement, vous pouvez activer C4793 (désactivé par défaut) ; voir Avertissement du compilateur (niveaux 1 et 3) C4793 pour plus d'informations.

Pannes lors de la fermeture du programme

Dans certains cas, le CLR peut quitter avant la fin de l'exécution de votre code managé. L'utilisation de std::set_terminate et SIGTERM peut en être la cause. Pour plus d'informations, consultez signal Constants et set_terminate (<exception>).

Utilisation des nouvelles fonctionnalités Visual C++

Une fois votre application compilée, liée et exécutée, vous pouvez commencer à utiliser des fonctionnalités .NET dans n'importe quel module compilé avec /clr. Pour plus d'informations, consultez Language Features for Targeting the CLR.

Si vous avez utilisé Extensions managées pour C++, vous pouvez convertir votre code afin d'utiliser la nouvelle syntaxe. Pour un résumé des différences syntaxiques, consultez Liste de vérification pour la mise à niveau de la syntaxe des extensions managées pour C++. Pour plus d'informations sur la conversion d'Extensions managées pour C++, consultez Initiation à la migration de C++/CLI.

Pour plus d'informations sur la programmation .NET en Visual C++, consultez :

Voir aussi

Concepts

Assemblys mixtes (natif et managé)