[ Home | Syllabus | Course Notes | Assignments | Search]
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;
}
Page 823 discusses the project creation procedures (And I will give a cookbook for creating this object):
// 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");
};
[
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
{
};
Instead of using "RegComp" from CD
We will develop a client which "flys" the spaceship.
This client features:
Here are the steps:

Need to include two files from the spaceshpisvr - generated by the MIDL
IMySpaceShip* m_pSpaceShip; IMotion* m_pMotion; IVisual* m_pVisual;
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);
}

_COM_SMARTPTR_TYPEDEF(IMotion, __uuidof(IMotion));
You will need to add the header file (#include "comdef.h")
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);
}
// by
m_pMotion = new IMotionPtr( _T("Spaceshipsvr.MySpaceShip.1")) ;
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.