Фабрика классов Логика функционирования
!gLockCount && IgObjCount ? S_OK : S_FALSE;
}
В конструктор класса coSay добавьте код, увеличивающий счетчик числа пользователей объектом Со Say:
gObjCount++;
а в деструктор — уменьшающий:
gObjCount--;
Важным шагом, о котором, тем не менее, легко забыть, является своевременная коррекция файла MyCom.def. Вставьте в конец этого файла строку
DllCanUnloadNow PRIVATE
которая добавляет в список экспортируемых функций еще один элемент. В файл MyCom. h добавьте декларацию нового класса CoSayFactory, реализующего интерфейс iclassFactory. Отметьте, что он произведен от интерфейса iClassFactory, который, как и положено, имеет родителя I unknown. Вы помните, что на плечи класса ложится бремя реализации всех методов своих предков. По той же причине мы вновь заводим счетчик числа пользователей классом (m_ref):
//====== Фабрика классов СОМ DLL-сервера
class CoSayFactory : public IClassFactory
{
public:
CoSayFactory() ;
virtual ~CoSayFactory() ;
// lUnknown
HRESULT _stdcall Querylnterface(REFIID riid,
void** ppv);
UbONG _stdcall AddRefO; ULONG _stdcall Release();
// IClassFactory
HRESULT _stdcall Createlnstance(LPUNKNOWN pUnk,
REFIID riid, void** ppv);
HRESULT _stdcall LockServer(BOOL bLock); private:
ULONG m_ref; };
Реализацию тел заявленных методов вставьте в файл МуСоm.срр. Здесь мы вынуждены повторяться,
вновь прокручивая логику управления временем жизни объектов СОМ:
//========== Фабрика классов
CoSayFactory::CoSayFactory()
{
m_ref = 0; gObjCount++;
}
CoSayFactory::-CoSayFactory()
{
gObjCount--;
}
//====== Методы lUnknown
HRESULT _stdcall CoSayFactory
::QueryInterface(REFIID riid, void** ppv)
{
*ppv = 0;
//=== На сей раз обойдемся без шаблона static_cast<>
if (riid == IID_IUnknown)
*ppv = (lUnknown*)this;
else if (riid == IID_IClassFactory)
*ppv = (IClassFactory*)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
ULONG _stdcall CoSayFactory:rAddRef()
{
return ++m_ref;
}
ULONG _stdcall CoSayFactory::Release()
{
if (--m_ref==0)
delete this;
return m_ref;
//====== Методы интерфейса IClassFactory
HRESULT _ stdcall CoSayFactory: :CreateInstance
(LPUNKNOWN pUnk, REFIID riid, void** ppv)
{
// Этот параметр управляет аггрегированием
// объектов СОМ, которое мы не поддерживаем
if (pUnk)
return CLASS_E_NOAGGREGATION;
//== Создание нового объекта и запрос его интерфейса
CoSay *pSay = new CoSay;
HRESULT hr = pSay->Query!nterface (riid, ppv) ;
if (FAILED (hr))
delete pSay; return hr;
//=== Управление счетчиком фиксаций сервера в памяти
HRESULT _stdcall CoSayFactory::LockServer(BOOL bLock)
{
if (bLock) // Если TRUE, то увеличиваем счетчик
++gLockCount;
else // Иначе — уменьшаем
--gLockCount;
return S_OK;
}
Мы должны также изменить алгоритм функции DllGetciassOb j ect, которая теперь создает объект фабрики классов и запрашивает один из двух возможных интерфейсов (lUnknown,
IClassFactory):
STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
if (rclsid != CLSID_CoSay)
return CLASS_E_CLASSNOTAVAILABLE;
CoSayFactory *pCF = new CoSayFactory;
HRESULT hr = pCF->Query!nterface(riid, ppv);
if (FAILED(hr))
delete pCF;
return hr;
}
На этом модификация сервера завершается. Дайте команду Build > Rebuild и устраните ошибки, если они имеются. Затем вновь откройте проект клиентского приложения SayClient и внесите изменения в функцию main, которая теперь должна работать с объектами СОМ более изощренным способом. Она должна сначала загрузить СОМ-сервер и запросить адрес его фабрики классов, затем создать с ее помощью объект CoSay, попросив у него адрес интерфейса isay, и лишь после этого можно начать управление объектом. Последовательность освобождения объектов тоже должна быть тщательно выверена. Ниже приведена новая версия файла SayClient.cpp:
#include "interfaces.h"
void main()
{
(reinitialize (0) ;
IClassFactory *pCF;
// Мы зарегистрировали только один класс CoSay,
// поэтому ищем DLL с его помощью, но при этом
// создается не объект CoSay, а объект CoSayFactory
// (см. код функции DllGetClassObject).
// Поэтому здесь мы просим дать адрес
// интерфейса IClassFactory
HRESULT hr = CoGetClassObject(CLSID_CoSay, CLSCTX_INPROC_SERVER,0, IID_IClassFactory,(void**)&pCF);
if (FAILED(hr))
{
MessageBox(0,"Could not Get Class Factory !
", "CoGetClassObject", MB_OK);
CoUninitialize();
return;
}
// Далее мы с помощью фабрики классов
// создаем объект CoSay и просим его
// дать нам адрес интерфеса ISay
ISay *pSay;
hr = pCF->Create!nstance(0,IID_ISay, (void**)&pSay) ;
if (FAILED(hr))
{
MessageBox(0,"Could not create CoSay and get ISay!
", "Createlnstance", MB_OK);
CoUninitialize ();
return;
}
// Уменьшаем счетчик числа пользователей
// фабрикой классов pCF->Release();
//====== Управляем объектом
pSay->Say();
BSTR word = SysAllocString(L"Yes, My Lord");
pSay->SetWord(word);
SysFreeString(word); pSay->Say();
//====== Уменьшаем число его пользователей
pSay->Release();
SCoUninitialize () ;
}
Запустите приложение (Ctrl+F5) и проверьте его работу. Алгоритм проверки остается тем же, что и ранее, но здесь мы должны по логике разработчиков СОМ, радоваться тому, что выполняем большее число правил и стандартов, а также имеем возможность одновременно создавать несколько СОМ-объектов.