Click here to Skip to main content
15,885,631 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 226.3K   6K   134  
An article about COM Library.
// Comp1.cpp 


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


//------------------------------------------//
//Definition of the class of the component 1
//-----------------------------------------//

class CComponent1 :public IComponent1

{
    private:
    
    long m_cRef;// reference count
    CComponent1Wnd*   m_pWnd;//pointer to the Components window
    
    public:
    //IUnknown
    virtual HRESULT  __stdcall QueryInterface(const IID& iid,void** ppv);
    virtual ULONG	 __stdcall AddRef();
    virtual ULONG	 __stdcall Release();
    //Desired functionality for Component
    virtual void __stdcall DefineWindow_Com1(bool inner);
    virtual void __stdcall ShowWndBackground_Com1(COLORREF bgcolor);
    virtual IUnknown* __stdcall Queryitself1();
    virtual void __stdcall MenuitemNotselected1();
    virtual void __stdcall Night();
    CComponent1();
    ~CComponent1();
};

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


////////////////////////////////////////////////////////////////////////
HRESULT __stdcall CComponent1::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
    {
        TRACE(_T("Interface is not supported\n"));
        *ppv=NULL;
        return E_NOINTERFACE;
    }
    
    reinterpret_cast<IUnknown*>(*ppv)->AddRef();
    return S_OK;
    
}



/////////////////////////////////////
//AddRef
ULONG __stdcall CComponent1::AddRef()
    ////////////////////////////////////
{
    CPoint point;
    CRect rect;
    char buf[10];
    TRACE(_T("Increamenting the Refrance count\n"));
    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 CComponent1::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  component 1 in progress..."));
        delete this;
        ::DestroyWindow (::GetActiveWindow());
        //The client uses this file in order to know the componet exsists,before using the interfaces
        fw.Open ("C:\\Comp1IUnknown.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;
}



///////////////////////////////////////////////////////////
void __stdcall CComponent1::DefineWindow_Com1(bool inner)
{
    
    CString wndtxt="COM Component 1";
    if(inner)
        wndtxt+=",inner";
    
    //Registering the windows class
    CString strWndClass= AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,
    LoadCursor(NULL, IDC_ARROW),
    (HBRUSH)GetStockObject(WHITE_BRUSH),
    0);
    
    //having a window object for Component1
    m_pWnd = new CComponent1Wnd();
    
    //------------------------------------------------//
    //Creating  component1's window with popup style
    //------------------------------------------------//
    m_pWnd->CreateEx(WS_OVERLAPPED,//windows syle
    strWndClass,//class name
    wndtxt,//Window text
    WS_EX_TOOLWINDOW,//windows extended style
    140,//rect.right,
    330,//rect.bottom,
    180,//windows width
    120,//windows hight
    0,//top-level window and no parent
    0,//no menu will be loaded at creation time
    0);//no data
    
    /*
    //---------------------------------------------------------------------------------//
    // use this function if the client is a Multiple Document and the components window
    //is a child window
    //---------------------------------------------------------------------------------//
    m_pWnd->Create(strWndClass,
    "COMPONENT 1",
    WS_CHILD |WS_VISIBLE | WS_OVERLAPPEDWINDOW,
    rect,
    NULL,
    NULL);
    */
    
    
    //------------------------------------------------------------------------------------//
    //pointing to the own interface from the components own inner window
    //in order to be able to handel menuitem selections regarding to AddRef() and Release()
    //------------------------------------------------------------------------------------//
    m_pWnd->m_pComponent1sIUnknown=Queryitself1();
    //------------------------------------------//
    
    //--------------------------------------------------------------------//
    //loading a menu resource from the application�s executable file and
    //attach it to the m_WndMenu object
    if(!inner)//no menu for inner components
    {
        m_pWnd->m_WndMenu.LoadMenu("IDR_COM1MENU");
        m_pWnd->SetMenu(&m_pWnd->m_WndMenu);
    }
    //-------------------------------------------------------------------//
    
    //showing component1
    m_pWnd->ShowWindow(SW_SHOW);
    
    
}


//----------------------------------------------------------------------------//
//This function is called from the client,indicating that a menu item from the
//componnents window has not been selected.
//---------------------------------------------------------------------------//
//////////////////////////////////////////////////
void __stdcall CComponent1::MenuitemNotselected1()
{
    TRACE(_T("MenuitemNotselected\n"));
    if(NULL!=m_pWnd)
        //(white/black color code).. client area of the clients view window
        m_pWnd->m_color_hittest=16777215;//white as default
}



///////////////////////////////////////////////////////////////////
void __stdcall CComponent1::ShowWndBackground_Com1(COLORREF bgcolor)
{
    CPoint point;
    CRect rect;
    CDC*  pDC=m_pWnd->GetDC();
    m_pWnd->GetClientRect (&rect);
    CBrush bgbrush;
    bgbrush.CreateSolidBrush (bgcolor);
    pDC->FillRect(&rect,&bgbrush);
    
    HICON HI=::LoadIcon(AfxGetResourceHandle(),"IDI_SUN");
    point.x =rect.left /2;
    point.y=rect.bottom /2;
    pDC->DrawIcon(point,HI);
    
}


////////////////////////////////////
void __stdcall CComponent1::Night ()
{
    CRect rect;
    CDC*  pDC=m_pWnd->GetDC();
    m_pWnd->GetClientRect (&rect);
    CBrush brush;
    brush.CreateSolidBrush (RGB(0,0,0));
    pDC->FillRect(&rect,&brush);
    CBitmap bmp, *poldbmp;
    CDC memdc;
    
    //----------------------------------------------------------------------//
    //The dll is loaded into the same address space as the client,(look at
    //the third parameter in the CoCreateInstance(...) function which defines
    //server type (CLSCTX_INPROC_SERVER))
    //therefor the dll have access to the clients resources
    //as en example here,a bitmap is loaded from the client's exe file
    //in the following line:
    //------------------------------------------------------------------------//
    bmp.LoadBitmap("IDB_MOON" );
    //------------------------------------------------------------------------//
    
    memdc.CreateCompatibleDC( pDC );
    poldbmp = memdc.SelectObject( &bmp );
    pDC->BitBlt( rect.right -122,rect.bottom -64, 100, 100, &memdc, 0, 0, SRCCOPY );
    memdc.SelectObject( poldbmp );
    
}





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

	
}

//////////////
//Destructor
CComponent1::~CComponent1()
{
	TRACE(_T("~CComponent1: Destructor is called\n"));
 	
}


///////////////////////////////////////////////////////////
//
// 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 component.
    TRACE(_T("Creating Component1 \n"));
    CComponent1* pComponent1 = new CComponent1 ;
    if (pComponent1 == NULL)
    {
        TRACE(_T("No memory available\n"));
        return E_OUTOFMEMORY ;
    }
    
    // Get the requested interface.
    TRACE(_T("Calling QueryInterface(IID_Component1,(void**)&pIComponent1\n"));
    HRESULT	hr = pComponent1->QueryInterface(iid,(void**) ppv) ;
    //if Query faild the comp will delete itself
    
    
    if(FAILED(hr))
    {
        TRACE(_T("Problem in calling Queryinterface\n"));
        pComponent1->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 ;
}

//--------------------------------------------------------------------------//
// Getting the class factory
// DllGetClassObject :
// Retrieves the class object from a DLL object handler or object application.
// DllGetClassObject is called from within the CoGetClassObject function when
// the class context is a DLL.
//-------------------------------------------------------------------------//
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
    TRACE(_T("DllGetClassObject:\tCreate class factory.\n"));
    
    // Can we create component1?
    if (clsid != CLSID_Component1)
    {
        TRACE(_T("Unable to create Component1\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 a poiner to the IClassFactory 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 ;
}



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

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