![]() |
![]() |
![]() |
Создание
класса СОМ-объекта
Подключите
к проекту новый файл MyCom.h, в который надо поместить объявление класса CoSay.
Как вы помните, он должен быть потомком экспортируемого интерфейса iSay и дать
тела всем методам, унаследованным от всех своих абстрактных предков (isay, lUnknown).
Введите в файл следующие коды:
# if !defined (MY_COSAY_HEADER)
#define
MY_COSAY_HEADER
#pragma
once
class
CoSay
: public
ISay
{
//=====Класс,
реализующий интерфейсы ISay, lUnknown
public:
CoSay
() ;
virtual
-CoSay();
//
lUnknown
HRESULT
_
stdcall
Querylnterface(REFIID riid,
void**
ppv);
ULONG
_
stdcall
AddRefO;
ULONG
_
stdcall
Release ();
//
ISay
HRESULT
_
stdcall
Say();
HRESULT
_
stdcall
SetWord (BSTR word);
private:
//======
Счетчик числа пользователей классом
ULONG
m_ref; , //====== Текст, выводимый в окно
BSTR m word;
};
#
endif
Для реализации
тел методов класса CoSay подключите к проекту новый файл МуСоm. срр, в который
введите коды, приведенные ниже. Обратите внимание на то, как принято работать
со строками текста типа BSTR:
#include
"interfaces.h"
#include
"MyCom.h"
//======
Произвольный ограничитель длины строк
#define
MAX_LENGTH 128
CoSay::CoSay()
{
//===
Обнуляем счетчик числа пользователей класса,
//===
так как интерфейс пока не используется
m_ref
= 0;
//===
Динамически создаем строку текста по умолчанию
m_word
= SysAllocString (L"Hi, there."
"This
is MyCom speaking");
}
CoSay::-CoSay()
{
//===
При завершении работы освобождаем память
if
(m_word)
SysFreeString(m_word);
}
//======
Реализация методов lUnknown
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_re f;
}
//======
Реализация методов ISay
HRESULT _ stdcall CoSay::Say()
{
//===
Преобразование типов (из BSTR в char*), которое
//===
необходимо для использования MessageBox
char
buff[MAX_LENGTH];
WideCharToMultiByte(CP_ACP,
0, m_word,
-1,
buff, MAX_LENGTH, 0, 0);
MessageBox
(0, buff, "Interface ISay:", MB_OK);
return S_OK;
}
HRESULT _ stdcall CoSay::SetWord(BSTR word)
{
//======
Повторное выделение памяти
SysReAllocString
(&m_word, word);
freturn
S_OK;
}
Класс, поддерживающий
интерфейс, готов. Теперь следует сделать доступным для пользователей СОМ-объекта
весь DLL-сервер, где живет ко-класс CoSay. Минимальным набором функций, которые
должна экспортировать COM DLL, является реализация только одной функции DllGetClassObject.
Обычно ее сопровождают еще три функции, но в данный момент мы рассматриваем
лишь минимальный набор. DLL должна создать СОМ-объект и позволить работать с
ним, получив, то есть записав по адресу ppv, адрес зарегистрированного интерфейса.
Вы, конечно, заметили, что в предложении дважды использовано слово адрес. Именно
поэтому параметр ppv имеет тип void** . Введите эту функцию в конец файла МуСот.срр:
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
{
//=== Если идентификатор класса задан неправильно,
if
(rclsid != CLSID_CoSay)
// возвращаем код ошибки с указанием причины неудачи
return
CLASS_E_CLASSNOTAVAILABLE;
//======
Создаем объект ко-класса
CoSay
*pSay = new CoSay;
//=== Пытаемся получить адрес запрошенного интерфейса
HRESULT
hr = pSay->Query!nterface (riid, ppv) ;
if
(FAILED(hr))
delete pSay;
return
hr;
}
Макроподстановка
STDAPI при разворачивании превратится в
extern
"С" HRESULT
stdcall
Примечание
Работа по опознаванию объектов идет с идентификаторами класса (rclsid) и интерфейса (riid). Это является, как считают апологеты СОМ, одной из самых важных черт, которые вносят небывалый уровень надежности в функционирование СОМ-приложений. Весьма спорное утверждение, так как центром всей вселенной как разработчика, так и пользователя становится Windows-реестр, который открыт всем ветрам — как случайным, так и преднамеренным воздействиям со стороны человека и программы. Однако следует согласиться с тем, что уникальная идентификация снимает проблему случайного, но весьма вероятного совпадения имен интерфейсов, разработанных в разных частях света. То же относится и к именам классов, библиотек типов и т. д.
![]() |
![]() |
![]() |