// 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 ;
}