[ 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.