Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_II.pdf
Скачиваний:
41
Добавлен:
05.06.2014
Размер:
3.02 Mб
Скачать

221

MENUITEM "&Create",

IDM_CREATE

MENUITEM "&Destroy",

IDM_DESTROY

MENUITEM SEPARATOR

 

MENUITEM "QueryInterface IID_IUnknown", IDM_IUNKNOWN

MENUITEM "QueryInterface IID_IMalloc",

IDM_IMALLOC

MENUITEM "QueryInterface IID_IMarshal", IDM_IMARSHAL

}

POPUP "&Memory"

{

MENUITEM "&Allocate(IMalloc)", IDM_ALLOCATE_CUSTOM

MENUITEM "&Allocate(malloc)", IDM_ALLOCATE_DEFAULT

MENUITEM "&Free", IDM_FREE

}

}

Рис. 20.4 Программа CALLER

Программа CALLER непосредственно не использует библиотеки OLE и, следовательно, как и представленная ранее библиотека IMALLOC.DLL, программа CALLER не инициализирует библиотеки OLE. (Это изменится после модернизации программы CALLER в программу CALLPUB, представленную далее в этой главе; так же как и наследник библиотеки IMALLOC — библиотека PUBMEM, тоже вынуждена иметь дело с библиотеками OLE и, следовательно, иметь соответствующие функции инициализации и удаления.)

Весь доступ к услугам интерфейса IMalloc в программе CALLER происходит посредством выбора пунктов меню, что обеспечивает полный контроль над тем, что вызывается и тем, когда это вызывается. Первое, что необходимо сделать при запуске программы CALLER — это создать компонент для выделения памяти, что достигается посредством выбора опции Create из меню Allocator. Это приводит к вызову функции CreateAllocator библиотеки IMALLOC, возвращаемым значением которой является указатель на интерфейс, требуемый для доступа к интерфейсу процедуры выделения памяти библиотеки IMALLOC.

При выборе опции Destroy из меню Allocator, компонент для выделения памяти удаляется благодаря уменьшению значения счетчика ссылок при вызове функции Release:

pMalloc -> lpVtbl -> Release(pMalloc); pMalloc = NULL;

Устанавливать значение только что освобожденного указателя на интерфейс в NULL очень полезно. Это гарантирует, что его невозможно будет снова использовать без генерации исключения (что означает программную ошибку, от которой вы, будем надеяться, избавитесь до того, как начнете распространять вашу программу).

Программа CALLER вызывает функцию-член QueryInterface из процедуры выделения памяти для проверки поддерживаемых интерфейсов. С позиции клиента, важно всегда вызывать функцию Release, когда вызов функции QueryInterface возвращает указатель на интерфейс. В противном случае, вы рискуете оставить компонент в оперативной памяти со счетчиком ссылок большим нуля, хотя клиент считает, что он освободил ресурсы.

Теперь обратимся к тому, что представляет собой создание сервера открытого компонента.

Сервер открытого компонента

Библиотека PUBMEM.DLL демонстрирует создание сервера открытого компонента OLE. Отличие между открытым и закрытым компонентами заключается не в самом интерфейсе; фактически открытый интерфейс IMalloc, поставляемый библиотекой PUBMEM идентичен (за небольшим исключением) закрытому интерфейсу, поставляемому в представленном ранее образце библиотеки IMALLOC. Открытый компонент OLE — это компонент, созданный из класса открытого компонента OLE.

Класс открытого компонента OLE требует координации нескольких элементов. Класс компонента имеет уникальный идентификатор класса (CLSID) и элемент реестра (registry), который связывает идентификатор класса с инсталлированными файлами с расширением .EXE и .DLL. Сам компонент должен обеспечивать стандартный механизм для создания компонента по запросу, который называется фабрикой классов (class factory). Фабрика классов является закрытым компонентом OLE, созданным посредством вызова экспортируемой функции DllGetClassObject сервера DLL, которая обеспечивает услуги интерфейса IClassFactory. Библиотеки OLE периодически вызывают вторую точку входа — функцию DllCanUnloadNow, для проверки того, безопасно ли для состояния DLL удалить компонент. Будучи более сложной, чем закрытый компонент, фабрика классов обеспечивает базовый механизм для выдачи многих типов классов компонентов, каждый из которых предусматривает несколько разных интерфейсов. На рис. 20.5 представлены файлы с исходным текстом библиотеки PUBMEM.

PUBMEM.MAK

222

#----------------------

# PUBMEM.MAK make file

#----------------------

pubmem.dll : pubmem.obj classfac.obj compobj.obj

$(LINKER) /EXPORT:DllGetClassObject /EXPORT:DllCanUnloadNow \ $(DLLFLAGS) -OUT:pubmem.dll pubmem.obj \

classfac.obj compobj.obj $(GUILIBS) uuid.lib ole32.lib

pubmem.obj : pubmem.cpp pubmem.h $(CC) $(CFLAGS) pubmem.cpp

classfac.obj : classfac.cpp pubmem.h $(CC) $(CFLAGS) classfac.cpp

compobj.obj : compobj.cpp pubmem.h $(CC) $(CFLAGS) compobj.cpp

PUBMEM.CPP

/*-------------------------------------------------

 

 

PUBMEM.CPP --

Define a public imalloc component

 

(c) Paul Yao, 1996

-------------------------------------------------

 

*/

#include <windows.h>

 

#include "pubmem.h"

 

extern int cObject;

 

//-------------------------------------------------------------------

 

 

// CreateAllocator --

Exported function to create allocator

//-------------------------------------------------------------------

 

 

EXPORT LPMALLOC CreateAllocator()

{

DAlloc *pAllocator = NULL;

pAllocator = new DAlloc();

if(pAllocator != NULL && pAllocator->Initialize())

{

pAllocator->AddRef();

}

else

{

delete pAllocator;

}

return(LPMALLOC) pAllocator;

}

//-------------------------------------------------------------------

DAlloc::DAlloc()

{

RefCount = 0;

hHeap = NULL;

}

//-------------------------------------------------------------------

DAlloc::~DAlloc()

{

if(hHeap)

HeapDestroy(hHeap);

}

//-------------------------------------------------------------------

BOOL DAlloc::Initialize()

{

hHeap = HeapCreate(0, 4096, 65535); return(BOOL) hHeap;

223

}

//-------------------------------------------------------------------

STDMETHODIMP

DAlloc::QueryInterface(REFIID riid, LPVOID FAR *ppvObject)

{

//Always initialize "out" parameters to NULL *ppvObject = NULL;

//Everyone supports IUnknown

if(riid == IID_IUnknown) *ppvObject =(LPUNKNOWN) this;

// We support IMalloc if(riid == IID_IMalloc)

*ppvObject =(LPMALLOC) this;

if(*ppvObject == NULL)

{

// Interface not supported return E_NOINTERFACE;

}

else

{

// Interface supported, so increment reference count ((LPUNKNOWN) *ppvObject)->AddRef();

return S_OK;

}

}

//-------------------------------------------------------------------

STDMETHODIMP_(ULONG)

DAlloc::AddRef(void)

{

return ++RefCount;

}

//-------------------------------------------------------------------

STDMETHODIMP_(ULONG)

DAlloc::Release(void)

{

if(0L != --RefCount) return RefCount;

--cObject; delete this;

return 0L;

}

//-------------------------------------------------------------------

STDMETHODIMP_(void *)

DAlloc::Alloc(ULONG cb)

{

return HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cb);

}

//-------------------------------------------------------------------

STDMETHODIMP_(void *)

DAlloc::Realloc(void *pv, ULONG cb)

{

return HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pv, cb);

}

//-------------------------------------------------------------------

STDMETHODIMP_(void)

224

DAlloc::Free(void *pv)

{

HeapFree(hHeap, 0, pv);

}

//-------------------------------------------------------------------

STDMETHODIMP_(ULONG)

DAlloc::GetSize(void *pv)

{

return HeapSize(hHeap, 0, pv);

}

//-------------------------------------------------------------------

STDMETHODIMP_(int)

DAlloc::DidAlloc(void *pv)

{

PROCESS_HEAP_ENTRY phe;

ZeroMemory(&phe, sizeof(PROCESS_HEAP_ENTRY));

while(HeapWalk(hHeap, &phe))

{

if(phe.lpData == pv) return 1;

}

return 0;

}

//-------------------------------------------------------------------

STDMETHODIMP_(void)

DAlloc::HeapMinimize(void)

{

HeapCompact(hHeap, 0);

}

CLASSFAC.CPP

/*---------------------------------------------

 

CLASSFAC.CPP --

OLE Class Factory component

 

(c) Paul Yao, 1996

---------------------------------------------

*/

#include <windows.h> #include <initguid.h> #include "pubmem.h"

extern int cObject; extern int cLockCount;

//-------------------------------------------------------------------

DClassFactory::DClassFactory()

{

RefCount = 0;

}

//-------------------------------------------------------------------

DClassFactory::~DClassFactory()

{

}

//-------------------------------------------------------------------

STDMETHODIMP

DClassFactory::QueryInterface(REFIID riid, LPVOID FAR *ppvObj)

{

// Init recipient's pointer *ppvObj = NULL;

// If asking for IUnknown, we can provide

225

if(riid == IID_IUnknown) *ppvObj =(LPUNKNOWN) this;

//If asking for IClassFactory, we can provide if(riid == IID_IClassFactory)

*ppvObj =(LPCLASSFACTORY) this;

//Make sure reference count reflects access if(*ppvObj == NULL)

{

//Interface not supported

return E_NOINTERFACE;

}

else

{

// Interface supported to increment reference count ((LPUNKNOWN) *ppvObj)->AddRef();

return S_OK;

}

}

//-------------------------------------------------------------------

STDMETHODIMP_(ULONG)

DClassFactory::AddRef()

{

return ++RefCount;

}

//-------------------------------------------------------------------

STDMETHODIMP_(ULONG)

DClassFactory::Release()

{

if(0L != --RefCount)

return RefCount;

delete this; return 0L;

}

//-------------------------------------------------------------------

STDMETHODIMP

DClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid,

LPVOID FAR *ppvObject)

{

//Initialize return pointer *ppvObject = NULL;

//If trying to aggregate, fail if(pUnkOuter != NULL)

return CLASS_E_NOAGGREGATION;

//Create memory allocation object LPMALLOC pMalloc = CreateAllocator();

if(pMalloc == NULL)

{

return E_OUTOFMEMORY;

}

else

{

// Fetch interface requested by caller

HRESULT hr = pMalloc->QueryInterface(riid, ppvObject);

// Decrement reference count produced by CreateAllocator pMalloc->Release();

226

// Increment count of objects

if(SUCCEEDED(hr))

++cObject;

return hr;

}

}

//-------------------------------------------------------------------

STDMETHODIMP

DClassFactory::LockServer(BOOL fLock)

{

if(fLock)

{

++cLockCount;

}

else

{

--cLockCount;

}

return NOERROR;

}

COMPOBJ.CPP

/*----------------------------------------------

 

COMPOBJ.CPP

-- Component Object registration

 

(c) Paul Yao, 1996

----------------------------------------------

*/

#include <windows.h>

#include "pubmem.h"

int cObject

= 0;

int cLockCount = 0;

//-------------------------------------------------------------------

HRESULT APIENTRY

DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvObj)

{

//Initialize "out" pointer to known value *ppvObj = NULL;

if(rclsid != CLSID_ALLOCATOR)

{

return CLASS_E_CLASSNOTAVAILABLE;

}

DClassFactory *pClassFactory = new DClassFactory(); if(pClassFactory == NULL)

{

return E_OUTOFMEMORY;

}

else

{

return pClassFactory->QueryInterface(riid, ppvObj);

}

}

//-------------------------------------------------------------------

HRESULT APIENTRY

DllCanUnloadNow(void)

{

if(cObject > 0 || cLockCount > 0)

{

return S_FALSE;

227

}

else

{

return S_OK;

}

}

PUBMEM.H

//-------------------------------------------------------------------

// C Interface to private allocator //-------------------------------------------------------------------

#define EXPORT extern "C" __declspec(dllexport)

EXPORT LPMALLOC CreateAllocator();

// {308D0430-1090-11cf-B92A-00AA006238F8} DEFINE_GUID(CLSID_ALLOCATOR,

0x308d0430, 0x1090, 0x11cf, 0xb9,

0x2a, 0x0, 0xaa, 0x0, 0x62, 0x38, 0xf8);

//-------------------------------------------------------------------

// Implementation of allocator interface //-------------------------------------------------------------------

#undef INTERFACE #define INTERFACE DAlloc

DECLARE_INTERFACE_(DAlloc, IMalloc)

{

// *** IUnknown methods ***

STDMETHOD (QueryInterface)(THIS_ REFIID riid, LPVOID FAR *ppv);

STDMETHOD_(ULONG, AddRef) (THIS);

STDMETHOD_(ULONG, Release)(THIS);

// *** IMalloc methods ***

 

STDMETHOD_(void *, Alloc)

(THIS_ ULONG cb);

STDMETHOD_(void *, Realloc)

(THIS_ void *pv, ULONG cb);

STDMETHOD_(void,

Free)

(THIS_ void *pv);

STDMETHOD_(ULONG,

GetSize)

(THIS_ void *pv);

STDMETHOD_(int,

DidAlloc)

(THIS_ void *pv);

STDMETHOD_(void,

HeapMinimize)(THIS);

#ifndef CINTERFACE public :

DAlloc();

~DAlloc();

BOOL Initialize(); private :

ULONG RefCount;

HANDLE hHeap; #endif

};

// Class Factory #undef INTERFACE

#define INTERFACE DClassFactory

DECLARE_INTERFACE_(DClassFactory, IClassFactory)

{

// *** IUnknown methods ***

STDMETHOD (QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppv);

STDMETHOD_(ULONG, AddRef) (THIS);

STDMETHOD_(ULONG, Release)(THIS);

// *** IClassFactory methods ***

STDMETHOD(CreateInstance)(THIS_ LPUNKNOWN pUnkOuter,

Соседние файлы в предмете Операционные системы