Совмещение управляемого и неуправляемого кодов
Программный код, выполняющийся под управлением 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);
}
}
}