Программирование на Visual C++. Архив рассылки
Шрифт:
CLR расшифровывается как "Common Language Runtime" (межъязыковый рантайм). Чтобы понять, зачем он нужен, необходимо предварительно проанализировать текущее состояние дел в COM и Java– технологиях.
Для начала приведем определение из материала «Microsoft .Net Common Language Runtime Architecture», базовой спецификации, поставляемой Microsoft.
…Common Language Runtime управляет исполнением исходного кода после его компиляции в Microsoft Intermediate Language(MSIL), OptIL или машинные коды.Весь код на MSIL или OptIL исполняется как управляемый код (managed code); этот код исполняется в сотрудничестве с .Net Framework. .Net Framework обеспечивает предоставляет управление памятью, кросс-языковую
Ключевым свойством CLR является возможность обеспечения программной изоляции приложений, исполняемых в общем адресном пространстве. Это осуществляется с помощью типо-безопасного доступа ко всем областям памяти при исполнении типо-безопасного управляемого кода. Некоторые компиляторы могут создавать MSIL-код, который не только типо-безопасен, но и поддается простой проверке на безопасность исполнения. Этот процесс называется верификацией и позволет серверам просто проверять написанные на MSIL пользовательские программы, и запускать только те, которые не будут производить небезопасных обращений к памяти. Такая независимая верификация важна для действительно масштабируемых серверов, исполняющих пользовательские программы и скрипты.
MSIL – это некоторый язык инструкций, похожий на независимый от платформы ассемблер. Внутри CLR-совместимого исполняемого модуля помещается некоторый p-код, состоящий из MSIL-инструкций. Но с помощью утилиты ildasm из p-кода можно получить текстовое представление MSIL Оно выглядит примерно так:
Такой код можно скомпилировать обратно в исполняемый файл с помощью утилиты ilasm. Это позволяет, например, при программировании на языке, не поддерживающем полностью всех возможностей CLR, скомпилироваться во MSIL, дизассемблировать его и добавить недостающие элементы вручную. Такие широкие возможности дизассемблирования очень порадовали бы хакеров, но Microsoft предусмотрел средства, позволяющие предотвратить дизассемблирование готового модуля. К сожалению, в beta 1 это можно сделать только с помощью повторной компиляции дизассемблированного кода из командной строки. В будущем эта опция будет встроена непосредственно в компилятор. К выходу VS.Net Microsoft обещает сделать так, чтобы приложения компилировались непосредственно при инсталляции, или даже при создании инсталляторов для конкретных платформ. Пока же компиляция в машинный код происходит только при загрузке программы.
Одно из преимуществ, дарованных нам COM – динамическая загрузка компонентов. Причем загрузка экземпляров конкретных компонентов
Заметьте, что нигде нет вызовов LoadLibrary или GetProcAddress. Этот код избавлен от подробностей типа физического размещения DLL– библиотеки (мы даже не знаем, в DLL или в EXE хранится код компонента) или явного запроса адреса метода по символическому имени с последующим преобразованием адреса в указатель на функцию. Но этот код неуклюж и велик по сравнению с кодом создания экземпляра C++-класса и его приведения к базовому классу:
В чем же разница между этими листингами? В первом из них на языке программирования C++ был динамически создан экземпляр компонента, возможно, созданного на другом языке и располагающегося в отдельном исполняемом модуле, а во втором был создан экземпляр класса, определенного в той же программе (а значит, написанного на том же языке, располагающегося в том же модуле…). В остальном же эти листинги идентичны.
Ключ к пониманию недостатков COM спрятан именно в первом листинге. Этот код иллюстрирует напряженность между системой типов COM и системой типов языка реализации (в данном случае, C++). Заметьте, что везде, где объектная ссылка возвращается вызывающей стороне, ее должен сопровождать GUID (в этом примере IID_IAntique или IID_ICar). Это потому, что идентификатор типа языка реализации (std::type_info в случае C++) несовместим с форматом идентификатора типа COM.
За долгие годы группа C++ в Microsoft представила несколько технологий, позволяющих сгладить разницу между системами типов C++ и COM, самой важной (хотя и хитрой) из которых были расширения языка: __uuidof и declspec(uuid). Эти расширения позволили ассоциировать GUID (или, как его еще называют, UUID) с некоторым пользовательским типом. Компилятор MIDL при обработке IDL-файлов автоматически ассоциирует идентификатор типа (GUID) COM с символическим именем C++-типа. При использовании uuidof код становится более типобезопасным: