COM原理与实现之一
COM原理与实现之一
COM组件其实是一种特殊的对象体系,遵循一个统一的标准,使到各个软件都可以通过某种方法访问这个对象的方法,也就可以做到组件调用。COM就是统一的标准——通过接口来调用COM组件。接口是COM组件能被外界所感知的唯一的东西。
所有接口的接口都继承自IUnknown,实现了“接口查询”和“引用计数”。包含3个方法:
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负责得到该组件的其他接口的指针。
AddRef/Release负责管理该组件的生存期——引用计数+1/-1。
我实现的跨平台COM,也定义了类似IUnknown的接口,我称之为:IUniversal,定义如下:
/**
* 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_IUniversal ((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 */
其中Platform.h 定义如下:
/**
* Platform.h
*
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef PLATFORM_H
#define PLATFORM_H
#if defined _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>
#endif
#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)
#else
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 */
任何一个C++对象想要成为COM,必须从IUniversal继承,并且由于 UniversalImpl 实现了一个默认的 IUniversal,所以可以直接从UniversalImpl继承过来。
例如我们定义下面一个组件Entity,其接口定义如下:
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;
};
组件 Entity 的实现如下:
/**
* Entity.h
*
* Refer:
* http://www.richardlord.net/blog/what-is-an-entity-framework
* http://blog.csdn.net/i_dovelemon/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 ENTITY_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) {
EntityInterface * 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 compType = 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 AbstractComponent, 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 */
这样一个COM系统就初具雏形。使用的时候我们还需要一个智能指针对象,辅助我们使用组件对象。我定义这个智能接口指针如下:
/**
* SIPtr.h
* Smart Interface Pointer
*
* Use: SIPtr<IX, iidIX> spIX;
* Do not use with IUniversal; SIPtr<IUniversal, iidIUniversal>
* will not compile. Instead, use IUniversalSPtr.
*
* Refer:
* <<Inside COM>>
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef SIPTR_H
#define SIPTR_H
#include "IUniversal.h"
#include <assert.h>
template <class T> class SIPtr
{
public:
// Constructors
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 existing interface (does not retain)
void attach(T * pI) {
if (m_pI != pI) {
IUniversal* pOld = m_pI;
m_pI = pI;
if (pOld) {
// Release 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 current value
IUniversal* pOld = (IUniversal *) m_pI;
// Assign new value
m_pI = pI;
if (m_pI) {
m_pI->retain();
}
if (pOld) {
// Release the old interface
pOld->release();
}
}
return m_pI;
}
// Assignment from another interface
T* operator=(IUniversal* pI) {
// Save current value
IUniversal* 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
IUniversalPtr() {
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 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 */
使用 Entity 很简单:
void testEntityInterface()
{
SIPtr<EntityInterface>spEntity;
Entity::createInstance(&spEntity);
spEntity->addComponent(...);
}
COM原理与实现之一的更多相关文章
- 奇异值分解(SVD)原理与在降维中的应用
奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 线性判别分析LDA原理总结
在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...
- [原] KVM 虚拟化原理探究(1)— overview
KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...
- H5单页面手势滑屏切换原理
H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...
- .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...
- python自动化测试(2)-自动化基本技术原理
python自动化测试(2) 自动化基本技术原理 1 概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...
- CRC、反码求和校验 原理分析
3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
- Objective-C中block的底层原理
先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...
随机推荐
- Java Servlet 笔记4
Servlet 客户端 HTTP 请求 当浏览器请求网页时,它会向 Web 服务器发送特定信息,这些信息不能被直接读取,因为这些信息是作为 HTTP 请求的头的一部分进行传输的. 读取 HTTP 头的 ...
- mysql免安装版下载及配置教程
第一步:下载 下载地址:http://dev.mysql.com/downloads/mysql/ 滚动到下方就能看到了,根据自己的需求下载: 我的电脑为64为的所以下载的为 Windows (x86 ...
- codeblocks设置背景主题
一. 首先进入codeblocks官网找到colour theme代码. codeblocks官网代码地址:http://wiki.codeblocks.org/index.php?title=Syn ...
- final、finally与finalize的区别
1. final 在java中,final可以用来修饰类,方法和变量(成员变量或局部变量).下面将对其详细介绍. 1.1 修饰类 当用final修饰类的时,表明该类不能被其他类所继承.当我们需要让一 ...
- js登录,回车登录
$(document).ready(function(){ $("#loginBtn").click(doLoginEvent); loadCookies(); //回车登录 do ...
- 原生js移动端列表无缝间歇向上滚动
在项目开发中尤其是在项目的活动页面的开发中,经常需要将用户的购买信息或中奖信息等以列表的形式展示在页面当中,并可以使其自动间歇向上滚动来达到在有限的区域内展示所有信息的目的.通常的做法是通过将列表父元 ...
- 操作系统内存管理之 内部碎片vs外部碎片
外部碎片:因为行程持续地被载入与置换,使得可用的记忆体空间被分割成许多不连续的区块.虽然记忆体所剩空间总和足够让新行程执行,却因为空间不连续,导致程式无法载入执行.内部碎片:发生在以固定长度分割区来进 ...
- Python小代码_2_格式化输出
Python小代码_2_格式化输出 name = input("name:") age = input("age:") job = input("jo ...
- Docker学习系列(二)Docker初体验
一.系统要求 Docker的安装,需要在CentOS 7.0+版本,内核至少3.10,64-bit uname --r [randy@randysun ~]$ uname --r -.el7.x86_ ...
- C#判断画的图形是不是三角形
这个源代码写的不是十全十美,只是提供一个 还待完善的地方例如判断是否这个图形是封闭的.得空在解决吧 这只是一个算法上 谁有c#的参考手册网盘分享一份 谢谢 下面请看源码 凑够150个字了,不废话了. ...