one of the principles and implementation of COM
COM component is actually a special object system, follow a unified standard, so that each software can access the object in some way, can do component calls. COM is the unified standard-invoking COM components through interfaces. An interface is the only thing that a COM component can be perceived by the outside world.
Interfaces for all interfaces inherit from IUnknown, implementing interface queries and reference counts. Contains 3 methods:
Interface IUnknown
{
virtual HRESULT _stdcall QueryInterface ([In]refiid IID, [out] void * * * PPV) =0;
Virtual ULONG _stdcall AddRef (void) =0;
Virtual ULONG _stdcall release (void) =0;
}
QueryInterface is responsible for obtaining pointers to the other interfaces of the component.
Addref/release is responsible for managing the lifetime of the component-reference count +1/-1.
I implemented Cross-platform COM, also defined a similar IUnknown interface, I call it: iuniversal, defined as follows:
/** * IUniversal.h * Iuniversal is a variant from IUnknown * Refer: * <<inside com>> * * Init Created: 2016-06-10 * Last updated:2016-06-10 * * * #ifndef iuniversal_h #define IUNIVERSAL_H #include "Platform.h" #define Iid_iu
Niversal ((iid_t) ( -1)) interface Iuniversal {static const iid_t IID = ((iid_t) (-1));
Virtual lresult_t query (iid_t iid, void **ppvout) = 0;
Virtual unsigned long retain (void) = 0;
Virtual unsigned long release (void) = 0;
};
Class Universalimpl {private:refcount_t _REFC;
Public:universalimpl (): _REFC (1) {} virtual ~universalimpl () {}///Iuniversal//
Virtual lresult_t query (iid_t iid, void **PPV) = 0;
Virtual unsigned long retain (void) {return __interlock_inc (&_REFC);
Virtual unsigned long release (void) {if (__interlock_dec (&_REFC) = = 0) {Delete this;
return 0;
return _REFC;
}
}; #endIf/* Iuniversal_h *
Where Platform.h is defined as follows:
/** * Platform.h * * * Init created:2016-06-10 * Last updated:2016-06-10/#ifndef platform_h #define PLATFORM_H #if D efined _msc_ver | | WIN32 #ifndef os_platform_win #define Os_platform_win #endif #endif #ifdef os_platform_win #include <windows.h> #include <process.h> #else #include <pthread.h> #include <unistd.h> #endi
F #ifndef Interface #define INTERFACE struct #endif/** * Interface IID/typedef unsigned int iid_t;
/** * Long result/typedef long LRESULT_T; #define LRES_SUCCESS 0 #define LRES_ERROR ( -1) #define LRES_E_OUTMEMORY ( -4) #define LRES_E_
Nointerface ( -11)/** * Ref count type */#ifdef os_platform_win typedef volatile unsigned long refcount_t; #define __INTERLOCK_INC (ADD) interlockedincrement (add) #define __INTERLOCK_DEC (sub) InterlockedDecrement (sub) #el
SE typedef volatile size_t refcount_t; #define __INTERLOCK_INC (ADD) __sync_add_and_fetcH (Add, 1) #define __INTERLOCK_DEC (sub) __sync_sub_and_fetch (sub, 1) #endif #endif/* Platform_h *
Any C + + object that wants to be COM must inherit from Iuniversal, and because Universalimpl implements a default iuniversal, it can be inherited directly from Universalimpl.
For example, we define the following component entity, whose interface is defined as follows:
Interface Entityinterface:iuniversal
{
static const iid_t IID = ((iid_t) 0x00f001);
virtual void addcomponent (abstractcomponent * component) = 0;
virtual void removecomponent (abstractcomponent * component) = 0;
virtual void removeallcomponents () = 0;
};
The implementation of the component Entity is as follows:
/** * Entity.h * * Refer: * http://www.richardlord.net/blog/what-is-an-entity-framework * http://blog.csdn.net/i_dovel emon/article/details/30250049 * http://blog.csdn.net/zhao_92221/article/details/46629553 * http://blog.csdn.net/ ubuntu64fan/article/details/8839778 * Init created:2016-05-30 * Last updated:2016-06-08/#ifndef entity_h #define EN Tity_h #include ". /entityinterface.h "#include". /componentmanager.h "#include <stdio.h> #include <assert.h> #include". /.. /.. /common/hashmap.h "#include". /.. /..
/common/dhlist.h "#include <memory> #include <vector> using namespace std;
Namespace ECS {class Entitymanager;
Class Entity:public Universalimpl, public entityinterface {friend Class Entitymanager;
static const int comps_hashsize = 0x10;
Entity () {printf ("entity\n");
Init_list_head (&list1_comps); for (int hash = 0; hash <= comps_hashsize; hash++) {Init_hlist_head (&hlist_comps[hash]);
} public:virtual ~entity () {printf ("~entity\n");
Removeallcomponents (); Public://Create function//static lresult_t CreateInstance (Entityinterface **PPV) {Entityinte
Rface * p = (entityinterface *) new Entity ();
if (p) {*PPV = P;
return lres_success;
else {*PPV = 0;
return lres_e_outmemory; }//Iuniversal//Virtual lresult_t query (iid_t iid, void **PPV) {if (IID = = Iuniversal::iid ||
IID = = entityinterface::iid) {*PPV = Static_cast<entityinterface *> (this);
else {*PPV = 0;
return lres_e_nointerface;
} reinterpret_cast<iuniversal*> (*PPV)->retain ();
return lres_success;
Virtual unsigned long retain (void) {return universalimpl::retain (); Virtual unsigned long release (void) {return universalimpl::release (); }//Entityinterface//virtual void addcomponent (Abstractcomponent * component) {Component_type Co
Mptype = Component->getcomponenttype ();
List_add (&component->i_list, &list1_comps);
virtual void removecomponent (Abstractcomponent * component) {} virtual void removeallcomponents () {
struct List_head *list, *node; List_for_each_safe (list, node, &list1_comps) {class abstractcomponent * p = list_entry (list, class Abstra
Ctcomponent, i_list);
List_del (list);
Delete (p);
}} private:struct List_head i_list;
struct Hlist_node i_hash;
* * Components list and hlist * * struct list_head list1_comps;
struct Hlist_head hlist_comps[comps_hashsize + 1];
}; }; * Namespace ECS */#endif/* entity_h * *
Such a COM system is initially embryonic. We also need a smart pointer object to help us use the Component object when we use it. I define this smart interface pointer as follows:
/** * SIPtr.h * Smart Interface pointer * * Use:siptr<ix, iidix> Spix; * Don't use with iuniversal; Siptr<iuniversal, iidiuniversal> * would not compile.
Instead, use Iuniversalsptr. * * Refer: * <<inside com>> * * Init created:2016-06-10 * Last updated:2016-06-10/#ifndef siptr_h #defi Ne siptr_h #include "IUniversal.h" #include <assert.h> template <class t> class Siptr {public://Co
Nstructors siptr () {m_pi = 0;
} siptr (t* lp) {M_PI = LP;
if (M_PI) {m_pi->retain ();
} siptr (iuniversal* pI) {m_pi = 0;
if (PI) {pi->query (t::iid, (void * *) & M_PI);
}//destructor ~siptr () {release ();
}//Reset void release () {if (M_PI) {t* pold = M_PI;
M_PI = 0;
Pold->release (); }//Attach to an existingInterface (does not retain) void attach (T * PI) {if (M_pi!= pI) {iuniversal* pold = M_PI;
M_PI = PI;
if (pold) {//release of the Old Interface Pold->release ();
}}//Detach The interface (does not release) t* Detach () {t* pold = M_PI;
M_PI = 0;
return pold;
}//conversion operator t* () {return m_pi;
}//Pointer operations t& operator* () {assert (M_PI);
return * M_PI;
} t** operator& () {assert (!M_PI);
Return &m_pI;
} t* operator-> () {assert (M_PI);
return M_PI; }//assignment from the same interface t* operator= (t* pi) {if (m_pi!= pi) {//Save Curr
ENT value iuniversal* pold = (iuniversal *) M_pi;
Assign new Value m_pi = PI; if (m_PI) {m_pi->retain ();
} if (Pold) {//release of the Old Interface Pold->release ();
} return M_PI; }//Assignment from another interface t* operator= (iuniversal* PI) {//Save value Iuni
versal* pold = M_PI;
M_PI = 0; Query for Correct interface if (PI) {lresult_t hr = Pi->query (T::iid_interface, (void**) ;
M_PI);
ASSERT (hr = = lres_success && m_pi);
} if (Pold) {//release old pointer Pold->release ();
return M_PI; }//BOOL functions bool operator!
() {return M_PI false:true;
}//Requires a compiler that supports BOOL operator BOOL () const {return m_pi? true:false;
}//Interface ID iid_t iid () {return t::iid;
} Private: pointer variable t* M_PI;
}; /** * Iuniversalptr is a smart interface for Iuniversal */class Iuniversalptr {public://Constructors Iuniversa
Lptr () {m_pi = 0;
} iuniversalptr (iuniversal* lp) {M_PI = LP;
if (M_PI) {m_pi->retain ();
}//destructor ~iuniversalptr () {release ();
}//Reset void release () {if (M_PI) {iuniversal* pold = M_PI;
M_PI = 0;
Pold->release ();
}//conversion operator iuniversal* () {return (iuniversal*) M_pi;
}//Pointer operations iuniversal& operator* () {assert (M_PI);
return *M_PI;
} iuniversal** operator& () {assert (!M_PI);
Return &m_pI;
} iuniversal* operator-> () {assert (M_PI);
return M_PI;
}//Assignment iuniversal* operator= (iuniversal* PI) { if (m_pi!= PI) {//Save current value iuniversal* pold = M_PI;
Assign new Value m_pi = PI;
if (M_PI) {m_pi->retain ();
} if (Pold) {//release of the Old Interface Pold->release ();
} return M_PI; }//Boolean functions bool operator!
() {return M_PI false:true;
} operator bool () const {return m_pi? true:false;
Private://pointer variable iuniversal* M_PI;
};
#endif/* Siptr_h * *
Using Entity is simple:
void Testentityinterface ()
{
siptr<entityinterface>spentity;
Entity::createinstance (&spentity);
Spentity->addcomponent (...);
}