Совмещение управляемого и неуправляемого кодов
Программный код, выполняющийся под управлением CLR, называется управляемым кодом.
Программный код, выполняющийся вне среды выполнения CLR, называется неуправляемым кодом.
Примеры неуправляемого программного кода:
- функции Win32 API;
- компоненты COM;
- интерфейсы ActiveX.
.NET появилась не на пустом месте. Вновь разрабатываемый управляемый код вынужден взаимодействовать с существующим неуправляемым программным кодом. Поэтому на платформе .NET предусмотрены различные сценарии установления взаимодействия между управляемым и неуправляемым кодами. Microsoft .NET Framework обеспечивает взаимодействие с компонентами COM, службами COM+, внешними библиотеками типов и многими службами операционной системы.
CLR скрывает имеющиеся в управляемой и неуправляемой моделях различия. Проблемы, связанные с типами данных, механизмами обработки ошибок и т. д. в управляемой и неуправляемой моделях, решаются CLR "незаметно" как для вызывающей стороны (клиента), так и для вызываемой стороны (сервера). Таким образом, организация взаимодействия между управляемым и неуправляемым кодом выглядит проще, чем могло быть...
C++ .NET. Совмещение управляемого и неуправляемого кодов
Реализованные в .NET языки программирования позволяют создавать управляемый код, который может взаимодействовать с неуправляемыми библиотеками Win32 и компонентами на основе модели компонентных объектов Microsoft (COM).
Язык программирования C++ .NET является единственным, который позволяет создавать как управляемый, так и неуправляемый код. Это дает возможность не только использовать неуправляемый библиотечный код, но и смешивать управляемый и неуправляемый коды в одном приложении.
В приводимых ниже примерах кроме языка программирования C# будет использоваться язык C++.
Управляемый код. Осознать разницу
Первый шаг тривиален. Создается C++ Win32 Console Project, то есть Неуправляемое Консольное Приложение на C++. Последняя версия Visual Studio .NET 2005 позволяет в широких пределах смешивать управляемый и неуправляемый коды.
// Транслятору задали опцию /clr. // Эта опция преобразует все объявляемые в программе типы. // От имени объекта элементарного типа (например, int) можно // вызвать методы базового класса object. // Но только вызываются они лишь из фрагментов управляемого кода. // Иначе – сообщение транслятора: // ... managed type or function cannot be used in an unmanaged function #include "stdafx.h" #include <iostream> using namespace std; #using <mscorlib.dll> // Ядро CLR using namespace System; class uClass; // Предварительное неполное объявление класса. class mClass; // Предварительное неполное объявление класса. #pragma managed class mClass { public: uClass *ucP; mClass *mcP; int x; mClass() { // Только в неуправляемом коде! // cout << "Ha-Ha-Ha"; Console::WriteLine("mClass"); // Легко посмотрели значение непроинициализированной переменной. Console::WriteLine(x.ToString()); } ~mClass() { Console::WriteLine("~mClass"); } void mcF0() { Console::WriteLine("mcF0()"); } mClass* mcGenerator(); }; #pragma unmanaged class uClass { public: uClass *ucP; mClass *mcP; int x; uClass() { // Только в управляемом коде! //Console::WriteLine("Ha-Ha-Ha"); printf("uClass\n"); } ~uClass() { printf("~uClass\n"); } void ucF0() { cout << "ucF0()\n"; } uClass* ucGenerator(); }; // Судя по всему, функция Управляемого // класса может быть НеУправляемой! mClass* mClass::mcGenerator() { //x.ToString(); //Console::WriteLine("Ha-Ha-Ha"); cout << "Ha-Ha-Ha from unmanaged function of managed class!" << endl; ucP = new uClass(); ucP->ucF0(); delete ucP; return new mClass(); } #pragma managed // А сделать Управляемой функцию НеУправляемого класса невозможно. // Прагма managed для функции - члена неуправляемого класса игнорируется. uClass* uClass::ucGenerator() { cout << "Ha-Ha-Ha from function of unmanaged class!" << endl; //Console::WriteLine("Ha-Ha-Ha"); //x.ToString(); mcP = new mClass(); mcP->mcF0(); delete mcP; return new uClass(); } #pragma unmanaged int _tmain(int argc, _TCHAR* argv[]) { void *xPoint; int x = 125; // Только не смешивать! //Console::WriteLine("Ha-Ha-Ha"); mClass *mc = new mClass(); mc->mcF0(); xPoint = mc->mcGenerator(); delete (mClass*)xPoint; delete mc; uClass *uc = new uClass(); uc->ucF0(); xPoint = uc->ucGenerator(); delete (uClass*)xPoint; delete uc; return 0; }Листинг 14.1.
Управляемая библиотека
Создание кода управляемой библиотеки тривиально. Для этого в Visual Studio предусмотрены специальные опции. Новый проект создается как библиотека классов (Class Library). Сборка автоматически получает расширение .dll.
C# основывается на парадигме объектно-ориентированного программирования, поэтому библиотека классов представляет собой все то же объявление класса.
Методы – члены класса составляют основу функциональности библиотеки. Наличие пары явно определяемых конструкторов – вынужденная мера. Это требование со стороны модуля на C++, использующего библиотеку. Там невозможно создать объект без явным образом объявленных конструкторов умолчания и копирования:
using System; namespace CSLib00 { public class Class1 { // Явное объявление конструктора без параметров. public Class1() { } // Явное объявление конструктора копирования. // Конструктор с одним параметром – ссылкой на // объект - представитель собственного класса. // Именно такие конструкторы называются конструкторами // копирования. public Class1(Class1 cKey) { } // Реализация функциональности. Метод - член класса Class1 Summ. public int Summ(int key1, int key2) { Console.WriteLine("this is Summ from CSLib00.dll"); return (key1 + key2); } } }