📄 ch14.htm
字号:
}<BR>
else if (IID_IClassFactory == riid)<BR>
{<BR>
*ppv = &m_ImpIClassFactory;<BR>
LOG("S: CFBass::QueryInterface. pIClassFactory returned.");<BR>
} <BR>
if (NULL != *ppv)<BR>
{<BR>
// We've handed out a pointer to the interface so obey the COM rules<BR>
// and AddRef the reference count.<BR>
((LPUNKNOWN)*ppv)->AddRef();<BR>
hr = NOERROR;<BR>
} <BR>
return (hr);<BR>
} <BR>
STDMETHODIMP_(ULONG) CFBass::AddRef(void)<BR>
{<BR>
m_cRefs++; <BR>
LOGF1("S: CFBass::AddRef. New cRefs=%i.", m_cRefs); <BR>
return m_cRefs;<BR>
} <BR>
STDMETHODIMP_(ULONG) CFBass::Release(void)<BR>
{<BR>
m_cRefs--; <BR>
LOGF1("S: CFBass::Release. New cRefs=%i.", m_cRefs); <BR>
if (0 == m_cRefs)<BR>
{<BR>
if (NULL != m_pServer)<BR>
m_pServer->ObjectsDown(); <BR>
delete this;<BR>
} <BR>
return m_cRefs; <BR>
}</TT></FONT></P>
<P>The <TT>IClassFactory</TT> interface is analogous to the C++ <TT>new</TT> operator.
<TT>IClassFactory</TT> is an interface used for creating COM classes. Each COM class
is created through an <TT>IClassFactory</TT> interface. The <TT>IClassFactory</TT>
interface is derived from <TT>IUnknown</TT> and contains the following methods:</P>
<P><FONT COLOR="#0066FF"><TT><BR>
// IClassFactory methods.<BR>
STDMETHODIMP CreateInstance(IUnknown*, REFIID, PPVOID);<BR>
STDMETHODIMP LockServer(BOOL);</TT></FONT></P>
<P>The method <TT>CreateInstance</TT> is used to create an instance of a COM class.
<TT>LockServer</TT> method increments or decrements a reference count within the
COM server. If the count is greater than 0, the server cannot be removed from memory.
Within the <TT>CFBass</TT> class, the <TT>IClassFactory</TT> is implemented through
the class <TT>CImpIClassFactory</TT>. The <TT>IUnknown</TT> and <TT>IClassFactory</TT>
implementations of <TT>CImpIClassFactory</TT> are shown in Listing 14.8.
<H3><A NAME="Heading14"></A>Listing 14.8<SPACER TYPE="HORIZONTAL" SIZE="10"> FACTORY.CPP--IUnknown
and IClassFactory Implementations in CImpIClassFactory</H3>
<P><FONT COLOR="#0066FF"><TT>CFBass::CImpIClassFactory::CImpIClassFactory(<BR>
CFBass* pBackObj,<BR>
IUnknown* pUnkOuter,<BR>
CServer* pServer)<BR>
{<BR>
// Init the Interface Ref Count (used for debugging only).<BR>
m_cRefI = 0; <BR>
// Init the Back Object Pointer to point to the parent object.<BR>
m_pBackObj = pBackObj; <BR>
// Init the pointer to the server control object.<BR>
m_pServer = pServer; <BR>
// Init the CImpIClassFactory interface's<BR>
//delegating Unknown pointer.<BR>
// We use the Back Object pointer for<BR>
// IUnknown delegation here if we are<BR>
// not being aggregated. If we are being<BR>
// aggregated we use the supplied<BR>
// pUnkOuter for IUnknown delegation.<BR>
// In either case the pointer<BR>
// assignment requires no AddRef<BR>
// because the CImpIClassFactory lifetime is<BR>
// quaranteed by the lifetime of the parent object in which<BR>
// CImpIClassFactory is nested.<BR>
if (NULL == pUnkOuter)<BR>
{<BR>
m_pUnkOuter = pBackObj;<BR>
LOG("S: CFBass::CImpIClassFactory Constructor.<BR>
Non-Aggregating.");<BR>
}<BR>
else<BR>
{<BR>
m_pUnkOuter = pUnkOuter;<BR>
LOG("S: CFBass::CImpIClassFactory Constructor.<BR>
Aggregating.");<BR>
} <BR>
return;<BR>
} <BR>
CFBass::CImpIClassFactory::~CImpIClassFactory(void)<BR>
{<BR>
LOG("S: CFBass::CImpIClassFactory Destructor."); <BR>
return;<BR>
} <BR>
STDMETHODIMP CFBass::CImpIClassFactory::QueryInterface(<BR>
REFIID riid,<BR>
PPVOID ppv)<BR>
{<BR>
LOG("S: CFBass::CImpIClassFactory::QueryInterface.<BR>
Delegating."); <BR>
// Delegate this call to the outer object's QueryInterface.<BR>
return m_pUnkOuter->QueryInterface(riid, ppv);<BR>
} <BR>
STDMETHODIMP_(ULONG) CFBass::CImpIClassFactory::AddRef(void)<BR>
{<BR>
// Increment the Interface Reference Count.<BR>
++m_cRefI; <BR>
LOGF1("S: CFBass::CImpIClassFactory::Addref.<BR>
Delegating. New cI=%i.",m_cRefI); <BR>
// Delegate this call to the outer object's AddRef.<BR>
return m_pUnkOuter->AddRef();<BR>
} <BR>
STDMETHODIMP_(ULONG) CFBass::CImpIClassFactory::Release(void)<BR>
{<BR>
// Decrement the Interface Reference Count.<BR>
--m_cRefI; <BR>
LOGF1("S: CFBass::CImpIClassFactory::Release.<BR>
Delegating. New cI=%i.",m_cRefI); <BR>
// Delegate this call to the outer object's Release.<BR>
return m_pUnkOuter->Release();<BR>
} <BR>
STDMETHODIMP CFBass::CImpIClassFactory::CreateInstance(<BR>
IUnknown* pUnkOuter,<BR>
REFIID riid,<BR>
PPVOID ppv)<BR>
{<BR>
HRESULT hr = E_FAIL;<BR>
COBass* pCob = NULL; <BR>
LOGF1("S: CFBass::CImpIClassFactory::CreateInstance.<BR>
pUnkOuter=0x%X.",pUnkOuter); <BR>
// NULL the output pointer.<BR>
*ppv = NULL; <BR>
// If the creation call is requesting aggregation<BR>
// (pUnkOuter != NULL),<BR>
// the COM rules state the IUnknown interface<BR>
// MUST also be concomitantly<BR>
// be requested. If it is not so requested<BR>
// (riid != IID_IUnknown) then<BR>
// an error must be returned indicating that<BR>
// no aggregate creation of<BR>
// the CFBass COM Object can be performed.<BR>
if (NULL != pUnkOuter && riid != IID_IUnknown)<BR>
hr = CLASS_E_NOAGGREGATION;<BR>
else<BR>
{<BR>
pCob = new COBass(pUnkOuter, m_pServer);<BR>
if (NULL != pCob)<BR>
{<BR>
// We initially created the new COM object<BR>
// so tell the server<BR>
// to increment its global server object<BR>
// count to help ensure<BR>
// that the server remains loaded until<BR>
// this partial creation<BR>
// of a COM component is completed.<BR>
m_pServer->ObjectsUp(); <BR>
// We QueryInterface this new COM Object not<BR>
// only to deposit the<BR>
// main interface pointer to the caller's<BR>
// pointer variable, but to<BR>
// also automatically bump the Reference<BR>
// Count on the new COM<BR>
// Object after handing out this reference to it.<BR>
hr = pCob->QueryInterface(riid, (PPVOID)ppv);<BR>
if (FAILED(hr))<BR>
{<BR>
m_pServer->ObjectsDown();<BR>
delete pCob;<BR>
}<BR>
}<BR>
else<BR>
hr = E_OUTOFMEMORY;<BR>
} <BR>
if (SUCCEEDED(hr))<BR>
{<BR>
LOGF1("S: CFBass::CImpIClassFactory::CreateInstance<BR>
Succeeded. *ppv=0x%X.",*ppv);<BR>
}<BR>
else<BR>
{<BR>
LOG("S: CFBass::CImpIClassFactory::CreateInstance Failed.");<BR>
} <BR>
return hr;<BR>
} <BR>
STDMETHODIMP CFBass::CImpIClassFactory::LockServer(<BR>
BOOL fLock)<BR>
{<BR>
HRESULT hr = NOERROR; <BR>
LOG("S: CFBass::CImpIClassFactory::LockServer."); <BR>
if (fLock)<BR>
m_pServer->Lock();<BR>
else<BR>
m_pServer->Unlock(); <BR>
return hr; <BR>
}</TT></FONT></P>
<P>Three parameters are passed into the method <TT>CreateInstance</TT>:
<UL>
<LI><TT>IUnknown* pUnkOuter</TT>: An outer <TT>IUnknown</TT> interface pointer. This
pointer indicates that object aggregation is being requested by the client application.
In order for aggregation to be successful, the <TT>IID</TT> passed into <TT>CreateInstance</TT>
must be <TT>IID_IUnknown</TT>.
<P>
<LI><TT>REFIID riid</TT>: This variable is the interface ID (<TT>IID</TT>) that the
client application is requesting when creating an instance of the COM class.
<P>
<LI><TT>PPVOID ppv</TT>: A double pointer used to store a pointer to the interface
ID. PPVOID ppv is returned to the client application. In other words, the client
passes in the address of the pointer to the interface ID. The server's responsibility
is to create the interface pointer and return it to the calling program.
</UL>
<P>The <TT>CreateInstance</TT> method is not complicated. When this method is called,
an object of class <TT>COBass</TT> is created. After the object is created, <TT>QueryInterface</TT>
is called on the object using the interface ID passed to <TT>CreateInstance</TT>.
If the requested interface is contained within <TT>COBass</TT>, the interface pointer
is returned to the client. If the requested interface is not contained within <TT>COBass</TT>,
the <TT>COBass</TT> object is deleted and <TT>NULL</TT> is returned.
<H2><A NAME="Heading15"></A>Implementation of the Server Application</H2>
<P>The implementation of the COM server requires some global housekeeping. The class
<TT>CServer</TT> does this housekeeping. <TT>CServer</TT>, a global variable much
like an MFC <TT>CApplication</TT> object, keeps track of the number of object references
within the server (see Listing 14.9).
<H3><A NAME="Heading16"></A>Listing 14.9<SPACER TYPE="HORIZONTAL" SIZE="10"> SERVER.H--CServer
Class Definition</H3>
<P><FONT COLOR="#0066FF"><TT>class CServer<BR>
{<BR>
public:<BR>
CServer(void);<BR>
~CServer(void); <BR>
void Lock(void);<BR>
void Unlock(void);<BR>
void ObjectsUp(void);<BR>
void ObjectsDown(void); <BR>
// A place to store the handle to loaded instance of this DLL module.<BR>
HINSTANCE m_hDllInst; <BR>
// Global DLL Server living Object count.<BR>
LONG m_cObjects; <BR>
// Global DLL Server Client Lock count.<BR>
LONG m_cLocks;<BR>
}; <BR>
extern CServer* g_pServer;</TT></FONT></P>
<P>The server application object is passed into the constructor of all classes implemented
within the COM server. The classes that accept the server application object in their
constructor include the COM Object <TT>COBass</TT>, the class factory <TT>CFBass,</TT>
and <TT>CImpIClassFactory</TT>. Using a central application object allows all object
instances to reference global counters within the COM server. The <TT>CServer</TT>
implementation is shown in Listing 14.10.
<H3><A NAME="Heading17"></A>Listing 14.10 <SPACER TYPE="HORIZONTAL" SIZE="10">SERVER.CPP--CServer
Object Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>CServer::CServer(void)<BR>
{<BR>
// Zero the Object and Lock counts for this attached process.<BR>
m_cObjects = 0;<BR>
m_cLocks = 0; <BR>
return;<BR>
} <BR>
CServer::~CServer(void)<BR>
{<BR>
return;<BR>
} <BR>
void CServer::Lock(void)<BR>
{<BR>
InterlockedIncrement((PLONG) &m_cLocks); <BR>
LOGF1("S: CServer::Lock. New cLocks=%i.", m_cLocks); <BR>
return;<BR>
} <BR>
void CServer::Unlock(void)<BR>
{<BR>
InterlockedDecrement((PLONG) &m_cLocks); <BR>
LOGF1("S: CServer::Unlock. New cLocks=%i.", m_cLocks); <BR>
return;<BR>
} <BR>
void CServer::ObjectsUp(void)<BR>
{<BR>
InterlockedIncrement((PLONG) &m_cObjects); <BR>
LOGF1("S: CServer::ObjectsUp. New cObjects=%i.", m_cObjects); <BR>
return;<BR>
} <BR>
void CServer::ObjectsDown(void)<BR>
{<BR>
InterlockedDecrement((PLONG) &m_cObjects); <BR>
LOGF1("S: CServer::ObjectsDown. New cObjects=%i.", m_cObjects); <BR>
return; <BR>
}</TT></FONT></P>
<P>Two variables used within the <TT>CServer</TT> object, <TT>m_cObjects</TT> and
<TT>m_cLocks</TT>, are accessed by the COM class factory and COM Object. The variable
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -