Freigeben über


Gewusst wie: Migrieren auf /clr

Aktualisiert: November 2007

Dieses Thema behandelt Probleme, die beim Kompilieren mit /clr auftreten (weitere Informationen finden Sie unter /clr (Common Language Runtime-Kompilierung)). Mit /clr können Visual C++-Module .NET-Assemblys aufrufen bzw. von diesen aufgerufen werden, ohne ihre Kompatibilität mit nicht verwalteten Modulen zu verlieren. Weitere Informationen über die Vorteile, mit /clr zu kompilieren, finden Sie unter Gemischte (systemeigene und verwaltete) Assemblys und Interoperabilität von systemeigenem Code und .NET.

Bekannte Probleme beim Kompilieren von Bibliotheksprojekten mit /clr

In Visual C++ 2005 gibt es einige bekannte Probleme beim Kompilieren von Bibliotheksprojekten mit /clr:

  • Wenn Sie in der Entwicklungsumgebung ein MFC-ActiveX-Steuerelementprojekt mit /clr kompilieren**,** versucht das Buildsystem, die DLL mit regasm statt mit regsvr32 zu registrieren. Sie müssen das Steuerelement manuell mit regsvr32 registrieren.

  • Wenn Sie ein ATL-Projekt erstellen und dann /clr aktivieren, erzeugen die C-Dateien einen Fehler, weil C-Dateien nicht mit /clr kompiliert werden können. Wenn Sie dagegen die Dateieinstellungen so ändern, dass die Datei mit /TP kompiliert wird, erzeugen Sie Linkerfehler. Die Lösung besteht darin, die C-Dateien als systemeigenen Code (ohne /clr) zu kompilieren.

  • Der Code kann zur Laufzeit Typen mit CRuntimeClass::FromName abfragen. Befindet sich der Typ allerdings in einer MSIL-DLL-Datei (kompiliert mit /clr), kann der Aufruf von CRuntimeClass::FromName fehlschlagen, wenn er vor der Ausführung der statischen Konstruktoren in der verwalteten DLL erfolgt. (Dieses Problem tritt nicht auf, wenn der FromName-Aufruf erst nach dem Ausführen des Codes in der verwalteten DLL stattfindet.) Um dieses Problem zu umgehen, können Sie die Konstruktion des verwalteten statischen Konstruktors erzwingen, indem Sie in der verwalteten DLL eine Funktion definieren, sie exportieren und anschließend aus der systemeigenen MFC-Anwendung aufrufen. Beispiel:

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

Kompilieren mit Visual C++ 2005

Kompilieren und verknüpfen Sie ein systemeigenes Projekt mit Visual C++ 2005, bevor Sie auf irgendeines seiner Module /clr anwenden.

Die folgenden Schritte gewährleisten in der angegebenen Reihenfolge den einfachsten Weg einer Kompilierung mit /clr. Wichtig ist dabei, das Projekt nach jedem dieser Schritte zu kompilieren und auszuführen.

Ältere Versionen als Visual C++ 2003

Wenn Sie von einer älteren Version als Visual C++ 2003 auf Visual C++ 2005 aktualisieren, werden Ihnen möglicherweise Compilerfehler angezeigt, die sich auf die erweiterte C++-Standardkonformität in Visual C++ 2003 beziehen. Weitere Informationen finden Sie unter Wichtige Änderungen im Visual C++-Compiler.

Aktualisieren von Visual C++ 2003

Projekte, die mit Visual C++ 2003 erstellt wurden, müssen zunächst ohne /clr kompiliert werden, da es in Visual C++ 2005 eine verbesserte ANSI/ISO-Kompatibilität und einige grundlegende Änderungen gibt. Weitere Informationen finden Sie unter Wichtige Änderungen im Visual C++-Compiler. Security Enhancements in the CRT ist wahrscheinlich die Änderung, die die meiste Aufmerksamkeit verlangt. Code, der das CRT verwendet, löst sehr wahrscheinlich Veraltungswarnungen aus. Diese Warnungen lassen sich zwar unterdrücken, ein Migrieren zu den neuen Security-Enhanced Versions of CRT Functions ist jedoch vorzuziehen, da sie eine höhere Sicherheit gewährleisten und möglicherweise Sicherheitsprobleme in Ihrem Code aufdecken.

Aktualisieren von Managed Extensions for C++

Bei Projekten, die mit Visual C++ .NET oder Visual C++ 2003 unter Verwendung von Managed Extensions for C++ erstellt wurden, ist mindestens eine Änderung in den Projekteinstellungen erforderlich, da diese Erweiterungen veraltet sind. Folglich lässt sich mit Managed Extentions für C++ geschriebener Code nicht unter /clr kompilieren. Stattdessen sollte /clr:oldSyntax verwendet werden.

C-Code in C++ konvertieren

Obwohl Visual C++ 2005 C-Dateien kompiliert, ist es notwendig, diese für eine Kompilierung mit /clr in C++ zu konvertieren. Der eigentliche Dateiname muss nicht geändert werden. Sie können /Tp verwenden (Informationen dazu finden Sie unter /Tc, /Tp, /TC, /TP (Typ der Quelldatei angeben)). Beachten Sie, dass zwar C++-Quellcodedateien für /clr erforderlich sind, der Code jedoch nicht für die Verwendung objektorientierter Paradigmen umgestaltet werden muss.

Es ist sehr wahrscheinlich, dass C-Code bei einer Kompilierung als C++-Datei gewisse Änderungen erfordert. Da die C++-Typsicherheitsregeln streng sind, müssen Typkonvertierungen explizit durch Umwandlungen vorgenommen werden. Beispielsweise gibt malloc einen void-Zeiger zurück, kann aber durch Umwandlung einem Zeiger zugewiesen werden, der auf einen beliebigen Typ in C zeigt:

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

Auch Funktionszeiger sind in C++ streng typsicher, deshalb muss der folgende C-Code geändert werden. Es ist das Beste, in C++ einen typedef zu erstellen, der den Funktionszeigertyp definiert, und diesen Typ zur Umwandlung von Funktionszeigern zu verwenden:

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

C++ verlangt außerdem, dass Funktionen entweder einen Prototyp haben oder vollständig definiert sind, bevor auf sie verwiesen wird oder sie aufgerufen werden können.

In C-Code verwendete Bezeichner, die in C++ Schlüsselwörter sind, (wie virtual, new, delete, bool, true, false usw.) müssen umbenannt werden. Dies kann im Allgemeinen durch einfache Such- und Ersetzungsvorgänge erfolgen.

Schließlich erfordern COM-Aufrufe im C-Format die explizite Verwendung von v-table und dem this-Zeiger. Dies gilt nicht für C++:

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

Umkonfigurieren von Projekteinstellungen

Nachdem nun das Projekt in Visual C++ 2005 kompiliert und ausgeführt werden kann, ist es besser, neue Projektkonfigurationen für /clr zu erstellen, statt die Standardkonfigurationen anzupassen. /clr ist mit einigen Compileroptionen nicht kompatibel. Indem Sie separate Konfigurationen erstellen, können Sie das Projekt als systemeigenen oder als verwalteten Code erstellen. Wenn /clr im Dialogfeld Eigenschaftenseiten ausgewählt wird, werden Projekteinstellungen, die nicht mit /clr kompatibel sind, deaktiviert (deaktivierte Optionen werden nicht automatisch wieder aktiviert, wenn die Auswahl von /clr rückgängig gemacht wird).

Erstellen neuer Projektkonfigurationen

Sie können im Dialogfeld "Neue Projektkonfiguration" die Option Einstellungen kopieren von zum Erstellen einer Projektkonfiguration auf Grundlage der vorhandenen Projekteinstellungen verwenden. Führen Sie dies einmal für die Debugkonfiguration und einmal für die Releasekonfiguration durch. Anschließend können Änderungen an der /clr-spezifischen Konfiguration vorgenommen werden, ohne dass die ursprünglichen Projektkonfigurationen berührt werden.

Projekte, die benutzerdefinierte Buildregeln verwenden, erfordern möglicherweise zusätzliche Aufmerksamkeit.

Dieser Schritt hat auf Projekte, die Makefiles verwenden, unterschiedliche Auswirkungen. In diesem Fall kann ein separates Buildziel konfiguriert werden, oder es kann eine /clr-kompilierungsspezifische Version aus einer Kopie des Originals erstellt werden.

Ändern von Projekteinstellungen

Um /clr in der Entwicklungsumgebung auszuwählen, folgen Sie den Anweisungen unter /clr (Common Language Runtime-Kompilierung). Wie bereits erwähnt, werden in diesem Schritt automatisch sich widersprechende Projekteinstellungen deaktiviert.

Hinweis:

Beim Aktualisieren einer verwalteten Bibliothek oder eines Webdienstprojekts von Visual C++ 2003 auf Visual C++ 2005 wird die /Zl-Compileroption auf der Eigenschaftenseite für die Befehlszeile hinzugefügt. Dadurch wird LNK2001 verursacht. Beheben Sie das Problem, indem Sie /Zl auf der Eigenschaftenseite für die Befehlszeile entfernen. Weitere Informationen finden Sie unter /Zl (Kein Standardbibliotheksname) und Gewusst wie: Öffnen von Projekteigenschaftenseiten. Eine andere Möglichkeit besteht darin, der Zusätzliche Abhängigkeiten-Eigenschaft des Linkers msvcrt.lib und msvcmrt.lib hinzuzufügen.

Bei mit Makefiles erstellten Projekten müssen nicht kompatible Compileroptionen manuell deaktiviert werden, sobald /clr hinzugefügt wird. Informationen über Compileroptionen, die nicht kompatibel mit /clr sind, finden Sie unter Einschränkungen für "/clr".

Vorkompilierte Header

Vorkompilierte Header werden unter /clr unterstützt. Wenn Sie jedoch nur einige der CPP-Dateien mit /clr kompilieren (und den Rest als systemeigenen Code) sind einige Änderungen erforderlich, da mit /clr vorkompilierte Header nicht kompatibel sind mit solchen, die ohne /clr erzeugt wurden. Diese Inkompatibilität basiert auf der Tatsache, dass /clr Metadaten generiert und benötigt. Mit /clr kompilierte Module können folglich vorkompilierte Header, die keine Metadaten enthalten, nicht verwenden, und umgekehrt können nicht mit /clr kompilierte Module keine vorkompilierten Headerdateien verwenden, die Metadaten enthalten.

Um ein Projekt zu kompilieren, in dem einige Module mit /clr kompiliert sind, deaktivieren Sie am besten vorkompilierte Header insgesamt. (Öffnen Sie im Dialogfeld Eigenschaftenseiten des Projekts den Knoten C/C++, und wählen Sie Vorkompilierte Header aus. Ändern Sie dann die Eigenschaft Erstellen/Verwenden vorkompilierter Header in "Vorkompilierte Header nicht verwenden".)

Allerdings beschleunigen vorkompilierte Header insbesondere in großen Projekten die Kompilierung, insofern ist eine Deaktivierung dieses Features nicht wünschenswert. In diesem Fall ist es am besten, die /clr-Dateien und die nicht-/clr-Dateien für die Verwendung separater vorkompilierter Header zu konfigurieren. Dies kann in einem Schritt getan werden: Markieren Sie im Projektmappen-Explorer gleichzeitig alle Module, die mit /clr kompiliert werden sollen, klicken Sie dann mit der rechten Maustaste auf die Gruppe, und wählen Sie Eigenschaften aus. Ändern Sie dann die beiden Eigenschaften PCH durch Datei erstellen/verwenden und Vorkompilierte Headerdatei auf einen anderen Headerdateinamen bzw. eine andere PCH-Datei.

Beheben von Fehlern

Eine Kompilierung mit /clr führt u. U. zu Compiler-, Linker- oder Laufzeitfehlern. In diesem Abschnitt werden die häufigsten Probleme behandelt.

Zusammenführen von Metadaten

Unterschiedliche Datentypversionen können den Linker scheitern lassen, weil die für die beiden Typen generierten Metadaten nicht übereinstimmen. (Dies geschieht gewöhnlich, wenn Member eines Typs bedingt definiert sind, die Bedingungen jedoch nicht für alle CPP-Dateien gleich sind, die diesen Typ verwenden.) In diesem Fall scheitert der Linker und meldet nur den Symbolnamen sowie den Namen der zweiten OBJ-Datei, in der der Typ definiert wurde. Es ist häufig hilfreich, die Reihenfolge zu ändern, in der die OBJ-Dateien an den Linker gesendet werden, um herauszufinden, wo sich die andere Version des Datentyps befindet.

Ladeprogrammsperren-Deadlocks

In Visual C++ .NET und Visual C++ 2003 war die Initialisierung unter /clr anfällig für nicht deterministische Deadlocks. Dieses Problem wird als "Ladeprogrammsperren-Deadlock" bezeichnet. In Visual C++ 2005 ist dieses Deadlock einfacher zu vermeiden. Es wird während der Laufzeit entdeckt und gemeldet und ist nicht mehr nicht deterministisch. Das Problem mit der Ladeprogrammsperre kann immer noch auftreten, kann aber jetzt viel leichter vermieden und gelöst werden. Ausführliche Hintergrundinformationen sowie eine Anweisung und Lösungen finden Sie unter Initialisierung gemischter Assemblys.

Datenexporte

Das Exportieren von DLL-Daten ist fehleranfällig und daher nicht empfehlenswert. Das liegt daran, dass die Initialisierung des Datenabschnitts einer DLL nicht gewährleistet ist, solange kein verwalteter Teil der DLL ausgeführt wurde. Verweisen Sie mit The #using Directive auf Metadaten.

Typsichtbarkeit

Systemeigene Typen sind jetzt standardmäßig privat. In Visual C++ .NET 2002 und Visual C++ 2003 waren systemeigene Typen standardmäßig öffentlich. Das kann dazu führen, dass ein systemeigener Typ außerhalb der DLL nicht sichtbar ist. Beheben Sie diesen Fehler, indem Sie zu diesen Typen public hinzufügen. Weitere Informationen finden Sie unter Type and Member Visibility.

Gleitkomma- und Ausrichtungsprobleme

__controlfp wird von der Common Language Runtime nicht unterstützt (weitere Informationen finden Sie unter _control87, _controlfp, __control87_2). Auch align (C++) wird von der CLR nicht berücksichtigt.

COM-Initialisierung

Die Common Language Runtime initialisiert COM automatisch beim Initialisieren eines Moduls. Bei automatischer Initialisierung wird COM als MTA initialisiert. Folglich führt explizites Initialisieren von COM zu Rückgabecodes, die angeben, dass COM bereits initialisiert ist. Wenn Sie versuchen, COM mit einem bestimmten Threadingmodell zu initialisieren, obwohl die CLR COM bereits mit einem anderen Threadingmodell initialisiert hat, kann die Anwendung fehlschlagen.

COM-Initialisierung und damit verbundene Fehlercodes müssen entweder den Fall einer bereits erfolgten COM-Initialisierung berücksichtigen. Oder aber Aufrufe von CoInitialize und CoUninitialize werden einfach grundsätzlich entfernt. Die Common Language Runtime startet COM standardmäßig als MTA; verwenden Sie /CLRTHREADATTRIBUTE (Festlegen des CLR-Threadattributs), um dies zu ändern.

Leistungsaspekte

Möglicherweise stellen Sie eine Verschlechterung der Leistung fest, wenn systemeigene für MSIL generierte C++-Methoden indirekt aufgerufen werden (durch virtuelle Funktionsaufrufe oder die Verwendung von Funktionszeigern). Weitere Informationen dazu finden Sie unter Doppeltes Thunking (C++).

Wenn Sie von systemeigenem Code zu MSIL wechseln, werden Sie feststellen, dass das Workingset größer wird. Das liegt daran, dass die Common Language Runtime viele Features enthält, die sicherstellen, dass Programme ordnungsgemäß ausgeführt werden. Falls die /clr-Anwendung nicht ordnungsgemäß funktioniert, können Sie C4793 aktivieren (standardmäßig deaktiviert). Weitere Informationen hierzu finden Sie unter Compilerwarnung (Stufe 1 und 3) C4793.

Programmabstürze beim Herunterfahren

In manchen Fällen wird die CLR heruntergefahren, bevor die Ausführung des verwalteten Codes abgeschlossen ist. Die Ursache kann in der Verwendung von std::set_terminate und SIGTERM liegen. Weitere Informationen finden Sie unter signal Constants und set_terminate (<exception>).

Verwenden neuer Visual C++-Features

Sobald die Anwendung kompiliert, verknüpft und ausgeführt werden kann, können Sie .NET-Features in jedem mit /clr kompilierten Modul verwenden. Weitere Informationen finden Sie unter Language Features for Targeting the CLR.

Wenn Sie Managed Extensions for C++ verwendet haben, können Sie den Code für die Verwendung der neuen Syntax konvertieren. Eine Zusammenfassung der syntaktischen Unterschiede finden Sie unter Prüfliste der Syntaxaktualisierung für Managed Extensions for C++. Ausführliche Informationen zum Konvertieren von Managed Extensions for C++ finden Sie unter Einführung in die C++/CLI-Migration

Informationen zur .NET-Programmierung in Visual C++ finden Sie unter:

Siehe auch

Konzepte

Gemischte (systemeigene und verwaltete) Assemblys