实现接口,从IUnknown开始
实现接口,从IUnknown开始
有必要回想一下IUnknown派生的每一个接口。因为IUnknown包含了两个COM对象的基本特性——引用计数和接口查询。当你编写组件对象类时(coclass),还要写一个满足自己需要的IUnknown实现。以实现IUnknown接口的组件对象类为例——下面这个例子可能是你编写的最简单的一个组件对象类。我们将在一个叫做CUnknownImpl的C++类中实现IUnknown。下面是这个类的声明:
class CUnknownImpl : public IUnknown{public:    // 构造函数和析构器    CUnknownImpl();    virtual ~CUnknownImpl();    // IUnknown 方法    ULONG AddRef();    ULONG Release)();    HRESULT QueryInterface( REFIID riid, void** ppv );protected:    UINT m_uRefCount;  // 对象的引用计数};
构造器和析构器
构造器和析构器管理服务器的引用计数:
CUnknownImpl::CUnknownImpl(){    m_uRefCount = 0;    g_uDllRefCount++;}CUnknownImpl::~CUnknownImpl(){    g_uDllRefCount--;}
当创建新的COM对象时,构造器被调用,它增加服务器的引用计数以保持这个服务器驻留内存。同时它还将对象的引用计数初始化为零。当这个COM对象被摧毁时,它减少服务器的引用计数。
AddRef()和Release()这两个方法控制COM对象的生命期。AddRef()很简单:ULONG CUnknownImpl::AddRef(){    return ++m_uRefCount;}AddRef()只增加对象的引用计数并返回更新的计数。Release()更简单:ULONG CUnknownImpl::Release(){ULONG uRet = --m_uRefCount;    if ( 0 == m_uRefCount )  // 是否释放了最后的引用?        delete this;    return uRet;}
除了减少对象的引用计数外,如果没有另外的明确引用,Release()将摧毁对象。Release()也返回更新的引用计数。注意Release()的实现假设COM对象在堆中创建。如果你在全局粘上创建某个对象,当对象试图删除自己时就会出问题。
现在应该明白了为什么在客户端应用程序中正确调用AddRef()和 Release()是如此重要!如果在这了做得不对,你使用的对象会被很快摧毁,这样的话在整个服务器中内存会很快溢出导致应用程序下次存取服务器代码时崩溃。
如果你编写多线程应用,可能会想到使用++&替代InterlockedIncrement()和InterlockedDecrement()的线程安全问题。++&——用于单线程服务器很保险,因为即使客户端应用是多线程的并从不同的线程中进行方法调用,COM库都会按顺序进行服务器的方法调用。也就是说,一旦一个方法调用开始,所有其它试图调用方法的线程都将阻塞,直到第一个方法返回。COM库本身确保服务器一次不会被一个以上的线程闯入。

阅读更多
个人分类: com
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

实现接口,从IUnknown开始

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭