Практическое руководство. Миграция в /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, truedeleteboolfalse, и т. д.), должны быть переименованы. Как правило, это изменение можно сделать с помощью простых операций поиска и замены.

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++см. в следующих статье:

См. также

Смешанные (собственные и управляемые) сборки