www.pudn.com > COM技术内幕配书源码.rar > CMPNT1.CPP


// 
// Cmpnt1.cpp - Component 1 
// 
//   Interesting bits of code marked with @N. 
// 
#include  
#include  
 
#include "Iface.h" 
#include "Registry.h" 
 
// Trace function 
void trace(const char* msg) { cout << "Component 1:\t" << msg << endl ;} 
 
/////////////////////////////////////////////////////////// 
// 
// Global variables 
// 
 
// Static variables 
static HMODULE g_hModule = NULL ;   // DLL module handle 
static long g_cComponents = 0 ;     // Count of active components 
static long g_cServerLocks = 0 ;    // Count of locks 
 
// Friendly name of component 
const char g_szFriendlyName[] 
	= "Inside COM, Chapter 8 Example 2, Component 1" ; 
 
// Version-independent ProgID 
const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1" ; 
 
// ProgID 
const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1.1" ; 
 
/////////////////////////////////////////////////////////// 
// 
// Component A 
// 
class CA : public IX 
        // public IY @N 
{ 
public: 
	// IUnknown 
	virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ; 
	virtual ULONG   __stdcall AddRef() ; 
	virtual ULONG   __stdcall Release() ; 
	 
	// Interface IX 
	virtual void __stdcall Fx() { cout << "Fx" << endl ;} 
	 
	/* @N Component1 aggregates instead of implementing interface IY. 
	// Interface IY 
	virtual void __stdcall Fy() { m_pIY->Fy() ;} 
	*/ 
	 
	// Constructor 
	CA() ; 
	 
	// Destructor 
	~CA() ; 
	 
	// Initialization function called by the class factory 
	// to create the contained component 
	HRESULT __stdcall Init() ;  // @N 
 
private: 
	// Reference count 
	long m_cRef ; 
	 
	// Pointer to the aggregated component's IY interface 
	// (We do not have to retain an IY pointer. However, we 
	// can use it in QueryInterface.) 
	IY* m_pIY ;                 // @N 
	 
	// Pointer to inner component's IUnknown 
	IUnknown* m_pUnknownInner ; // @N 
} ; 
 
 
// 
// Constructor 
// 
CA::CA()  
: m_cRef(1),  
  m_pUnknownInner(NULL) //@N 
{  
	::InterlockedIncrement(&g_cComponents) ;  
} 
 
// 
// Destructor 
// 
CA::~CA()  
{  
	::InterlockedDecrement(&g_cComponents) ;  
	trace("Destroy self.") ; 
 
	// Prevent recursive destruction on next AddRef/Release pair. 
	m_cRef = 1 ; 
 
	// Counter the pUnknownOuter->Release in the Init method. 
	IUnknown* pUnknownOuter = this ; 
	pUnknownOuter->AddRef() ; 
 
	// Properly release the pointer; there might be per-interface 
	// reference counts. 
	m_pIY->Release() ; 
 
	// Release contained component. 
	if (m_pUnknownInner != NULL)   // @N 
	{ 
		m_pUnknownInner->Release() ; 
	} 
} 
 
// Initialize the component by creating the contained component. 
HRESULT __stdcall CA::Init() 
{ 
	// Get the pointer to the outer unknown. 
	// Since this component is not aggregated, the outer unknown 
	// is the same as the this pointer.  
	IUnknown* pUnknownOuter = this ; 
	 
	trace("Create inner component.") ; 
	HRESULT hr = 
		::CoCreateInstance(CLSID_Component2, 		  
		                   pUnknownOuter, // Outer component's IUnknown @N 
		                   CLSCTX_INPROC_SERVER, 
		                   IID_IUnknown,  // IUnknown when aggregating  @N 
		                   (void**)&m_pUnknownInner) ;  
	if (FAILED(hr)) 
	{ 
		trace("Could not create contained component.") ; 
		return E_FAIL ; 
	} 
	 
	// This call will increment the reference count on the outer component. 
	trace("Get the IY interface from the inner component.") ; 
	hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N 
	if (FAILED(hr)) 
	{ 
		trace("Inner component does not support interface IY.") ; 
		m_pUnknownInner->Release() ; 
		return E_FAIL ; 
	} 
	 
	// We need to release the reference count added to the 
	// outer component in the above call.  So call Release 
	// on the pointer you passed to CoCreateInstance. 
	pUnknownOuter->Release() ; //@N 
	return S_OK ; 
} 
 
// 
// IUnknown implementation 
// 
HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv) 
{ 	 
	if (iid == IID_IUnknown) 
	{ 
		*ppv = static_cast(this) ;  
	} 
	else if (iid == IID_IX) 
	{ 
		*ppv = static_cast(this) ; 
	} 
	else if (iid == IID_IY) 
	{ 
		trace("Return inner component's IY interface.") ; 
#if 1 
		// You can query for the interface. 
		return m_pUnknownInner->QueryInterface(iid,ppv) ; //@N 
#else 
		// Or you can return a cached pointer. 
		*ppv = m_pIY ;   //@N 
		// Fall through so it will get AddRef'ed 
#endif 
	} 
	else 
	{ 
		*ppv = NULL ; 
		return E_NOINTERFACE ; 
	} 
	reinterpret_cast(*ppv)->AddRef() ; 
	return S_OK ; 
} 
 
ULONG __stdcall CA::AddRef() 
{ 
  	return ::InterlockedIncrement(&m_cRef) ; 
} 
 
ULONG __stdcall CA::Release()  
{ 
	if (::InterlockedDecrement(&m_cRef) == 0) 
	{ 
		delete this ; 
		return 0 ; 
	} 
	return m_cRef ; 
} 
 
 
 
/////////////////////////////////////////////////////////// 
// 
// Class factory 
// 
class CFactory : public IClassFactory 
{ 
public: 
	// IUnknown 
	virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ; 
	virtual ULONG   __stdcall AddRef() ; 
	virtual ULONG   __stdcall Release() ; 
	 
	// Interface IClassFactory 
	virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, 
	                                         const IID& iid, 
	                                         void** ppv) ; 
	virtual HRESULT __stdcall LockServer(BOOL bLock) ;  
	 
	// Constructor 
	CFactory() : m_cRef(1) {} 
 
	// Destructor 
	~CFactory() {} 
	 
private: 
	long m_cRef ; 
} ; 
 
// 
// Class factory IUnknown implementation 
// 
HRESULT __stdcall CFactory::QueryInterface(REFIID iid, void** ppv) 
{ 	 
	IUnknown* pI ; 
	if ((iid == IID_IUnknown) || (iid == IID_IClassFactory)) 
	{ 
		pI = static_cast(this) ;  
	} 
	else 
	{ 
		*ppv = NULL ; 
		return E_NOINTERFACE ; 
	} 
	pI->AddRef() ; 
	*ppv = pI ; 
	return S_OK ; 
} 
 
ULONG __stdcall CFactory::AddRef()  
{  
	return ::InterlockedIncrement(&m_cRef) ;  
} 
 
ULONG __stdcall CFactory::Release()  
{ 
	if (::InterlockedDecrement(&m_cRef) == 0)  
	{ 
		delete this ;  
		return 0 ; 
	}    
	return m_cRef ; 
} 
 
// 
// IClassFactory implementation 
// 
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, 
                                           const IID& iid, 
                                           void** ppv)  
{ 
	// Cannot aggregate 
	if (pUnknownOuter != NULL) 
	{ 
		return CLASS_E_NOAGGREGATION ; 
	} 
	 
	// Create component. 
	CA* pA = new CA ; 
	if (pA == NULL) 
	{ 
		return E_OUTOFMEMORY ; 
	} 
	 
	// Initialize the component. @N 
	HRESULT hr = pA->Init() ; 
	if (FAILED(hr)) 
	{ 
		// Initialization failed. Delete component. 
		pA->Release() ; 
		return hr ; 
	} 
	 
	// Get the requested interface. 
	hr = pA->QueryInterface(iid, ppv) ; 
	pA->Release() ; 
	return hr ;    
} 
 
// LockServer 
HRESULT __stdcall CFactory::LockServer(BOOL bLock)  
{ 
	if (bLock) 
	{ 
		::InterlockedIncrement(&g_cServerLocks) ;  
	} 
	else 
	{ 
		::InterlockedDecrement(&g_cServerLocks) ; 
	} 
	return S_OK ; 
} 
 
 
/////////////////////////////////////////////////////////// 
// 
// Exported functions 
// 
 
STDAPI DllCanUnloadNow() 
{ 
	if ((g_cComponents == 0) && (g_cServerLocks == 0)) 
	{ 
		return S_OK ; 
	} 
	else 
	{ 
		return S_FALSE ; 
	} 
} 
 
// 
// Get class factory. 
// 
STDAPI DllGetClassObject(const CLSID& clsid, 
                         const IID& iid, 
                         void** ppv)  
{ 
	// Can we create this component? 
	if (clsid != CLSID_Component1) 
	{ 
		return CLASS_E_CLASSNOTAVAILABLE ; 
	} 
	 
	// Create class factory. 
	CFactory* pFactory = new CFactory ; // No Addref in constructor 
	if (pFactory == NULL) 
	{ 
		return E_OUTOFMEMORY ; 
	} 
	 
	// Get requested interface. 
	HRESULT hr = pFactory->QueryInterface(iid, ppv) ; 
	pFactory->Release() ; 
	 
	return hr ;	    
} 
 
// 
// Server registration 
// 
STDAPI DllRegisterServer() 
{ 
	return RegisterServer(g_hModule,  
	                      CLSID_Component1,  
	                      g_szFriendlyName, 
	                      g_szVerIndProgID, 
	                      g_szProgID) ; 
} 
 
 
STDAPI DllUnregisterServer() 
{ 
	return UnregisterServer(CLSID_Component1, 
	                        g_szVerIndProgID, 
	                        g_szProgID) ; 
} 
 
/////////////////////////////////////////////////////////// 
// 
// DLL module information 
// 
BOOL APIENTRY DllMain(HANDLE hModule,  
                      DWORD dwReason,  
                      void* lpReserved) 
{ 
	if (dwReason == DLL_PROCESS_ATTACH) 
	{ 
		g_hModule = hModule ; 
	} 
	return TRUE ; 
}