Click here to Skip to main content
15,897,094 members
Articles / Programming Languages / C++

COM from scratch - PART TWO

Rate me:
Please Sign up or sign in to vote.
4.85/5 (44 votes)
17 Apr 200414 min read 229.6K   6K   134  
An article about COM Library.
// Comp3.cpp 


#include "stdafx.h"
#include "interface.h"
#include <afxdllx.h>
#include <objbase.h>
#include <assert.h>
#include "component3wnd.h"
#include "resource.h"
#include <objbase.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////
BOOL APIENTRY DllMain(HINSTANCE InsModule, 
                      DWORD dwReason, 
                      void* lpReserved)
{
	
	return TRUE ;
}

//------------------------------------------//
//Definition of the class of the component 3
//-----------------------------------------//

class CComponent3 :public  IComponent3

{	
private:
        long m_cRef;
         CComponent3Wnd*   m_pWnd;
       //pointers to the innner components interfaces
	     IComponent1* m_pIComponent1;
	     IComponent2* m_pIComponent2;
public:
//IUnknown
	virtual HRESULT  __stdcall QueryInterface(const IID& iid,void** ppv);
	virtual ULONG	 __stdcall AddRef();
	virtual ULONG	 __stdcall Release();

//IComponent3(Own Interface)
	virtual void __stdcall DefineWindow_Com3();
	virtual void __stdcall ShowWndBackground_Com3(COLORREF bgcolor);
    virtual IUnknown* __stdcall Queryitself3();
	virtual void __stdcall MenuitemNotselected3();
   	//---------------------------------------------------//
	// Initialization function called by the class factory
	// to create the inner components
    HRESULT __stdcall CreateInnerComponents() ;   
    //--------------------------------------------------//

//IComponent1 Interface
   virtual void __stdcall DefineWindow_Com1(bool inner);
   virtual void __stdcall ShowWndBackground_Com1(COLORREF bgcolor);
   virtual void __stdcall Night();
   virtual IUnknown* __stdcall Queryitself1();
   virtual void __stdcall MenuitemNotselected1();
   
//IComponent2 Interface
   virtual void __stdcall DefineWindow_Com2(bool inner);
   virtual void __stdcall ShowWndBackground_Com2(COLORREF bgcolor);
   virtual void __stdcall StartFlying();
   virtual void __stdcall StopFlying();
   virtual IUnknown* __stdcall Queryitself2();
   virtual void __stdcall MenuitemNotselected2();
   CComponent3();
   ~CComponent3();
};


///////////////////////////////////////////////
IUnknown*  __stdcall CComponent3::Queryitself3()
{
    IUnknown* pIunkown=NULL;
	QueryInterface(IID_IUnknown,(void**)&pIunkown);
  	m_cRef-=3;
	return pIunkown;
}

///////////////
//Counstructor
CComponent3::CComponent3():m_cRef(1),m_pWnd(NULL)
{
	TRACE(_T("Component3:constructor is called\n"));
	TRACE(_T("Initializing the Refrance conut to one\n"));
	
}

//////////////
//Destructor
CComponent3::~CComponent3()
{
	TRACE(_T("~CComponent3: Destructor is called\n"));
    if ((m_pIComponent1 != NULL)&&(m_pIComponent2!=NULL))
	{
		m_pIComponent1->Release() ;
		m_pIComponent2->Release() ;
	}
   
}


// Initializing component3 by creating the contained components.
HRESULT __stdcall CComponent3::CreateInnerComponents()
{
 
//Creating inner Component1	
	
HRESULT hr = ::CoCreateInstance(CLSID_Component1, 
	                                NULL, 
	                                CLSCTX_INPROC_SERVER,
	                                IID_IComponent1,
	                                (void**)&m_pIComponent1) ;
 if (FAILED(hr))
	{
	TRACE(_T("Could not create inner component1.\n")) ;
    AfxMessageBox("Run the registration file and put the Comp1.dll in the folder:'C:\\Codeproject'");
	  return E_FAIL ;
	}
	
//Creating inner Component2	
	hr = ::CoCreateInstance(CLSID_Component2, 
	                                NULL, 
	                                CLSCTX_INPROC_SERVER,
	                                IID_IComponent2,
	                                (void**)&m_pIComponent2) ;
	if (FAILED(hr))
	{
	 TRACE(_T("Could not create inner component2.\n")) ;
	 AfxMessageBox("Run the registration file and put the Comp2.dll in the folder:'C:\\Codeproject'");
     return E_FAIL ;
	}

else
	{
		return S_OK ;
	}
}


////////////////////////////////////////////////////////////////////////
HRESULT __stdcall CComponent3::QueryInterface(const IID& iid,void** ppv)
////////////////////////////////////////////////////////////////////////
{
	if(iid==IID_IUnknown)
	{
		TRACE(_T("Returning a pointer to IUnkown interface\n"));
		*ppv=static_cast<IComponent1*>(this);
	   
	}
	   

	else if(iid==IID_IComponent1)
	{
		TRACE(_T("Returing a pointer to IComponent interface\n"));
		*ppv=static_cast<IComponent1*>(this);
	    
	}
	
    else if(iid==IID_IComponent2)
	{
		TRACE(_T("Returing a pointer to IComponent interface\n"));
		*ppv=static_cast<IComponent2*>(this);
	    
	}
	
	
	
	
	else if(iid==IID_IComponent3)
	{
		TRACE(_T("Returing a pointer to IComponent3 interface\n"));
		*ppv=static_cast<IComponent3*>(this);
	    
	}
	
	
	else
{
	TRACE(_T("Interface is not supported\n"));
	*ppv=NULL;
	return E_NOINTERFACE;
}

reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
	return S_OK ;

}
void __stdcall CComponent3::MenuitemNotselected3()
{

}	
//////////////////////////////////////////
void __stdcall CComponent3::DefineWindow_Com1(bool inner)
{
 m_pIComponent1->DefineWindow_Com1 (inner); 

}
////////////////////////////////////////
void __stdcall CComponent3::ShowWndBackground_Com1(COLORREF bgcolor)
{
m_pIComponent1->ShowWndBackground_Com1(bgcolor);
}

//////////////////////////////////////////
void __stdcall CComponent3::Night()
{
m_pIComponent1->Night();
}

IUnknown* __stdcall CComponent3::Queryitself1()
{
    return m_pIComponent1->Queryitself1();
}

void __stdcall CComponent3::MenuitemNotselected1()
{
//No menu is loaded to the inner components window
}

//Interface for component2
//////////////////////////////////////////
void __stdcall CComponent3::DefineWindow_Com2(bool inner)
{
 m_pIComponent2->DefineWindow_Com2 (inner); 

}
////////////////////////////////////////
void __stdcall CComponent3::ShowWndBackground_Com2(COLORREF bgcolor)
{
//--------------------------------------------------------------------------------//
//The outer component (Component3) can reimplement an interface supported
//by the inner component by forwarding calls to the inner component.The outer
//component can specialize the interface by adding code before and after the code
//for the inner component. As an example the background color of component2's window
//will be changed to yellow 
//--------------------------------------------------------------------------------//
	bgcolor=RGB(255,255,0);  //bgcolor is changed to yellow color
//--------------------------------------------------------------------------------//	
    m_pIComponent2->StartFlying();//The butterfly should fly 
    m_pIComponent2->ShowWndBackground_Com2(bgcolor);
    
}

//////////////////////////////////////////
void __stdcall CComponent3::StartFlying()
{
    COLORREF whitecolor=RGB(255,255,255);
	m_pIComponent2->ShowWndBackground_Com2(whitecolor);
	m_pIComponent2->StartFlying();
}

//////////////////////////////////////////
void __stdcall CComponent3::StopFlying()
{
m_pIComponent2->StopFlying();
}


IUnknown* __stdcall CComponent3::Queryitself2()
{
	return 0;
}


void __stdcall CComponent3::MenuitemNotselected2()
{
	//No menu is loaded to the inner components window

}




//////////////////////////////////////////
void __stdcall CComponent3::DefineWindow_Com3()
{

   //Registering the windows class
	CString strWndClass= AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,
		                                    LoadCursor(NULL, IDC_ARROW),
	                                        (HBRUSH)GetStockObject(WHITE_BRUSH),
	                                         0);
	//Create a window object
	m_pWnd = new CComponent3Wnd();
   	
	//Creating the component3 window with popup style
    m_pWnd->CreateEx(WS_OVERLAPPED,//windows syle
					  strWndClass,//class name
					  "COM component 3",//Window text
					  WS_EX_TOOLWINDOW,//windows extended style
					  520,//120,//rect.left,
				      210,//rect.top
					  243,//widows width
				  	  240,//windows hight
					  0,//top-level window and no parent
					  0,//no menu loaded yet
					  0);//no data
    
	//pointing to the own interface from the components own  window
	//in order to be able to handel menuitem selections regarding to AddRef and Release methods
	m_pWnd->m_pComponent3sIUnknown=Queryitself3();
	
	//pointing to the inner interfaces from the components own  window
	//in order to be able to handel menuitem selections regarding to  Release() methods of the inner components
      m_pIComponent1->QueryInterface(IID_IUnknown,(void**)&m_pWnd->m_pComponent1sIUnknown);
	  m_pIComponent2->QueryInterface(IID_IUnknown,(void**)&m_pWnd->m_pComponent2sIUnknown);
	

	
	
	//loading a menu resource from the application�s executable file and
	//attach it to the m_WndMenu object
	m_pWnd->m_WndMenu.LoadMenu("IDR_COM3MENU");
    m_pWnd->SetMenu(&m_pWnd->m_WndMenu);
	
	//showing component1
	m_pWnd->ShowWindow(SW_SHOW);

}

////////////////////////////////////////
void __stdcall CComponent3::ShowWndBackground_Com3(COLORREF bgcolor)
{
 
    CRect rect;
	CRect grassRect;
    CDC*  pDC=m_pWnd->GetDC();
    m_pWnd->GetClientRect (&rect);
   	CBrush grassbrush;
	grassbrush.CreateSolidBrush(RGB(0,255,0));
	CBrush brush;
	brush.CreateSolidBrush (RGB(0,255,255));
    pDC->FillRect(&rect,&brush);	
	CBitmap bmp, *poldbmp;
    CDC memdc;
    bmp.LoadBitmap("IDB_NATURE" );
  	memdc.CreateCompatibleDC( pDC );
    poldbmp = memdc.SelectObject( &bmp );
    pDC->BitBlt( rect.right -180,rect.bottom-109, 200, 100, &memdc, 0, 0, SRCCOPY );
    memdc.SelectObject( poldbmp );
    grassRect.left=rect.left;
	grassRect.top=rect.bottom-10;
	grassRect.right=rect.right;
	grassRect.bottom=rect.bottom;
	pDC->FillRect(&grassRect,&grassbrush);
	
}



/////////////////////////////////////
//AddRef
ULONG __stdcall CComponent3::AddRef()
////////////////////////////////////
{
    CPoint point;
    CRect rect;
	char buf[10];
	TRACE(_T("Increamenting the Refrance count\n"));
	//TRACE(_T("The Refrance count is:\n"));
    //TRACE(_T(itoa(m_cRef+1,buf,10)));
    if(NULL!=m_pWnd)
	{
		m_pWnd->m_cRef++;
		CRect rect;
        CDC* pDC=m_pWnd->GetDC();
		pDC->GetClipBox (&rect);
	    pDC->DrawText(itoa(m_pWnd->m_cRef,buf,10),&rect,DT_RIGHT);
	}
	return ++m_cRef;
}


/////////////////////////////////////	
//Release
/////////////////////////////////////
ULONG __stdcall CComponent3::Release()
{
	char buf[10];
	CStdioFile fw;
	if(NULL!=m_pWnd)
	{
		m_pWnd->m_cRef--;
		CRect rect;
        CDC* pDC=m_pWnd->GetDC();
		pDC->GetClipBox (&rect);
		pDC->DrawText(itoa(m_pWnd->m_cRef,buf,10),&rect,DT_RIGHT);
	}
	// Win32 functions InterlockedDecrement and InterlockedIncrement are used
	// to make sure that only one thread accesses the refrance count variable at a time
	if(InterlockedDecrement(&m_cRef)==0)
	{
	
		TRACE(_T("Deleting of component 3 in progress..."));
		delete this;
		::DestroyWindow (::GetActiveWindow());
	  //The client uses this file in order to know the componet exsists,
		//befor using the interfaces
     	fw.Open ("C:\\Comp3IUnknown.txt",CFile::modeWrite);
					fw.WriteString ("0");
					fw.Close();	
		return 0;
	}
	TRACE(_T("Decermenting the Refrance count\n"));
	//TRACE(_T("The Refrance count is:\n"));
    //TRACE(_T(itoa(m_cRef,buf,10)));
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* pUnkOuter,
	                                         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(const IID& iid,LPVOID* ppv)
{ 	
	if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
		*ppv = static_cast<IClassFactory*>(this) ; 
	else
	{
		*ppv = NULL ;
		return E_NOINTERFACE ;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
	return S_OK ;
}

ULONG __stdcall CFactory::AddRef()
{
	return ::InterlockedIncrement(&m_cRef) ;
}

ULONG __stdcall CFactory::Release() 
{
	TRACE(_T("Release() from CFactroy in progress..."));
	if (::InterlockedDecrement(&m_cRef) == 0)
	{
		delete this ;
		return 0 ;
	}
	return m_cRef ;
}

//
// IClassFactory implementation
///////////////////////////////////////////////////////////////
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnkOuter,
                                           const IID& iid,
                                           void** ppv) 
{
	
	TRACE(_T("CreateInstance is called\n"));
	// Cannot aggregate
	if (pUnkOuter != NULL)
	{
		return CLASS_E_NOAGGREGATION ;
	}
	// Create component3.
    TRACE(_T("Creating Component3 \n"));
	CComponent3* pComponent3 = new CComponent3 ;
	if (pComponent3 == NULL)
	{
		TRACE(_T("No memory available\n"));
		return E_OUTOFMEMORY ;
	}
	

	// Initialize the component. 
	HRESULT hr = pComponent3->CreateInnerComponents() ;
	if (FAILED(hr))
	{
		TRACE(_T("Initialization failed. Deleting the component.\n"));
		pComponent3->Release() ;
		return hr ;
	}
	
	// Get the requested interface.
    hr = pComponent3->QueryInterface(iid,(void**) ppv) ;
	//if Query faild the comp will delete itself
  
if(FAILED(hr))
	{
	    TRACE(_T("Problem in calling Queryinterface\n"));
		pComponent3->Release() ;
	}

	return hr ;   
}
//-----------------------------------------------------------------------//
// LockServer
// Called by the client of a class object to keep a server open in memory,
// allowing instances to be created more quickly.
//-----------------------------------------------------------------------//
HRESULT __stdcall CFactory::LockServer(BOOL bLock) 
{
	
	return S_OK ;
}



// Get class factory
////////////////////////////////////////////
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
    TRACE(_T("DllGetClassObject:\tCreate class factory.\n")) ;
    
    // Can we create this component?
    if (clsid != CLSID_Component3)
    {
        TRACE(_T("Unable to create Component3\n"));
        return CLASS_E_CLASSNOTAVAILABLE ;
    }
    
    // Create class factory.
    CFactory* pFactory = new CFactory ;  // No AddRef in constructor
    if (pFactory == NULL)
    {
        TRACE(_T("No memory available\n"));
        return E_OUTOFMEMORY ;
    }
    
    TRACE(_T("Getting the requested interface\n"));
    // Get requested interface.
    HRESULT hr = pFactory->QueryInterface(iid, ppv) ;
    TRACE(_T("Calling Release() member of CFactory object\n"));
    pFactory->Release() ;
    TRACE(_T("CFactory: Releasing itself,done\n"));
    return hr ;
}










By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions