На этом шаге мы рассмотрим особенности определения класса компонента.
Начиная с этого шага мы изучим исходный текст, сгенерированный мастерами ATL для Вашего СОМ-объекта, который включает объявление класса, тело класса, функции глобальной точки входа, сценарий регистрации в реестре и IDL-файл. После знакомства с ATL мы рассмотрим альтернативные способы разработки СОМ-объектов.
Определение класса Вашего компонента находится в файле Encoder.h. Это стандартное определение класса C++, использующее множественное наследование.
class ATL_NO_VTABLE CEncoder : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CEncoder, &CLSID_Encoder>, public IEncoder { public: CEncoder() { m_Key = 1; } DECLARE_REGISTRY_RESOURCEID(IDR_ENCODER) DECLARE_NOT_AGGREGATABLE(CEncoder) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CEncoder) COM_INTERFACE_ENTRY(IEncoder) END_COM_MAP() // IEncoder public: STDMETHOD(get_Key)(/*[out, retval]*/ short *pVal); STDMETHOD(put_Key)(/*[in]*/ short newVal); STDMETHOD(EncodeString)(/*[in]*/ const BSTR instring, /*[out, retval]*/ BSTR * outstring); protected: short m_Key; };
Класс наследует от трех базовых классов: CComObjectRootEx, CComCoClass и IEncoder. Первые два - шаблонные базовые классы ATL, а последний - интерфейс, объявленный в файле EncodeServer.h как абстрактный базовый класс. Определяемые методы интерфейса помещаются в класс IEncoder в качестве виртуальных функций. Предоставляемые нами версии этих функций в производных классах реализуют конкретные услуги СОМ-сервера. В открытом разделе в конце определения класса находится тело EncodeString().
Класс CComObjectRootEx содержит реализацию по умолчанию методов QueryInterface(), AddRef() и Release() интерфейса IUnknown. Создавая производный класс, мы позволяем клиенту обращаться к QueryInterface() для получения указателя на любой из интерфейсов, поддерживаемых Вашим СОМ-объектом. Методы AddRef() и Release() ведут учет обращений к СОМ-объекту, чтобы держать его в памяти, только пока он нужен клиентам.
Класс, производный от CComCoClass, получает реализацию по умолчанию фабрики классов, которая создает экземпляр СОМ-сервера. В качестве аргументов мы передаем в этот шаблонный базовый класс имя класса сервера (CEncoder) и ссылку на его GUID (CLSIDEncoder). Для генерации всех идентификаторов GUID ATL-мастера используют утилиту UUIDGEN.EXE.
Другой важный элемент объявления класса - СОМ-карта. Она содержит список интерфейсов, поддерживаемых СОM-объектом. Добавление записей в СОМ-карту происходит с помощью макроса COM_INTERFACE_ENTRY. Внутренние механизмы каркаса поддерживают соответствующий массив структур ATL_INTMAP_ENTRY, которые связывают GUID интерфейсов и функции, возвращающие указатели на интерфейс. СОМ-карта используется методом по умолчанию QueryInterface(), унаследованным от шаблонного базового класса CComObjectRootEx. Всякий раз, когда клиентское приложение вызывает QueryInterface(), реализация по умолчанию просматривает эту карту в поисках соответствующего GUID интерфейса. Найдя подходящую ссылку, функция возвращает указатель на интерфейс.
На следующем шаге мы рассмотрим реализацию методов компонента.