C++中COM对象 INTERFACE接口 和接口基类三者的构建模型
- 格式:doc
- 大小:53.00 KB
- 文档页数:12
《C++中COM对象INTERFACE接口和接口基类三者的构建模型》//===================================================================== ==============// Copyright (c) Microsoft Corporation. All rights reserved.//// THIS CODE AND INFORMA TION IS PROVIDED 'AS IS' WITHOUT W ARRANTY// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND// FITNESS FOR A PARTICULAR PURPOSE.//===================================================================== ==============#pragma once#include <Unknwn.h>///LWW:本文件中,若想剔除ShareObject<T>模板类对"ComPtr.h"头文件的依赖,实现更好的独立性,可将本文件中用"///oo///"打头的代码代替其对应代码,/// 并将无对应代码的行解除注销即可,共涉及5处地方;///oo/// #include "ComPtr.h"#include "ComPtr.h"// Used for initialization of a COM Object// Implement this interface if you require your COMObject// to do initialization after it's created.[uuid("0B3B5912-31A9-49C2-B195-DCABB870AB59")]__interface IInitializable : public IUnknown{// This function is called right after the object is constructed// W ARNING: Don't call AddRef() or Release() for the current object// inside this functionHRESULT __stdcall Initialize();};//// This class encapsulates an IUnknown based object,// and implements AddRef, Relase and QueryInterface// However, QueryInterface requires a helper function: T::QueryInterfaceHelper(IID const&, void**)// that must be implented by all classes using the COMObject// W ARNING: Don't call AddRef() or Release() in the current object's constructor//template <class T>class SharedObject: public T{public:template <class I>static HRESULT Create(__out I** object){///LWW:://如何自定义判断I是T的基类的方法?来取代std::tr1::is_base_of<I, T>::value?static_assert(std::tr1::is_base_of<I, T>::value, "Template arg T must derive from I");ComPtr<I> comPtr = new (std::nothrow) SharedObject<T>();///oo/// I* comPtr = new (std::nothrow) SharedObject<T>();///LWW:操作符“!”已被重载,这里"!comPtr"相当于“nullptr==comPtr”if (!comPtr){return E_FAIL;}return InitializeHelper(comPtr, object);}template <class I, class TArg1>static HRESULT Create(TArg1 &&arg1, __out I** object){static_assert(std::tr1::is_base_of<I, T>::value, "Template arg T must derive from I");ComPtr<I> comPtr = new (std::nothrow) SharedObject<T>(arg1);///oo/// I* comPtr = new (std::nothrow) SharedObject<T>(arg1);if (!comPtr){return E_FAIL;}return InitializeHelper(comPtr, object);}template <class I, class TArg1, class TArg2>static HRESULT Create(TArg1 &&arg1, TArg2 &&arg2, __out I** object){static_assert(std::tr1::is_base_of<I, T>::value, "Template arg T must derive from I");ComPtr<I> comPtr = new (std::nothrow) SharedObject<T>(arg1, arg2);if (!comPtr){return E_FAIL;}return InitializeHelper(comPtr, object);}private:template <class I>static HRESULT InitializeHelper(const ComPtr<I>& comPtr, __out I** object)///oo/// static HRESULT InitializeHelper(I* comPtr, __out I** object){static_assert(std::tr1::is_base_of<I, T>::value, "Template arg T must derive from I");if (!IsOutputPointerV alid(object)){return E_POINTER;}HRESULT hr = S_OK;ComPtr<IInitializable> initializer;if (SUCCEEDED(comPtr->QueryInterface(IID_PPV_ARGS(&initializer)))){hr = initializer->Initialize();}///oo/// ComPtr<I> comPtrtest=comPtr;if (SUCCEEDED(hr)){hr = AssignToOutputPointer(object, comPtr);///oo/// hr = AssignToOutputPointer(object, comPtrtest);}assert(SUCCEEDED(hr));return hr;}SharedObject(): T(), m_refCount(0){}template <class TArg1>SharedObject(TArg1 &&arg1): T(arg1), m_refCount(0){}template <class TArg1, class TArg2>SharedObject(TArg1 &&arg1, TArg2 &&arg2): T(arg1, arg2), m_refCount(0){}///LWW:本函数作用是用以让另一个COM对象的基类接口指针引用它;HRESULT __stdcall QueryInterface(const IID &iid, void **object){if (nullptr == object){return E_POINTER;}*object = nullptr;if (T::QueryInterfaceHelper(iid, object))//lww: 用if (QueryInterfaceHelper(iid, object))替代左侧也可;{//lww: static_cast<IInitializable*>(*object)->AddRef();用此行替代下行也可以;///LWW:这个地方用AddRef(),是因为调用函数中的成员变量ComPtr<IInitializable> initializer没进行加引用操作,这里补上;static_cast<IUnknown*>(*object)->AddRef();return S_OK;}return E_NOINTERFACE;}///LWW:外部用户每次应用COM时,应都调用AddRef(),每次解除引用时都应调用Release();unsigned long __stdcall AddRef(){return static_cast<unsigned long>(InterlockedIncrement(reinterpret_cast<long*>(&m_refCount)));}///LWW:该COM对象,将在引用计数(m_refCount)为零时,销毁自身,以便腾出内存;unsigned long __stdcall Release(){unsigned long refCount = static_cast<unsigned long>(InterlockedDecrement(reinterpret_cast<long*>(&m_refCount)));if (refCount == 0){delete this;}return refCount;}private:// The variable holding the ref count///LWW:该COM用以统计自身是否还被外部引用的计数变量;unsigned long m_refCount;};template <typename I>struct CastHelper{template <typename T>static bool CastTo(const IID &iid, T* objPtr, void **interfacePtr){if (__uuidof(I) == iid || IID_IUnknown == iid){*interfacePtr = static_cast<I*>(objPtr);return true;}return false;}};//===================================================================== ==============// Copyright (c) Microsoft Corporation. All rights reserved.//// THIS CODE AND INFORMA TION IS PROVIDED 'AS IS' WITHOUT W ARRANTY// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND// FITNESS FOR A PARTICULAR PURPOSE.//===================================================================== ==============#pragma once//// This structs acts as a smart pointer for IUnknown pointers// making sure to call AddRef() and Release() as needed.//template<typename T>struct ComPtr{public:///LWW:这个构造函数起到了默认构造函数的作用,因为参数有默认值;ComPtr(T* lComPtr = nullptr) : m_ComPtr(lComPtr){static_assert(std::tr1::is_base_of<IUnknown, T>::value, "T needs to be IUnknown based");if (m_ComPtr){m_ComPtr->AddRef();}}ComPtr(const ComPtr<T>& lComPtrObj){static_assert(std::tr1::is_base_of<IUnknown, T>::value, "T needs to be IUnknown based");m_ComPtr = lComPtrObj.m_ComPtr;if (m_ComPtr){m_ComPtr->AddRef();}}///LWW:这个构造函数在本程序中可去掉;ComPtr(ComPtr<T>&& lComPtrObj){m_ComPtr = lComPtrObj.m_ComPtr;lComPtrObj.m_ComPtr = nullptr;}T* operator=(T* lComPtr){if (m_ComPtr){m_ComPtr->Release();}m_ComPtr = lComPtr;if (m_ComPtr){m_ComPtr->AddRef();}return m_ComPtr;}T* operator=(const ComPtr<T>& lComPtrObj) {if (m_ComPtr){m_ComPtr->Release();}m_ComPtr = lComPtrObj.m_ComPtr;if (m_ComPtr){m_ComPtr->AddRef();}return m_ComPtr;}~ComPtr(){if (m_ComPtr){m_ComPtr->Release();m_ComPtr = nullptr;}}///LWW:定义一个转换操作符“T*”;operator T*() const{return m_ComPtr;}T* GetInterface() const{return m_ComPtr;}///LWW:若将下行代码改成右侧代码“ T operator*() const”,则会出现错误“error:不能创建接口实例”,///LWW:这个操作符重载函数在本程序中可去掉;T& operator*() const{return *m_ComPtr;}T** operator&(){//The assert on operator& usually indicates a bug. Could be a potential memory leak.// If this really what is needed, however, use GetInterface() explicitly.assert(nullptr == m_ComPtr);return &m_ComPtr;}///LWW:重载了“->"这个操作符,使ComPtr对象可以像指针一样使用了;T* operator->() const{return m_ComPtr;}bool operator!() const{return (nullptr == m_ComPtr);}///LWW:对于比较操作符只需定义两个即可:==和<;/// 虽然本程序自定义代码中没有明确调用本函数,但在FlyAnimation.cpp中的FlyAnimationMap.pushback()方法中内含的比较算法中隐式调用了"<"操作符函数;bool operator<(T* lComPtr) const{return m_ComPtr < lComPtr;}///LWW:这个操作符重载函数在本程序中可去掉;bool operator!=(T* lComPtr) const{return !operator==(lComPtr);}bool operator==(T* lComPtr) const{return m_ComPtr == lComPtr;}///LWW:用以将创建好的COM对象在不同基类接口指针间传递;template <typename I>HRESULT QueryInterface(I **interfacePtr){return m_ComPtr->QueryInterface(IID_PPV_ARGS(interfacePtr));}protected:// The internal interface pointerT* m_ComPtr;};//===================================================================== ==============// Copyright (c) Microsoft Corporation. All rights reserved.//// THIS CODE AND INFORMA TION IS PROVIDED 'AS IS' WITHOUT W ARRANTY// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND// FITNESS FOR A PARTICULAR PURPOSE.//===================================================================== ==============#pragma once#include "ComPtr.h"// This error code is not defined in the Windows headers so we// define it here for readibility.const static HRESULT E_USER_CANCELED_OPERA TION = 0x800704C7;template<class T>inline bool IsOutputPointerV alid(T* p){bool valid = (nullptr != p) && (nullptr == *p);assert(valid);return valid;}template<class T>HRESULT AssignToOutputPointer(T** pp, ComPtr<T>p){if ( !IsOutputPointerV alid(pp) ){return E_POINTER;}///LWW:将用到ComPtr对象中的转换操作符“T*”,即p先调用转换操作符T*转换成T*后,在赋值给(*pp);(*pp) = p;if ( nullptr != (*pp) ){(*pp)->AddRef();}return S_OK;}//===================================================================== ==============// Copyright (c) Microsoft Corporation. All rights reserved.//// THIS CODE AND INFORMA TION IS PROVIDED 'AS IS' WITHOUT W ARRANTY// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND// FITNESS FOR A PARTICULAR PURPOSE.//===================================================================== ==============#pragma once#include "ComPtr.h"#include "AsyncLoaderInterfaces.h"namespace Hilo{namespace AsyncLoader{//// class AsyncLoaderItemCache//// This is a helper class for a client item that is to be loaded/unloaded// by the AsyncLoader.//// Its goal is to keep track of a primary and secondary objects, and encapsulate// the logic behind which one is used by the client item, which is unloaded, etc.//class AsyncLoaderItemCache : public IAsyncLoaderItemCache{CRITICAL_SECTION* m_cs;// Primary objectComPtr<IUnknown> m_primaryObject;unsigned int m_primaryObjectSize; // Size is in client units.// Secondary objectComPtr<IUnknown> m_secondaryObject;unsigned int m_secondaryObjectSize; // Size is in client units.ComPtr<IAsyncLoaderItem> m_loadableItem; // The owner client item.ComPtr<IAsyncLoaderMemoryManager> m_memoryManager; // The memory manager is needed// to know at which size the item// should be loaded.// Private helper methods:HRESULT Load(IAsyncLoaderItem* loadableItem, LoadPage loadPage, LoadSize loadSize, bool* set, IUnknown** newObject);protected:AsyncLoaderItemCache();virtual ~AsyncLoaderItemCache();bool QueryInterfaceHelper(const IID &iid, void **object){return CastHelper<IAsyncLoaderItemCache>::CastTo(iid, this, object);}public:// IAsyncLoaderItemCacheHRESULT __stdcall SetCriticalSection(CRITICAL_SECTION* cs);HRESULT __stdcall SetLoadableItem(IAsyncLoaderItem* loadableItem);HRESULT __stdcall SetMemoryManager(IAsyncLoaderMemoryManager* memoryManager);HRESULT __stdcall Load(LoadPage loadPage, LoadSize loadSize);HRESULT __stdcall Unload(LoadSize loadSize);HRESULT __stdcall Shutdown();};}}。