Практическое руководство. Миграция в /clr
В этой статье рассматриваются проблемы, возникающие при компиляции машинного кода с /clr
помощью . (Дополнительные сведения см. в разделе /clr (компиляция среды CLR)).) /clr
позволяет собственному коду C++ вызываться и вызываться из сборок .NET в дополнение к другому собственному коду C++. Дополнительные сведения о преимуществах компиляции с помощью сборок с использованием смешанных (собственных и управляемых) сборок и взаимодействия в машинном коде и .NET./clr
Известные проблемы, связанные с компиляцией проектов библиотек с помощью /clr
Visual Studio содержит некоторые известные проблемы при компиляции проектов библиотек с помощью /clr
:
Код может запрашивать типы во время выполнения с
CRuntimeClass::FromName
помощью . Однако если тип находится в библиотеке DLL MSIL (скомпилированной с/clr
), вызовFromName
может завершиться ошибкой, если он возникает до запуска статических конструкторов в управляемой библиотеке DLL. (Эта проблема не отображается, еслиFromName
вызов происходит после выполнения кода в управляемой библиотеке DLL.) Чтобы обойти эту проблему, можно принудительно создать управляемый статический конструктор: определить функцию в управляемой библиотеке DLL, экспортировать ее и вызвать из собственного приложения MFC. Например:// MFC extension DLL Header file: __declspec( dllexport ) void EnsureManagedInitialization () { // managed code that won't be optimized away System::GC::KeepAlive(System::Int32::MaxValue); }
Компиляция с помощью Visual C++
Прежде чем использовать /clr
любой модуль в проекте, сначала скомпилируйте и свяжите собственный проект с Visual Studio.
Следующие шаги, описанные в порядке, предоставляют самый простой /clr
путь к компиляции. Важно скомпилировать и запустить проект после каждого из этих шагов.
Обновление с более ранних версий Visual Studio
Если вы обновляете Visual Studio с более ранней версии, в Visual Studio могут возникнуть ошибки компилятора, связанные с расширенным соответствием C++ уровня "Стандартный".
Проекты, созданные с более ранними версиями Visual Studio, также должны быть скомпилированы без /clr
. Visual Studio теперь увеличила соответствие C++ уровня "Стандартный" и некоторые критические изменения. Изменения, которые, скорее всего, требуют наибольшего внимания, являются функциями безопасности в CRT. Код, использующий CRT, скорее всего, выдает предупреждения об отмене. Эти предупреждения можно отключить, но миграция на новые версии функций CRT с повышенными безопасностью предпочтительнее, так как они обеспечивают более высокую безопасность и могут выявить проблемы с безопасностью в коде.
Обновление с управляемые расширения для C++
В Visual Studio 2005 и более поздних версиях код, написанный с помощью управляемые расширения для C++, не будет компилироваться в разделе /clr
.
Преобразование кода C в C++
Хотя Visual Studio компилирует файлы C, их необходимо преобразовать в C++ для /clr
компиляции. Фактическое имя файла не должно быть изменено; вы можете использовать /Tp
(см/Tc
. , /TC
/Tp
, /TP
(указать тип исходного файла)).) Хотя для файлов исходного кода C++ не требуется /clr
рефакторинг кода для использования объектно-ориентированных парадигм.
Код C, скорее всего, требует изменений при компиляции в виде файла C++. Правила безопасности типов C++ являются строгими, поэтому преобразования типов должны быть явными с помощью приведения. Например, malloc возвращает указатель void, но может быть назначен указателю на любой тип в C с приведением:
int* a = malloc(sizeof(int)); // C code
int* b = (int*)malloc(sizeof(int)); // C++ equivalent
Указатели функций также строго типобезопасны в C++, поэтому для следующего кода C требуется изменение. В C++рекомендуется создать typedef
тип указателя функции, а затем использовать этот тип для приведения указателей функций:
NewFunc1 = GetProcAddress( hLib, "Func1" ); // C code
typedef int(*MYPROC)(int); // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );
C++ также требует, чтобы функции были прототипированы или полностью определены, прежде чем они могут быть ссылаться или вызываться.
Идентификаторы, используемые в коде C, которые могут быть ключевыми словами в C++ (напримерvirtual
, , new
delete
, bool
, true
false
и т. д.), должны быть переименованы. Как правило, это изменение можно сделать с помощью простых операций поиска и замены.
COMObj1->lpVtbl->Method(COMObj, args); // C code
COMObj2->Method(args); // C++ equivalent
Перенастройка параметров проекта
После компиляции и запуска проекта в Visual Studio необходимо создать новые конфигурации проекта, /clr
а не изменять конфигурации по умолчанию. /clr
несовместим с некоторыми параметрами компилятора. Создание отдельных конфигураций позволяет создавать проект как собственный или управляемый. Если /clr
выбрано в диалоговом окне страниц свойств, параметры проекта не совместимы с /clr
отключены. (Отключенные параметры не восстанавливаются автоматически, если /clr
позже не выбрано.)
Создание конфигураций проекта
Параметры копирования можно использовать в диалоговом окне "Создание конфигурации проекта" (создание>конфигурации активного решения> Configuration Manager>) для создания конфигурации проекта на основе существующих параметров проекта. Создайте копию конфигурации один раз для конфигурации отладки и один раз для конфигурации выпуска. Последующие изменения можно применить только к /clr
конфигурациям с определенными значениями, оставив исходные конфигурации проекта нетронутыми.
Для проектов, использующих пользовательские правила сборки, может потребоваться дополнительное внимание.
Этот шаг имеет различные последствия для проектов, использующих makefiles. В этом случае можно настроить отдельный целевой объект сборки или версию, конкретную для /clr
компиляции, можно создать из копии исходного объекта.
Изменение параметров проекта
/clr
можно выбрать в среде разработки, следуя инструкциям в разделе /clr (компиляция среды CLR). Как упоминалось ранее, этот шаг автоматически отключает конфликтующие параметры проекта.
Примечание.
При обновлении управляемой библиотеки или проекта веб-службы из Visual Studio 2003 /Zl
параметр компилятора добавляется на страницу свойств командной строки . Это приводит к LNK2001 ошибкам. Удалите /Zl
с страницы свойств командной строки , чтобы устранить ошибки. Дополнительные сведения см. в разделе /Zl
(Опустить имя библиотеки по умолчанию) и Задать свойства компилятора и сборки.
Для проектов, созданных с помощью файлов makefile, несовместимые параметры компилятора должны быть отключены вручную после /clr
добавления. Сведения о параметрах компилятора, несовместимых с /clr
ограничениями./clr
Предварительно скомпилированные заголовки
Предварительно скомпилированные заголовки поддерживаются в разделе /clr
. Однако если вы компилируете только некоторые файлы CPP ( /clr
скомпилируя остальные как собственные), некоторые изменения требуются. Предварительно созданные заголовки /clr
несовместимы с предварительно созданными заголовками /clr
, так как /clr
создаются и требуют метаданных. Модули, скомпилированные с /clr
помощью не могут использовать предварительно скомпилированные заголовки, которые не включают метаданные, а/clr
не модули не могут использовать предварительно скомпилированные файлы заголовков, которые содержат метаданные.
Самый простой способ компиляции проекта, в котором некоторые модули компилируются с /clr
помощью, — отключить предварительно скомпилированные заголовки полностью. (В диалоговом окне "Страницы свойств проекта" откройте окно Узел C/C++ и выберите предварительно скомпилированные заголовки. Затем измените свойство Create/Use Precompiled Headers на "Not Using Precompiled Headers ".
Тем не менее, особенно для крупных проектов, предварительно скомпилированные заголовки обеспечивают гораздо большую скорость компиляции, поэтому отключение этой функции не желательно. В этом случае лучше настроить /clr
и некомпилировать/clr
файлы для использования отдельных предварительно скомпилированных заголовков. Их можно настроить на одном шаге: несколько выборок модулей для компиляции с /clr
помощью Обозреватель решений. Щелкните группу правой кнопкой мыши и выберите пункт "Свойства". Затем измените свойства файла создания и использования PCH-файла и предварительно скомпилированного файла заголовка , чтобы использовать другое имя файла заголовка и PCH-файл соответственно.
Исправление ошибок
Компиляция кода /clr
может привести к ошибкам компилятора, компоновщика или среды выполнения. В этом разделе рассматриваются наиболее распространенные проблемы.
Слияние метаданных
Различные версии типов данных могут привести к сбою компоновщика, так как метаданные, созданные для двух типов, не соответствуют. (Ошибки возникают при условном определении членов типа, но условия не совпадают для всех файлов CPP, использующих тип.) В этом случае компоновщик завершается ошибкой, сообщая только имя символа и имя второго OBJ-файла, в котором был определен тип. Возможно, полезно изменить порядок отправки OBJ-файлов компоновщику, чтобы узнать расположение другой версии типа данных.
Взаимоблокировка блокировки загрузчика
Может возникать "взаимоблокировка блокировки загрузчика", но детерминирована и обнаружена и сообщается во время выполнения. Сведения о инициализации смешанных сборок см . в разделе "Инициализация смешанных сборок" для получения подробных сведений, рекомендаций и решений.
Экспорт данных
Экспорт данных DLL подвержен ошибкам и не рекомендуется в коде /clr
. Это связано с тем, что инициализация раздела данных библиотеки DLL не гарантируется, пока не будет выполнена определенная управляемая часть библиотеки DLL. Ссылки на метаданные с #using
директивами.
Видимость типов
Собственные типы по private
умолчанию. Собственный private
тип не отображается вне библиотеки DLL. Устраните эту ошибку, добавив public
к этим типам.
Проблемы с плавающей запятой и выравниванием
__controlfp
не поддерживается в среде CLR. (Дополнительные сведения см. в разделе _control87
, __control87_2
_controlfp
.) СРЕДА CLR также не уважаетalign
.
Инициализация COM
Среда CLR инициализирует COM автоматически при инициализации модуля (при инициализации COM автоматически выполняется так, как MTA). В результате явно инициализация COM возвращает коды возврата, указывающие, что COM уже инициализирован. Попытка явно инициализировать COM с помощью одной модели потоков, когда среда CLR уже инициализировала COM в другую модель потоков, может привести к сбою приложения.
Среда CLR запускает COM как MTA по умолчанию; используйте /CLRTHREADATTRIBUTE
(задать атрибут потока CLR) для изменения модели COM.
Проблемы с производительностью
Вы можете увидеть снижение производительности, если собственные методы C++, созданные в MSIL, вызываются косвенно (через вызовы виртуальных функций или с помощью указателей функций). Дополнительные сведения см. в разделе Double Thunking.
При переходе из машинного кода в MSIL вы заметите увеличение размера рабочего набора. Это увеличение происходит, так как среда CLR предоставляет множество функций, чтобы обеспечить правильную работу программ. Если приложение /clr
работает неправильно, может потребоваться включить предупреждение компилятора по умолчанию (уровень 1 и 3) C4793.
Сбой программы при завершении работы
В некоторых случаях среда CLR может завершить работу до завершения работы управляемого кода. std::set_terminate
Использование и SIGTERM
может вызвать завершение работы. Дополнительные сведения см. в разделе signal
констант и set_terminate
.
Использование новых функций Visual C++
После компиляции, ссылок и запусков приложения можно начать использование функций .NET в любом модуле, скомпилированном./clr
Для получения дополнительной информации см. Component Extensions for Runtime Platforms.
Дополнительные сведения о программировании .NET в Visual C++см. в следующих статье: