Так как у интерфейса ISay, в свою очередь, имеется родитель (IUnknown), то класс должен также дать реальные тела всем трем его методам. Реализуя интерфейс IUnknown, обычный объект C++ превращается в COM-сервер. Интерфейс IUnknown определен в системе как простой абстрактный класс, в котором присутствуют 3 метода: QueryInterface, AddRef и Release. Он используется для двух целей:
¨ Управление жизненным циклом объекта в памяти.
¨ Доступ к интерфейсам.
Для управления жизненным циклом в памяти COM-серверы используют метод подсчета ссылок (reference counting). Сервер отслеживает количество клиентов, которые к нему обращаются, путем увеличения значения счетчика ссылок на единицу всякий раз, когда выдает указатель на один из своих интерфейсов.
Каждый COM-сервер содержит собственный счетчик ссылок, для чего используется закрытая переменная (нам надо ввести ее в ко-класс). До тех пор пока счетчик ссылок больше нуля, сервер должен оставаться в памяти. Когда же значение счетчика становится равным нулю, сервер может быть выгружен из памяти. COM-сервер увеличивает значение счетчика, вызывая собственный метод AddRef.
Метод Release дополняет AddRef. Клиенты вызывают этот метод для того, чтобы уменьшить счетчик ссылок на единицу. Когда клиент перестает нуждаться в функциях интерфейса, он дает знать об этом серверу, вызывая метод IUnknow::Release.
При помощи QueryInterface клиенты получают указатели на другие интерфейсы COM-сервера. COM не определяет способ динамического доступа клиентов к интерфейсам сервера. Поэтому клиент должен заранее знать имена интерфейсов, доступ к которым он должен получить.
Если вы хотите, чтобы класс реализовывал несколько интерфейсов, то вы должны использовать множественное наследование. Такой подход проповедует ATL (Active Template Library). MFC реализует другой подход к реализации интерфейсов. Он использует вложенные классы. Каждому интерфейсу соответствует новый класс, вложенный в один общий класс COM-объекта.
Абстрактный класс (каковым является наш интерфейс ISay), всегда является базовым классом, который наследуется конкретным классом реализации. Класс реализации может быть:
¨ Классом самого COM-сервера.
¨ Самостоятельным классом, который просто используется COM-сервером.
Для того, чтобы быть доступным тем приложениям, которые захотят воспользоваться услугами COM-объекта, ко-класс тоже должен иметь дом (в виде inproc-сервера DLL). Сейчас, разрабатывая проект типа Win32 DLL, мы строим именно этот дом. С помощью механизма DLL класс будет доступен приложению-клиенту. DLL загружается в адресное пространство клиентского процесса и это делается только при необходимости.
Каждому создаваемому COM-серверу необходимо присвоить GUID (Globally Unique ID – полностью индивидуальный идентификатор). GUID представляет собой 128-битовое уникальное число. Библиотеки OLE используют эти числа, чтобы идентифицировать, получать доступ и обращаться к серверу. GUID COM-сервера называется идентификатором класса (CLSID – class ID). CLSID идентифицирует отдельную реализацию COM-сервера в OLE, то есть это уникальное имя сервера.
Нам неоднократно понадобятся услуги инструмента студии под именем GuidGen. Утилита GuidGen (так же как и UuidGen) умеет генерировать уникальные 128-битовые идентификаторы, но она, в отличие от UuidGen, использует удобный Windows-интерфейс. Идентификаторы типа GUID понадобятся нам для регистрации класса CoSay, а впоследствии и самого сервера (то есть COM-DLL).
Целесообразно проверить есть ли команда запуска утилиты в меню Tools студии. Откройте меню и посмотрите, есть ли в нем команда Create GUID. Если нет, то выполните следующие действия:
1. Дайте команду Tools4External Tools и в окне диалога External Tools нажмите кнопку Add;
2. Введите имя новой команды меню Create GUID, переведите фокус в поле Command и нажмите кнопку справа от нее;
3. С помощью диалога поиска файла, найдите файл Guidgen.exe, который находится в папке ..\Microsoft Visual Studio.NET\Common7\Tools, и нажмите кнопку Open;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.