pSay->SetWord (L"The client now uses smart pointers!");
pSay->Say();
pSay = 0;
CoUninitialize();
}
Несмотря на то, что здесь нет многих строк кода, присутствовавших в предыдущей версии клиента, новая версия тоже должна работать. Попробуем разобраться в том, как это происходит.
¨ Во-первых, здесь использована директива #import, которая читает информацию из библиотеки типов MyComTLib.tlb и на ее основании генерирует некий код С++ (исходный код!). Этот код участвует в процессе компиляции и сборки выполняемого кода клиента. Новый код является эквивалентом библиотеки типов и содержит описания интерфейсов, импортированных из TLB-файла.
¨ Во-вторых, мы создаем и используем так называемый smart pointer ("умный" указатель pSay), на интересующий нас интерфейс. Он берет на себя основную работу по обслуживанию интерфейса.
Директивой #import можно пользоваться для генерации кода не только на основе TLB-файлов, но также и на основе других двоичных файлов, например EXE-, DLL- или OCX-файлов. Важно, чтобы в этих файлах была информация о типах, используемых COM-объектом.
Вы можете увидеть результат воздействия директивы #import на плоды работы компилятора С++ в папке Debug. Там появились два новых файла заголовков: MyCoTLib.tlh (type library header) и MyComTLib.tli (type library implementations). Первый файл подключает код второго (именно в таком порядке) и они оба компилируются так, как если бы были подключены директивой #include.
Этот процесс конвертации двоичной библиотеки типов в исходный код С++ дает возможность решить довольно сложную задачу обнаружения ошибок при пользовании данными о COM-объекте. Ошибки, присутствующие в двоичном коде, трудно диагностировать, а ошибки в исходном коде выявляет и указывает компилятор. В данный момент важно не потерять из виду цепь преобразований:
¨ Какая-то часть исходного текста COM-сервера (IDL-файла) была сначала преобразована в двоичный код библиотеки типов (TLB-файл);
¨ Затем на стороне клиента с помощью этого двоичного кода компилятор С++ сгенерировал рассматриваемый сейчас исходный код С++ (TLH- и TLI-файлы);
¨ После этого компилятор вновь превращает исходный код в двоичный, сплавляя его с двоичным кодом клиентского приложения.
Таким образом, при каждой компиляции клиентского приложения обновляются как exe-файл, так и tlh, tli-файлы. Немного позже мы рассмотрим содержимое этих файлов, а сейчас обратите внимание на то, что директива #import сопровождается двумя атрибутами: no_namespace и named_guids, которые помогают компилятору создавать файлы заголовков.
Чтобы избежать случайного совпадения имен, иногда содержимое библиотеки типов определяется в отдельном пространстве имен (namespace), Пространство имен определяется в контексте оператора library, который вы видели в IDL-файле. Но в нашем случае пространство имен не было указано и поэтому в директиве #import задан атрибут no_namespace. Второй атрибут (named_guids) указывает компилятору, что надо определить и инициализировать переменные типа GUID в определенном (старом) стиле: LIBID_MyCom, CLSID_CoSay и IID_ISay. Новый стиль задания идентификаторов состоит в использовании операции __uuidof(expression).
Microsoft-расширение языка С++ определяет ключевое слово __uuidof и связанную с ним операцию. Она позволяет добыть GUID объекта, стоящего в скобках. Для ее успешной работы необходимо прикрепить GUID к структуре или классу. Это действие выполняют строки вида:
struct __declspec(uuid("9b865820-2ffa-11d5-98b4-00e0293f01b2"))
/* LIBID */ __MyCom;
которые также используют Microsoft-расширение языка С++ (declspec). Рассматриваемые новшества вы в изобилии увидите, если откроете файл MyCoTLib.tlh.
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
// Forward references and typedefs
struct __declspec(uuid("0934da90-608d-4107-9ecc-c7e828ad0928"))
/* LIBID */ __MyCom;
struct /* coclass */ CoSay;
struct __declspec(uuid("170368d0-85be-43af-ae71-053f506657a2"))
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.