Практическое руководство. Миграция в /clr:pure (C++/CLI)
В этом разделе рассматриваются вопросы, которые могут возникнуть во время осуществления миграции в чистый MSIL с помощью /clr:pure (дополнительные сведения см. в разделе /clr (компиляция CLR)). Раздел подразумевает, что подвергаемый миграции код был скомпилирован как смешанная сборка с помощью параметра /clr, так как прямого пути миграции из неуправляемого кода в чистый MSIL не существует. Дополнительные сведения о неуправляемом коде см. в разделе Практическое руководство. Переход на /clr перед осуществлением миграции в чистый MSIL.
Основные изменения
Чистый MSIL состоит из инструкций MSIL, поэтому код с функциями, которые нельзя реализовать средствами MSIL, не скомпилируется. Это касается и функций, использующих соглашения о вызовах, отличные от __clrcall (функции, отличные от __clrcall могут вызываться в компоненте чистого MSIL, но не определяться).
Чтобы избежать ошибок в среде выполнения, активируйте предупреждение C4412. Активируйте предупреждение C4412, добавив #pragma warning (default : 4412) в каждую единицу компиляции, которая компилируется с /clr:pure и передает типы C++ в IJW (/clr)) или машинный код и вызывает их обратно. Дополнительные сведения см. в разделе Предупреждение компилятора (уровень 2) C4412.
Архитектурные вопросы
Некоторые ограничения сборок, использующих чистый MSIL, перечисленные в разделе Чистый и проверяемый код (C++/CLI), порождают последствия высокого уровня при разработке стратегий разработки приложения и миграции. Следует отметить, что в отличие от смешанных сборок, сборки чистого MSIL не совместимы с неуправляемыми модулями полностью.
Сборки чистого MSIL могут вызывать неуправляемые функции, но не могут вызываться управляемыми функциями. В результате, чистый MSIL является лучшим решением для клиентского кода, который использует неуправляемые функции, чем для кода сервера, используемого неуправляемыми функциями. Если функциональность, которая содержится в сборке чистого MSIL, используется неуправляемой функцией, то смешанная сборка должна применяться как уровень интерфейса.
Приложения, которые используют ATL или MFC, не являются удобными решениями для миграции в чистый MSIL, поскольку данные библиотеки не поддерживаются в этой версии. Таким же образом, SDK для Windows содержат файл заголовка, который не компилируется с /clr:pure.
Хотя сборки чистого MSIL и могут вызывать неуправляемые функции, подобная способность ограничена простыми функциями C-типа. Использование более сложных неуправляемых API, вероятно, потребует предоставления неуправляемой функциональности в виде COM-интерфейса или смешенной сборки, которая может служить как интерфейс между чистым MSIL и неуправляемыми компонентами. Единственный путь для применения неуправляемой функции – это использование слоя смешанной сборки. В этом случае функция выполняет обратный вызов. Например, чистая сборка может предоставлять собственную вызываемую функцию для использования обратного вызова.
Домены приложения и соглашения о вызове
Несмотря на то, что сборки чистого MSIL могут использовать неуправляемую функцию, функции и статистические данные обрабатываются по-разному. В чистых сборках функции реализуются с соглашением о вызове __clrcall, а статистические данные хранятся по доменам приложений. Эта отличается от заданного поведения по умолчанию в неуправляемых и смешанных сборках, которые используют соглашение о вызове __cdecl в функциях и хранят статические данные по процессам.
В рамках контекста чистого MSIL (и проверяемого кода, скомпилированного с /clr:safe) значения по умолчанию не представляют сложности, поскольку __clrcall является соглашением о вызове по умолчанию в среде CLR, а домены приложений — собственной областью для статистических и глобальных данных приложений .NET. Однако во время взаимодействия с неуправляемыми или смешанными компонентами разная обработка функций и глобальных данных может вызвать проблемы.
Например, если компонент чистого MSIL вызывает функцию в неуправляемой или смешанной библиотеке DLL, файл заголовка DLL используется для компиляции чистой сборки. Тем не менее, пока соглашение о вызове для каждой функции в заголовке не будет явно обозначено, всем функциям будет присваиваться __clrcall. Впоследствии это приведет к ошибкам во время выполнения, поскольку функции, скорее всего, будут реализованы вместе с соглашением __cdecl. Функции в неуправляемом файле заголовка должны быть явно обозначены как __cdecl, или же весь исходный код библиотеки DLL должен быть перекомпилирован с /clr:pure.
Аналогичным образом указатели функции предполагают наличие указателя на функции __clrcall в случае компиляции с /clr:pure. Указатели должны явно отмечаться правильным соглашением о вызове.
Дополнительные сведения см. в разделе Домены приложений и Visual C++.
Ограничения компоновки
Компоновщик Visual C++ не соединяет смешанные и чистые OBJ-файлы, поскольку область хранения и соглашения о вызове не совпадают.