Модель программирования Component Object Model. Разработка COM-сервера, страница 4

4.  Переведите фокус в поле Initial Directory и с помощью кнопки раскрытия выпадающего списка выберите элемент Item Directory и нажмите OK

С помощью команды Create GUID меню Tools вызовите генератор уникальных идентификаторов. Выберите формат DEFINE_GUID, нажмите кнопку Copy, а затем Exit.

В окне редактора студии (с файлом guids.h) поместите фокус перед строкой interface ISay и нажмите Ctrl+V. При этом из системного буфера в файл будут помещены три строки кода, которые с точностью до цифр (у вас они будут другими) имеют такой вид:

// {170368D0-85BE-43af-AE71-053F506657A2}

DEFINE_GUID(<<name>>,

0x170368d0, 0x85be, 0x43af, 0xae, 0x71, 0x5, 0x3f, 0x50,

0x66, 0x57, 0xa2);

Замените аргумент <<name>> (вместе с угловыми скобками) на IID_ISay. Повторите всю процедуру и создайте идентификатор для ко-класса CoSay, который вставьте сразу за идентификатором интерфейса ISay. На сей раз замените аргумент <<name>> на CLSID_CoSay, как показано ниже:

// {9B865820-2FFA-11d5-98B4-00E0293F01B2}

DEFINE_GUID(CLSID_CoSay,

0x9b865820, 0x2ffa, 0x11d5, 0x98, 0xb4, 0x0, 0xe0, 0x29,

0x3f, 0x1, 0xb2);

Сохраните и закройте файл guids.h, так как мы больше не будем вносить в него изменений. Если вы хотите знать, что делает макроподстановка DEFINE_GUID, то за ней стоит такое определение:

#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \

EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }

Этот макрос создает структуру типа GUID с именем name, которая служит для хранения уникальных идентификаторов COM-объектов, интерфейсов, библиотек типов и других "бирочных" реалий причудливого мира COM.

Создание класса для COM-объекта

Интерфейс определен, теперь надо создать ко-класс, который реализует (implements) его методы и предоставит (expose) его миру. Подключите к проекту новый файл MyCom.h, в который надо поместить объявление класса CoSay. Как вы помните, он должен быть потомком экспортируемого интерфейса ISay и дать тела всем методам, унаследованным от всех своих абстрактных предков (ISay, IUnknown). Введите в файл следующие коды:

#pragma once

class CoSay : public ISay  // Класс, реализующий интерфейсы ISay, IUnknown

{

private:

ULONG m_ref; // Счетчик числа пользователей классом

BSTR m_word; // Текст, выводимый в окно

public:

CoSay();

virtual ~CoSay();

// Реализация обещаний деда - IUnknown

HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);

ULONG __stdcall AddRef();

ULONG __stdcall Release();

// Реализация обещаний родителя - ISay

HRESULT __stdcall Say();

HRESULT __stdcall SetWord (BSTR word);

};

Для реализации тел методов класса CoSay подключите к проекту новый файл MyCom.cpp, в который введите коды, приведенные ниже. Обратите внимание на то, как принято работать со строками текста типа BSTR.

#include "guids.h"

#include "MyCom.h"

CoSay::CoSay()

{

m_ref = 0;        // Обнуляем счетчик числа пользователей класса (интерфейс пока не используется)

// Динамически создаем строку текста (по умолчанию)

m_word = SysAllocString (L"Hi, there. This is MyCom speaking");

}

CoSay::~CoSay()

{

if (m_word)   // При завершении работы освобождаем память

SysFreeString (m_word);

}

//==== Реализация методов IUnknown

HRESULT __stdcall CoSay::QueryInterface(REFIID riid, void** ppv)

{

*ppv = 0; // Стандартная логика работы с клиентом. Поддерживаем только два интерфейса

if (riid == IID_IUnknown)

*ppv = static_cast<IUnknown*>(this);

else if (riid==IID_ISay)

*ppv = static_cast<ISay*>(this);

else

return E_NOINTERFACE;

AddRef();   // Есть пользователи нашим объектом

return S_OK;

}

ULONG __stdcall CoSay::AddRef() { return ++m_ref; }

ULONG __stdcall CoSay::Release()

{

if (--m_ref==0)

delete this;

return m_ref;

}

HRESULT __stdcall CoSay::Say() // Реализация методов ISay

{

char buff [128];       // Преобразование типов (из BSTR в char*) необходимо для MessageBox

WideCharToMultiByte (CP_ACP, 0, m_word, -1, buff, MAX_LENGTH, 0, 0);