Программирование .NET с использованием C++/CLI
По умолчанию проекты CLR, созданные с помощью Visual Studio 2015, предназначены для целевой платформы .NET Framework 4.5.2. При создании нового проекта можно использовать платформа .NET Framework 4.6. В диалоговом окне «Новый проект» измените целевую платформу в раскрывающемся списке в верхней части диалогового окна. Чтобы изменить целевую платформу для существующего проекта, закройте проект, измените файл проекта ( .vcxproj ) и измените значение целевой платформы на 4.6. Изменения вступают в силу при следующем открытии проекта.
В Visual Studio 2017 целевая платформа .NET Framework по умолчанию — 4.6.1. Селектор версий Платформы находится в нижней части диалогового окна «Новый проект «.
Установка поддержки C++/CLI в Visual Studio 2017
При установке рабочей нагрузки Visual Studio C++/CLI сама по умолчанию не устанавливается. Чтобы установить компонент после установки Visual Studio, откройте установщик Visual Studio, выбрав меню «Пуск Windows» и найдите установщик Visual Studio. Нажмите кнопку «Изменить» рядом с установленной версией Visual Studio. Перейдите на вкладку «Отдельные компоненты». Прокрутите вниз до раздела «Компиляторы», средства сборки и среды выполнения и выберите поддержку C++/CLI. Выберите «Изменить», чтобы скачать необходимые файлы и обновить Visual Studio.
В Visual Studio 2019 целевая платформа по умолчанию для проектов .NET Core — 5.0. Для проектов платформа .NET Framework по умолчанию используется значение 4.7.2. Селектор версий платформа .NET Framework находится на странице «Настройка нового проекта» диалогового окна «Создание нового проекта«.
Установка поддержки C++/CLI в Visual Studio 2019
При установке рабочей нагрузки Visual Studio C++/CLI сама по умолчанию не устанавливается. Чтобы установить компонент после установки Visual Studio, откройте установщик Visual Studio, выбрав меню «Пуск Windows» и найдите установщик Visual Studio. Нажмите кнопку «Изменить» рядом с установленной версией Visual Studio. Перейдите на вкладку «Отдельные компоненты». Прокрутите вниз до раздела «Компиляторы», средства сборки и среды выполнения и выберите поддержку C++/CLI для средств сборки версии 142 (последняя версия). Выберите «Изменить», чтобы скачать необходимые файлы и обновить Visual Studio.
В Visual Studio 2022 целевая платформа по умолчанию для проектов .NET Core — 6.0. Для проектов платформа .NET Framework по умолчанию используется значение 4.7.2. Селектор версий платформа .NET Framework находится на странице «Настройка нового проекта» диалогового окна «Создание нового проекта«.
Установка поддержки C++/CLI в Visual Studio 2022
При установке рабочей нагрузки Visual Studio C++/CLI сама по умолчанию не устанавливается. Чтобы установить компонент после установки Visual Studio, откройте установщик Visual Studio, выбрав меню «Пуск Windows» и найдите установщик Visual Studio. Нажмите кнопку «Изменить» рядом с установленной версией Visual Studio. Перейдите на вкладку «Отдельные компоненты». Прокрутите вниз до раздела «Компиляторы», средства сборки и среды выполнения и выберите поддержку C++/CLI для средств сборки версии 143 (последняя версия). Выберите «Изменить», чтобы скачать необходимые файлы и обновить Visual Studio.
Расширения языка C++/CLI

— это набор расширений языка C++, позволяющий создавать гибридные управляемые и низкоуровневые библиотеки DLL. С применением расширений C++/CLI вы сможете определять управляемые и неуправляемые классы и функции в пределах одного файла .cpp, использовать управляемые и низкоуровневые типы C и C++, как в обычном программном коде на C++, то есть простым подключением заголовочного файла и связыванием с библиотекой. Эти широчайшие возможности можно использовать для создания управляемых типов-оберток, пригодных для использования в любом языке .NET, а так же низкоуровневые классы-обертки и функции (доступные через файлы .dll, .lib и .h), пригодные для использования в программном коде на C/C++.
При использовании расширения C++/CLI маршалинг выполняется вручную, благодаря чему разработчик имеет более полный контроль и более полное представление о накладных расходах. Расширение C++/CLI с успехом можно использовать там, где механизм P/Invoke оказывается бесполезен, например, для маршалинга структур переменной длины. Еще одно преимущество расширения C++/CLI состоит в том, что оно позволяет имитировать интерфейс объединения запросов, даже если у вас нет доступа к исходным текстам вызывающего кода, многократно вызывая низкоуровневые методы без необходимости каждый раз пересекать границу между управляемым и неуправляемым кодом.
В коде, представленном ниже, мы реализовали неуправляемый класс NativeEmployee и управляемый класс Employee, служащий оберткой для первого. Управляемый код будет обращаться только к управляемому классу.
#include #include #include #include using namespace System; using namespace System::Runtime::InteropServices; class NativeEmployee < public: NativeEmployee(const wchar_t *employeeName, int age) : _employeeName(employeeName), _employeeAge(age) < >void DoWork(const wchar_t **tasks, int numTasks) < for (int i = 0; i < numTasks; i++) < wprintf(L"Пользователь %s работает в задаче %s\n", _employeeName.c_str(), tasks[i]); >> int GetAge() const < return _employeeAge; >const wchar_t *GetName() const < return _employeeName.c_str(); >private: std::wstring _employeeName; int _employeeAge; >; #pragma managed namespace EmployeeLib < public ref class Employee < < public: Employee(String ^employeeName, int age) < // Вариант 1: // IntPtr pEmployeeName = Marshal::StringToHGlobalUni(employeeName); // m_pEmployee = new NativeEmployee( // reinterpret_cast(pEmployeeName.ToPointer()), age); // Marshal::FreeHGlobal(pEmployeeName); // Вариант 2 (прямой указатель на закрепленную // управляемую строку, самый быстрый): pin_ptr ppEmployeeName = PtrToStringChars(employeeName); _employee = new NativeEmployee(ppEmployeeName, age); > ~Employee() < delete _employee; _employee = nullptr; >int GetAge() < return _employee->GetAge(); > String ^GetName() < // Вариант 1: // return Marshal::PtrToStringUni( // (IntPtr)(void *) _employee->GetName()); // Вариант 2: return msclr::interop::marshal_as(_employee->GetName()); // Вариант 3 (самый быстрый): return gcnew String(_employee->GetName()); > void DoWork(array^ tasks) < // marshal_context - это управляемый класс, размещаемый // (в динамической памяти сборщика мусора) с использованием // семантики, напоминающей стек. Его деструктор IDisposable::Dispose() // будет вызван после выхода из области видимости этой функции msclr::interop::marshal_context ctx; const wchar_t **pTasks = new const wchar_t*[tasks->Length]; for (int i = 0; i < tasks->Length; i++) < String ^t = tasks[i]; pTasks[i] = ctx.marshal_as(t); > m_pEmployee->DoWork(pTasks, tasks->Length); // деструктор контекста освободит неуправляемую // память, выделенную методом marshal_as delete[] pTasks; > private: NativeEmployee *_employee; >; >
Взглянув на код, можно увидеть, что конструктор Employee демонстрирует два способа преобразования управляемых строк в неуправляемый: первый основан на выделении памяти с помощью GlobalAlloc, которую необходимо будет освободить явно, а второй временно закрепляет управляемую строку в памяти и возвращает прямой указатель. Второй способ выполняется быстрее, но его можно использовать, только когда неуправляемый код принимает строки, завершающиеся нулевым символом, в кодировке UTF-16, и он не записывает ничего в память по указателю. Кроме того, закрепление управляемых объектов на длительное время может привести к фрагментации памяти, поэтому, если перечисленные требования не удовлетворяются, вам придется прибегнуть к копированию строк.
Метод GetName() класса Employee демонстрирует три способа преобразования неуправляемых строк в управляемые: первый основан на использовании класса System.Runtime.InteropServices.Marshal, второй использует функцию marshal_as, объявленную в заголовочном файле msclr/marshal.h, и, наконец, третий использует конструктор класса System.String, являющийся наиболее быстрым.
Метод DoWork() класса Employee принимает управляемый массив (или управляемые строки) и преобразует его в массив указателей типа wchar_t, указывающих на строки; фактически это массив строк в стиле языка C. Преобразование управляемых строк в неуправляемые выполняется с применением метода marshal_as класса объекта marshal_context. В отличие от глобальной функции marshal_as, объект marshal_context используется для преобразований, требующих освобождения занимаемых при этом ресурсов. Обычно для преобразования управляемых данных в неуправляемые метод marshal_as выделяет неуправляемую память, которую следует освободить после выполнения операции. Объект marshal_context содержит связанный список операций освобождения ресурсов, которые выполняются в момент уничтожения объекта.
Подводя итоги можно сказать, что расширение C++/CLI обеспечивает полный контроль над маршалингом и не требует дублирования объявлений функций, что чревато ошибками, особенно когда часто приходится изменять сигнатуры неуправляемых функций.
Вспомогательная библиотека marshal_as
В этом разделе мы остановимся на вспомогательной библиотеке marshal_as, входящей в состав версии Visual C++ 2008 и выше. marshal_as — это библиотека шаблонов, упрощающая реализацию маршалиига управляемых типов в неуправляемые и обратно. Она способна преобразовывать многие неуправляемые строковые типы, такие как char*, wchar_t*, std::string, std::wstring, CStringT, CStringT, BSTR, bstr_t и CComBSTR, в управляемые типы и обратно. Она способна автоматически выполнять преобразование символов Юникода и ANSI, а также выделять и освобождать память.
Библиотека объявлена и реализована в файлах marshal.h (базовые типы), marshal_windows.h (типы Windows), marshal_cppstd.h (типы данных STL) и marshal_atl.h (типы данных ATL).
Имеется возможность расширять библиотеку marshal_as реализацией преобразований пользовательских типов. Это помогает избежать дублирования кода, когда требуется организовать маршалинг одного и того же типа во многих местах в программе, и дает возможность обеспечить единообразие синтаксиса маршалинга разных типов.
В следующем фрагменте демонстрируется пример расширения библиотеки marshal_as поддержкой преобразования управляемого массива строк в эквивалентный неуправляемый массив строк:
namespace msclr < namespace interop < template<>ref class context_node^> : public context_node_base < private: const wchar_t** _tasks; marshal_context _context; public: context_node(const wchar_t**& toObject, array^ fromObject) < // здесь начинается логика преобразования _tasks = NULL; const wchar_t **pTasks = new const wchar_t*[fromObject->Length]; for (int i = 0; i < fromObject->Length; i++) < String ^t = fromObject[i]; pTasks[i] = _context.marshal_as(t); > toObject = _tasks = pTasks; > ~context_node() < this->!context_node(); > protected: !context_node() < // При удалении контекста будет освобождена память, // выделенная для строк (и принадлежащая marshal_context), // поэтому массив - единственная память, // которую требуется освободить if (_tasks != nullptr) < delete[] _tasks; _tasks = nullptr; >> >; > > // Теперь можно переписать метод Employee::DoWork: void DoWork(array^ tasks) < // Вся неуправляемая память освобождается автоматически, // как только marshal_context выйдет из области видимости msclr::interop::marshal_context ctx; _employee->DoWork(ctx.marshal_as(tasks), tasks->Length); >
Код на языке IL и неуправляемый код
Неуправляемый класс по умолчанию будет скомпилирован расширением C++/CLI в код на языке IL, а не в машинный код. Это может ухудшать производительность в сравнении с оптимизированным машинным кодом, потому что компилятор Visual C++ способен оптимизировать код лучше, чем JIT-компилятор.
Чтобы повлиять на процедуру компиляции можно, добавив объявление #pragma unmanaged или #pragma managed перед требуемым разделом кода. Кроме того, в проектах VC++ имеется возможность включать поддержку C++/CLI для отдельных единиц компиляции (файлов .cpp).
Эффективные приемы взаимодействий
Итак, в этой и предыдущих статьях вы познакомились с небезопасным кодом, особенностями реализации различных механизмов взаимодействий, влиянием на производительность каждой из особенностей и узнали, как можно ослабить это влияние. Вашему вниманию были представлены наиболее эффективные приемы увеличения производительности операций взаимодействий и упрощения их реализации (например, с помощью библиотеки marshal_as и генератора сигнатур для P/Invoke). Давайте подытожим все приведенные ранее советы, относительно небезопасного кода.
Ниже перечислены наиболее эффективные приемы реализации взаимодействий:
- проектируя интерфейсы, старайтесь сводить к минимуму количество переходов через границу между управляемым и неуправляемым кодом, например, объединяя задания;
- уменьшайте количество взаимодействий, совмещая несколько вызовов простых функций в одном вызове;
- реализуйте интерфейс IDisposable, если неуправляемые ресурсы сохраняются между вызовами;
- используйте пулы памяти и выделяйте блоки неуправляемой памяти;
- используйте небезопасный код для интерпретации данных (например, в сетевых протоколах);
- явно именуйте вызываемые функции и используйте ExactSpelling=true;
- используйте параметры двоично совместимых типов, где это возможно;
- избегайте преобразования Юникода в ANSI, когда это возможно;
- вручную преобразуйте строки в/из IntPtr;
- используйте расширение C++/CLI, обеспечивающее лучшие управляемость и производительность при взаимодействиях с кодом на C/C++ и COM-объектами;
- указывайте атрибуты [In] и [Out], чтобы избежать ненужного маршалинга;
- избегайте закрепления долгоживущих объектов;
- используйте метод ReleaseComObject при необходимости;
- используйте атрибут SuppressUnmanagedCodeSecurityAttribute в окружениях, заслуживающих доверия;
- используйте утилиту tlbimp.exe с ключом /unsafe в окружениях, заслуживающих доверия;
- избегайте или старайтесь уменьшать количество вызовов через границы подразделений COM;
- при возможности используйте атрибут AspCompat в приложениях ASP.NET, чтобы уменьшить количество вызовов через границы подразделений COM.
Пошаговое руководство. Компиляция программы C++/CLI, предназначенной для среды CLR в Visual Studio
С помощью C++/CLI можно создавать программы C++, использующие классы .NET, а также собственные типы C++. C++/CLI предназначен для использования в консольных приложениях и в библиотеках DLL, которые упаковывают собственный код C++ и делают его доступными из программ .NET. Чтобы создать пользовательский интерфейс Windows на основе .NET, используйте C# или Visual Basic.
Для этой процедуры можно ввести собственную программу C++ или использовать одну из примеров программ. Пример программы, используемый в этой процедуре, создает текстовый файл textfile.txt и сохраняет его в каталог проекта.
Необходимые компоненты
- Для работы необходимо владеть основами языка C++.
- В Visual Studio 2017 и более поздних версиях поддержка C++/CLI является необязательным компонентом. Чтобы установить его, откройте установщик Visual Studio из Windows меню . Убедитесь, что плитка «Разработка компьютеров с помощью C++ проверка» и в разделе «Необязательные компоненты» также проверка поддержка C++/CLI.
Создание нового проекта
Приведенные ниже инструкции немного отличаются в зависимости от используемой версии Visual Studio. Чтобы ознакомиться с документацией по предпочтительной версии Visual Studio, используйте селектор Версия. Он находится в верхней части оглавления на этой странице.
Создание проекта C++/CLI в Visual Studio
- В Обозреватель решений щелкните правой кнопкой мыши вверху, чтобы открыть диалоговое окно «Создать проект«.
- В верхней части диалогового окна введите CLR в поле поиска и выберите clR Empty Project (платформа .NET Framework) из списка результатов.
- Нажмите кнопку Создать, чтобы создать проект.
Создание проекта C++/CLI в Visual Studio 2017
- Создание проекта В меню Файл укажите Создать, затем нажмите Проект.
- В списке типов проектов Visual C++ щелкните CLR, а затем — Пустой проект CLR.
- Введите имя проекта. По умолчанию содержащее проект решение имеет то же имя, что и новый проект, но можно ввести другое имя. При необходимости можно ввести другое расположение для проекта.
- Нажмите кнопку ОК для создания проекта.
Создание проекта C++/CLI в Visual Studio 2015
- Создание проекта В меню Файл укажите Создать, затем нажмите Проект.
- В списке типов проектов Visual C++ щелкните CLR, а затем — Пустой проект CLR.
- Введите имя проекта. По умолчанию содержащее проект решение имеет то же имя, что и новый проект, но можно ввести другое имя. При необходимости можно ввести другое расположение для проекта.
- Нажмите кнопку ОК для создания проекта.
Добавление исходного файла
- Если обозреватель решений не отображается, в меню Вид выберите пунукт Обозреватель решений.
- Добавьте новый исходный файл в проект:
- Щелкните правой кнопкой мыши папку Исходные файлы в обозревателе решений, наведите указатель мыши на пункт Добавить и щелкните Новый элемент.
- Щелкните элемент Файл C++ (.cpp), введите имя файла и нажмите кнопу Добавить.
Файл с расширением .cpp отображается в папке Исходные файлы в обозревателе решений, а окно с вкладками отображается в месте ввода кода в этом файле.
Примечание. При выборе пустого шаблона проекта CLR автоматически задается параметр компилятора /clr . Чтобы проверить это, щелкните правой кнопкой мыши проект в обозревателе решений и выберите Свойства, а затем установите флажок Поддержка общеязыковой среды выполнения (CLR) в узле Общие окна Свойства конфигурации.
Что такое CLI (c++/CLI)?
Читал, это как то связано с .net. А что это вообще такое, как работает и зачем нужно? И как это отключить (слышал есть такое) в visual studio 2010?
Отслеживать
23.8k 3 3 золотых знака 47 47 серебряных знаков 61 61 бронзовый знак
задан 9 ноя 2012 в 19:11
1,267 2 2 золотых знака 21 21 серебряный знак 56 56 бронзовых знаков
9 ноя 2012 в 19:23
@Котик_хочет_кушать по-буржуйски я не гу-гу
9 ноя 2012 в 19:25
Вообще-то в левой части страницы и на русский ссылка есть: ru.wikipedia.org/wiki/C%2B%2B/CLI
9 ноя 2012 в 19:47
@TAPAHbl4, уважение у вас прямо таки «зашкаливает» =D. Если не уверены, пишите хотя бы в комментариях.
9 ноя 2012 в 20:36
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
CLI в данном случае не командная строка, а Common Language Infrastructure, то есть, говоря языком Пушкина и Достоевского, Общеязыковая Инфраструктура. CLI не что иное, как спецификация, в которой описывается архитектура .NET и связанных с ним проектов (в частности, Mono) C++/CLI не что иное, как управляемый С++, код которого транслируется в CIL ( не путать с CLI), представляющий собой что-то вроде ассемблера для .net
Отслеживать
ответ дан 9 ноя 2012 в 21:44
DreamChild DreamChild
36.2k 3 3 золотых знака 45 45 серебряных знаков 85 85 бронзовых знаков
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.26.3951