Instrukcje: migrowanie do /clr
W tym artykule omówiono problemy występujące podczas kompilowania kodu natywnego za pomocą polecenia /clr
. (Aby uzyskać więcej informacji, zobacz /clr (kompilacja środowiska uruchomieniowego języka wspólnego)). /clr
umożliwia wywoływanie i wywoływanie natywnego kodu C++ z zestawów platformy .NET oprócz innego natywnego kodu C++. Aby uzyskać więcej informacji na temat zalet kompilowania za pomocą /clr
programu , zobacz Zestawy mieszane (natywne i zarządzane) oraz Współdziałanie natywne i .NET.
Znane problemy z kompilowaniem projektów biblioteki za pomocą polecenia /clr
Program Visual Studio zawiera niektóre znane problemy podczas kompilowania projektów biblioteki za pomocą polecenia /clr
:
Kod może wykonywać zapytania dotyczące typów w czasie wykonywania za pomocą polecenia
CRuntimeClass::FromName
. Jeśli jednak typ znajduje się w biblioteki DLL MSIL (skompilowanej za pomocą/clr
polecenia ), wywołanieFromName
metody może zakończyć się niepowodzeniem, jeśli wystąpi przed uruchomieniem konstruktorów statycznych w zarządzanej biblioteki DLL. (Ten problem nie zostanie wyświetlony, jeśliFromName
wywołanie zostanie wykonane po wykonaniu kodu w zarządzanej biblioteki DLL). Aby obejść ten problem, możesz wymusić konstruowanie zarządzanego konstruktora statycznego: zdefiniować funkcję w zarządzanej bibliotece DLL, wyeksportować ją i wywołać z natywnej aplikacji MFC. Na przykład:// MFC extension DLL Header file: __declspec( dllexport ) void EnsureManagedInitialization () { // managed code that won't be optimized away System::GC::KeepAlive(System::Int32::MaxValue); }
Kompilowanie przy użyciu języka Visual C++
Przed użyciem /clr
dowolnego modułu w projekcie najpierw skompiluj i połącz projekt macierzysty z programem Visual Studio.
Poniższe kroki, wykonywane w podanej kolejności, zapewniają najłatwiejszą ścieżkę /clr
do kompilacji. Ważne jest, aby skompilować i uruchomić projekt po każdym z tych kroków.
Uaktualnianie z wcześniejszych wersji programu Visual Studio
W przypadku uaktualniania programu Visual Studio z wcześniejszej wersji mogą pojawić się błędy kompilatora związane z rozszerzoną zgodnością standardowego języka C++ w programie Visual Studio.
Projekty skompilowane przy użyciu wcześniejszych wersji programu Visual Studio powinny być również kompilowane bez /clr
programu . Program Visual Studio zwiększył zgodność standardowego języka C++ i pewne zmiany powodujące niezgodność. Zmiany, które prawdopodobnie będą wymagały największej uwagi, to funkcje zabezpieczeń w CRT. Kod korzystający z narzędzia CRT prawdopodobnie generuje ostrzeżenia o wycofaniu. Te ostrzeżenia można pominąć, ale migracja do nowych wersji rozszerzonych zabezpieczeń funkcji CRT jest preferowana, ponieważ zapewniają lepsze zabezpieczenia i mogą ujawnić problemy z zabezpieczeniami w kodzie.
Uaktualnianie z rozszerzeń zarządzanych dla języka C++
W programie Visual Studio 2005 i nowszych wersjach kod napisany za pomocą rozszerzeń zarządzanych dla języka C++ nie będzie kompilowany w programie /clr
.
Konwertowanie kodu C na C++
Mimo że program Visual Studio skompiluje pliki C, konieczne jest przekonwertowanie ich na język C++ na potrzeby /clr
kompilacji. Rzeczywista nazwa pliku nie musi zostać zmieniona; Można użyć /Tp
(zobacz /Tc
, , /Tp
, /TC
/TP
(Określ typ pliku źródłowego)). Mimo że pliki kodu źródłowego języka C++ są wymagane dla /clr
programu , nie jest konieczne refaktoryzowanie kodu w celu używania paradygmatów zorientowanych na obiekty.
Kod języka C może wymagać zmian podczas kompilowania jako pliku C++. Reguły bezpieczeństwa typów języka C++ są ścisłe, dlatego konwersje typów muszą być jawne z rzutami. Na przykład malloc zwraca wskaźnik void, ale może być przypisany do wskaźnika do dowolnego typu w języku C z rzutowania:
int* a = malloc(sizeof(int)); // C code
int* b = (int*)malloc(sizeof(int)); // C++ equivalent
Wskaźniki funkcji są również ściśle bezpieczne dla typów w języku C++, więc poniższy kod języka C wymaga modyfikacji. W języku C++najlepiej utworzyć element typedef
definiujący typ wskaźnika funkcji, a następnie użyć tego typu do rzutowania wskaźników funkcji:
NewFunc1 = GetProcAddress( hLib, "Func1" ); // C code
typedef int(*MYPROC)(int); // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );
Język C++ wymaga również, aby funkcje były prototypowane lub w pełni zdefiniowane, zanim będą mogły być przywoływane lub wywoływane.
Należy zmienić nazwy identyfikatorów używanych w kodzie języka C, które są słowami kluczowymi w języku C++ (na przykład virtual
, , new
bool
delete
, true
, false
itp.). Tę zmianę można zazwyczaj wykonać przy użyciu prostych operacji wyszukiwania i zastępowania.
COMObj1->lpVtbl->Method(COMObj, args); // C code
COMObj2->Method(args); // C++ equivalent
Ponowne konfigurowanie ustawień projektu
Po skompilowaniu i uruchomieniu projektu w programie Visual Studio należy utworzyć nowe konfiguracje /clr
projektu zamiast modyfikować konfiguracje domyślne. /clr
jest niezgodny z niektórymi opcjami kompilatora. Tworzenie oddzielnych konfiguracji umożliwia tworzenie projektu jako natywnego lub zarządzanego. Po /clr
wybraniu w oknie dialogowym strony właściwości ustawienia projektu niezgodne z /clr
programem są wyłączone. (Wyłączone opcje nie są automatycznie przywracane, jeśli /clr
zostaną później niezaznaczone).
Tworzenie nowych konfiguracji projektu
Możesz użyć opcji Kopiuj ustawienia Z w oknie dialogowym Nowa konfiguracja projektu (Utwórz>konfigurację aktywnego rozwiązania>programu Configuration Manager>Nowy), aby utworzyć konfigurację projektu na podstawie istniejących ustawień projektu. Utwórz kopię konfiguracji raz dla konfiguracji debugowania i raz dla konfiguracji wydania. Kolejne zmiany można następnie zastosować tylko do /clr
konfiguracji specyficznych dla projektu, pozostawiając oryginalne konfiguracje projektu bez zmian.
Projekty korzystające z niestandardowych reguł kompilacji mogą wymagać dodatkowej uwagi.
Ten krok ma różne konsekwencje dla projektów korzystających z plików make. W takim przypadku można skonfigurować oddzielny element docelowy kompilacji lub wersję specyficzną dla /clr
kompilacji na podstawie kopii oryginalnej.
Zmienianie ustawień projektu
/clr
Można wybrać w środowisku projektowym, postępując zgodnie z instrukcjami w / clr (kompilacja środowiska uruchomieniowego języka wspólnego). Jak wspomniano wcześniej, ten krok spowoduje automatyczne wyłączenie ustawień projektu powodującego konflikt.
Uwaga
Podczas uaktualniania biblioteki zarządzanej lub projektu usługi internetowej z programu Visual Studio 2003 /Zl
opcja kompilatora jest dodawana do strony właściwości Wiersza polecenia. Powoduje to błędy LNK2001. Usuń /Zl
ze strony właściwości Wiersza polecenia, aby usunąć błędy. Aby uzyskać więcej informacji, zobacz /Zl
(Pomijanie domyślnej nazwy biblioteki) i Ustawianie właściwości kompilatora i kompilacji.
W przypadku projektów utworzonych za pomocą plików make, niezgodne opcje kompilatora muszą być wyłączone ręcznie po /clr
dodaniu. Aby uzyskać informacje na temat opcji kompilatora, które nie są zgodne z /clr
programem , zobacz /clr
ograniczenia.
Prekompilowane nagłówki
Prekompilowane nagłówki są obsługiwane w obszarze /clr
. Jeśli jednak tylko skompilujesz niektóre pliki /clr
CPP (kompilując resztę jako natywną), wymagane są pewne zmiany. Wstępnie skompilowane nagłówki wygenerowane /clr
za pomocą elementu nie są zgodne ze wstępnie skompilowanym nagłówkami wygenerowanymi bez /clr
elementu , ponieważ /clr
generuje i wymaga metadanych. Moduły skompilowane /clr
za pomocą polecenia nie mogą używać wstępnie skompilowanych nagłówków, które nie zawierają metadanych, a moduły inne/clr
niż moduły nie mogą używać wstępnie skompilowanych plików nagłówkowych zawierających metadane.
Najprostszym sposobem skompilowania projektu, w którym są kompilowane /clr
niektóre moduły, jest całkowite wyłączenie prekompilowanych nagłówków. (W oknie dialogowym Strony właściwości projektu otwórz okno dialogoweWęzeł C/C++ i wybierz pozycję Prekompilowane nagłówki. Następnie zmień właściwość Create/Use Precompiled Headers na "Not Using Precompiled Headers".
Jednak szczególnie w przypadku dużych projektów prekompilowane nagłówki zapewniają znacznie lepszą szybkość kompilacji, więc wyłączenie tej funkcji nie jest pożądane. W takim przypadku najlepszym rozwiązaniem jest skonfigurowanie /clr
plików innych niż i do/clr
używania oddzielnych prekompilowanych nagłówków. Można je skonfigurować w jednym kroku: wybierz wiele modułów do skompilowania /clr
przy użyciu Eksplorator rozwiązań. Kliknij prawym przyciskiem myszy grupę, a następnie wybierz pozycję Właściwości. Następnie zmień zarówno właściwości Create/Use PCH Through File and Precompiled Header File ,aby użyć innej nazwy pliku nagłówka i pliku PCH, odpowiednio.
Naprawianie błędów
Kompilowanie kodu za pomocą /clr
polecenia może spowodować błędy kompilatora, konsolidatora lub środowiska uruchomieniowego. W tej sekcji omówiono najczęstsze problemy.
Scalanie metadanych
Różne wersje typów danych mogą spowodować niepowodzenie konsolidatora, ponieważ metadane wygenerowane dla tych dwóch typów nie są zgodne. (Błędy występują podczas warunkowego definiowania składowych typu, ale warunki nie są takie same dla wszystkich plików CPP, które używają typu). W takim przypadku konsolidator kończy się niepowodzeniem, zgłaszając tylko nazwę symbolu i nazwę drugiego pliku OBJ, w którym zdefiniowano typ. Może się okazać, że warto obrócić kolejność wysyłania plików OBJ do konsolidatora, aby odnaleźć lokalizację innej wersji typu danych.
Zakleszczenie blokady modułu ładującego
Może wystąpić "zakleszczenie blokady modułu ładującego", ale jest deterministyczne i wykrywane i zgłaszane w czasie wykonywania. Zobacz Inicjowanie zestawów mieszanych , aby uzyskać szczegółowe informacje, wskazówki i rozwiązania.
Eksporty danych
Eksportowanie danych dll jest podatne na błędy i nie jest zalecane w /clr
kodzie. Wynika to z faktu, że inicjowanie sekcji danych biblioteki DLL nie jest gwarantowane, dopóki część zarządzana biblioteki DLL nie zostanie wykonana. Odwołania do metadanych z dyrektywami#using
.
Widoczność typu
Typy natywne są private
domyślnie. private
Typ natywny nie jest widoczny poza biblioteką DLL. Rozwiąż ten błąd, dodając public
do tych typów.
Problemy z zmiennoprzecinką i wyrównaniem
__controlfp
program nie jest obsługiwany w środowisku uruchomieniowym języka wspólnego. (Aby uzyskać więcej informacji, zobacz _control87
, _controlfp
, __control87_2
.) ClR również nie szanuje align
.
Inicjowanie modelu COM
Środowisko uruchomieniowe języka wspólnego automatycznie inicjuje com po zainicjowaniu modułu (po zainicjowaniu modelu COM jest on wykonywany automatycznie jako MTA). W związku z tym jawne inicjowanie kodów zwracanych com wskazuje, że com jest już zainicjowany. Próba jawnego zainicjowania modelu COM przy użyciu jednego modelu wątkowego, gdy CLR zainicjował już model COM do innego modelu wątkowego, może spowodować niepowodzenie aplikacji.
Środowisko uruchomieniowe języka wspólnego domyślnie uruchamia com jako MTA; use /CLRTHREADATTRIBUTE
(Ustaw atrybut wątku CLR) w celu zmodyfikowania modelu COM.
Problemy z wydajnością
Wydajność może być zmniejszona, gdy natywne metody języka C++ generowane w języku MSIL są wywoływane pośrednio (za pośrednictwem wywołań funkcji wirtualnych lub przy użyciu wskaźników funkcji). Aby dowiedzieć się więcej, zobacz Double Thunking.
Podczas przechodzenia z natywnego do MSIL zauważysz wzrost rozmiaru zestawu roboczego. Ten wzrost występuje, ponieważ środowisko uruchomieniowe języka wspólnego udostępnia wiele funkcji, aby upewnić się, że programy działają poprawnie. Jeśli aplikacja /clr
nie działa poprawnie, możesz włączyć domyślne ostrzeżenie kompilatora (poziom 1 i 3) C4793.
Program ulega awarii po zamknięciu
W niektórych przypadkach clR może zostać zamknięty przed zakończeniem działania kodu zarządzanego. std::set_terminate
Użycie polecenia i SIGTERM
może spowodować zamknięcie. Aby uzyskać więcej informacji, zobacz signal
stałe i set_terminate
.
Korzystanie z nowych funkcji języka Visual C++
Po skompilowaniu, łączem i uruchomieniu aplikacji możesz rozpocząć korzystanie z funkcji platformy .NET w dowolnym module skompilowanym za pomocą /clr
polecenia . Aby uzyskać więcej informacji, zobacz Rozszerzenia składników dla platform środowiska uruchomieniowego.
Aby uzyskać więcej informacji na temat programowania .NET w języku Visual C++, zobacz:
Programowanie .NET w języku C++/interfejsie wiersza polecenia (Visual C++)
Component Extensions dla platform środowiska uruchomieniowego