Windows NT Systems Programming: Spring 2000

[ Home | Syllabus | Course Notes | Assignments | Search]


Active Template Library (ATL)

 


Smart Pointers

 


CComPtr (ATL\Include\ATLBASE.H)

template <class T>
class CComPtr
{
public:
	typedef T _PtrClass;
	CComPtr() 	{ p=NULL;} // Initialize when constructed
	CComPtr(T* lp) 	{ //constructor (copying unwrapped pointer)
		if ((p = lp) != NULL) p->AddRef(); // if not NULL, increase reference count
	}
	CComPtr(const CComPtr<T>& lp) 	{ //copy constructor (copying pointer)
		if ((p = lp.p) != NULL)	p->AddRef(); // if not NULL, increase reference count
	}
	~CComPtr() 	{
		if (p) p->Release(); // if pointing at something, release it (instead of "delete")
	}
	void Release() {
		IUnknown* pTemp = p; // all COM objects have IUnKnown at beginning
		if (pTemp) {
			p = NULL; // set to NULL because might be destroyed anytime
			pTemp->Release();
		}
	}
	operator T*() const { // cast ??
		return (T*)p;
	}
	T& operator*() const	{ // dereference (check to NULL)
		ATLASSERT(p!=NULL);
		return *p;
	}
	T** operator&()	{ // call by reference and such
		ATLASSERT(p==NULL);
		return &p;
	}
	T* operator=(T* lp) { // assignment is tricky since the LHS may be destroyed
		return (T*)AtlComPtrAssign((IUnknown**)&p, lp);
	}
	T* operator=(const CComPtr<T>& lp)	{
		return (T*)AtlComPtrAssign((IUnknown**)&p, lp.p);
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther)
	{
		if (p == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (p == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		CComPtr<IUnknown> punk1;
		CComPtr<IUnknown> punk2;
		p->QueryInterface(IID_IUnknown, (void**)&punk1);
		pOther->QueryInterface(IID_IUnknown, (void**)&punk2);
		return punk1 == punk2; // check their vtables
	}
	T* p; // only data member - the "real" pointer
};
ATLAPI_(IUnknown*) AtlComPtrAssign(IUnknown** pp, IUnknown* lp)
{
	if (lp != NULL) // if assigning non-null, record new reference
		lp->AddRef(); 
	if (*pp) // if LHS is already pointing to something, release it.
		(*pp)->Release();
	*pp = lp;
	return lp;
}

Server: example (SpaceShip)

Page 823 discusses the project creation procedures (And I will give a cookbook for creating this object):


IDL file created at this point

// spaceshipsvr.idl : IDL source for spaceshipsvr.dll
//

// This file will be processed by the MIDL tool to
// produce the type library (spaceshipsvr.tlb) and marshalling code.

import "oaidl.idl";
import "ocidl.idl";

[
	uuid(38E81745-04BD-11D4-80B1-0050DA0C5D58), // generates UUID for this new COM object
	version(1.0),
	helpstring("spaceshipsvr 1.0 Type Library")
]
library SPACESHIPSVRLib
{
	importlib("stdole32.tlb");
	importlib("stdole2.tlb");

};


Update IDL file

	[
		object,
		uuid(38E81753-04BD-11D4-80B1-0050DA0C5D58),
		dual,
		helpstring("IMySpaceShip Interface"),
		pointer_default(unique)
	]
	interface IMySpaceShip : IDispatch
	{
	};

[
	uuid(38E81745-04BD-11D4-80B1-0050DA0C5D58),
	version(1.0),
	helpstring("spaceshipsvr 1.0 Type Library")
]
library SPACESHIPSVRLib
{
	importlib("stdole32.tlb");
	importlib("stdole2.tlb");

	[
		uuid(38E81754-04BD-11D4-80B1-0050DA0C5D58),
		helpstring("MySpaceShip Class")
	]
	coclass MySpaceShip
	{
		[default] interface IMySpaceShip;
	};
};

   [
        object,
        uuid(01BCDE31-04C3-11d4-80B1-0050DA0C5D58),
        dual,
        helpstring("IMotion interface")
    ]
    interface IMotion : IDispatch // for this interface derive from IDispatch
    {
	
    };

    [
        object,
        uuid(01BCDE32-04C3-11d4-80B1-0050DA0C5D58),
        helpstring("IVisual interface")
    ]
    interface IVisual : IUnknown // derive from IKnown - to differ from above
    {
	
    };


Adding Properties and Funcionality

 


Developing a C++ client

We will develop a client which "flys" the spaceship.
This client features:

Here are the steps:

flySpace.gif (4465 bytes)

 


Accessing the COM specifications

Need to include two files from the spaceshpisvr - generated by the MIDL

 


BOOL CFlySpaceShipDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	
// skip wizard stuff
	// TODO: Add extra initialization here
	CSliderCtrl* pSlide1 =
		(CSliderCtrl*) GetDlgItem(IDC_POSITION);
	pSlide1->SetRange(-1000, 1000); // the limits of civilized space travel
	pSlide1->SetPos(m_nPosition); // initialized to 0 in constructor
	CSpinButtonCtrl* pSpin =
		(CSpinButtonCtrl*) GetDlgItem(IDC_SPIN1);
	pSpin->SetRange(-10, 10);
	pSpin->SetPos(m_nVelocity); // initialized to 0 in constructor
	
	HRESULT hr;
	hr = CoCreateInstance(CLSID_MySpaceShip, 
		NULL, 
		CLSCTX_INPROC_SERVER, 
		IID_IMySpaceShip, 
		(void**)&m_pSpaceShip);
	
	if(m_pSpaceShip) {
		m_pSpaceShip->QueryInterface(IID_IVisual, (void**)&m_pVisual); // not used in this program
		m_pSpaceShip->QueryInterface(IID_IMotion, (void**)&m_pMotion);
	}
	m_pMotion->SetVelocity(m_nVelocity); // set the initial velocity
	SetTimer(1,50,NULL); // update position every 50 milliseconds
		
	return TRUE;  // return TRUE  unless you set the focus to a control
}
void CFlySpaceShipDlg::OnTimer(UINT nIDEvent) 
{
	long pos;
	m_pMotion->Fly();// fly for another time period
	m_pMotion->GetPosition(&pos); // and get your new position
	m_nPosition = (int)pos; // update member variables
	m_nShowPos = pos;
	this->UpdateData(FALSE); //what does this do?
}
void CFlySpaceShipDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
   
		m_nVelocity = nPos;
		m_pMotion->SetVelocity(long(m_nVelocity)); // change velocity
		UpdateData(FALSE);
   
}

rainbow.gif (2243 bytes)

 


Adding Smart Pointers to the above


Threading Models

Need to be concerned about thread safety with COM objects if they are to be used simultaneously.

ATL supports several threading models.
Nomenclature is a little strange and confusing here.
Basic issue is thread safety. Can enforce safety while giving up opportunity for multithreading.

Free threading marshalling allows cross apartment calls more efficiently by passing pointer to data.

 


Copyright chris wild 1999/2000.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 29, 2000.