COM学习笔记
来源:互联网 发布:淘宝如何申请延期收货 编辑:程序博客网 时间:2024/05/16 06:14
COM 学习笔记
康 林 2004年11月
关键词:组件、接口、动态链接库、注册表、CLSID、GUID、IID、UUID
-
概念:
-
类型库:
-
组件:是一个接口的集合。
-
接口:是一个包含一个函数接针数组的内存结构。每一个数组元素包含的是一个由组件所实现的函数的地址。
组件是接口的集合,接口是函数的集合。
-
-
QueryInterface 的实现规则:
-
QueryInterface 返回的总是同一个 IUnknown 指针。
-
若客户曾经获得过某个接口,那么它将总能获取此接口。
-
客户可以再次获得已经拥有的接口。
-
客户可以返回到起始接口。
-
若能够从某个接口获得某按按特定接口,那么可以从任意接口都将可以获得此接口。
-
-
ProgID 与 CLSID的转换:
-
ProgIDFromCLSID
HRESULT CLSIDFromProgID(
LPCOLESTR lpszProgID, //Pointer to the ProgID
LPCLSID pclsid //Pointer to the CLSID
); -
CLSIDFromProgID
WINOLEAPI ProgIDFromCLSID(
REFCLSID clsid, //CLSID for which the ProgID is requested
LPOLESTR * lplpszProgID
//Address of output variable that receives a
// pointer to the requested ProgID string
);
-
-
CLSID 与字符串的转换:
-
CLSIDFromString
HRESULT CLSIDFromString(
LPOLESTR lpsz, //Pointer to the string representation of the CLSID
LPCLSID pclsid //Pointer to the CLSID
); -
StringFromCLSID
WINOLEAPI StringFromCLSID(
REFCLSID rclsid, //CLSID to be converted
LPOLESTR * ppsz //Address of output variable that receives a
// pointer to the resulting string
); -
StringFromGUID2
int StringFromGUID2(
REFGUID rguid, //Interface identifier to be converted
LPOLESTR lpsz, //Pointer to the resulting string on return
int cchMax //Character count of string at lpsz
);
-
StringFromIID
WINOLEAPI StringFromIID(
REFIID rclsid, //Interface identifier to be converted
LPOLESTR * lplpsz //Address of output variable that receives a
// pointer to the resulting string
); -
IIDFromString
WINOLEAPI IIDFromString(
LPOLESTR lpsz, //Pointer to the string representation of the IID
LPIID lpiid //Pointer to the requested IID on return
);
-
-
注册:
-
用程序注册:regsvr32.exe
-
调用动态函数库中的注册函数:DllRegisterServer
-
调用动态函数库中的反注册函数:DllUnregisterServer
-
-
COM库函数:
-
CoCreateInstance
STDAPI CoCreateInstance(
CoGetClassObject 实现的。CoGetClassObject 将在注册表中查找指定的组件。找到之后,它将装载实现此组件的 DLL(用 CoLoadLibrary)。装载成功之后,它将调用在 DLL 服务器中的实现的 DllGetClassObject。此函数的作用是创建相应的类厂。另外 DllGetClassObject 还将查询 IClassFactory 接口,并将其返回给 CoCreateInstance。然后,CoCreatInstnce 将使用此接口来调用 IClassFactory::CreateInstance 函数。并查询指 CoCreateInstance 参数 riid 中指定的接口。在得到了此接口之后,CoCreateInstance 将释放相应的类厂并将此接口的指针返回给客户。然后客户就能使用此指针来调用组件中的某个方法了。
REFCLSID rclsid, //Class identifier (CLSID) of the object
LPUNKNOWN pUnkOuter, //Pointer to whether object is or isn't part
// of an aggregate
DWORD dwClsContext, //Context for running executable code
REFIID riid, //Reference to the identifier of the interface
LPVOID * ppv //Address of output variable that receives
// the interface pointer requested in riid
);
CoCreateInstance 实际上是调用 -
CoGetClassObject
STDAPI CoGetClassObject(
REFCLSID rclsid, //CLSID associated with the class object
DWORD dwClsContext,
//Context for running executable code
COSERVERINFO * pServerInfo,
//Pointer to machine on which the object is to
// be instantiated
REFIID riid, //Reference to the identifier of the interface
LPVOID * ppv //Address of output variable that receives the
// interface pointer requested in riid
); - CoFreeUnusedLibraries:释放不再使用的DLL
-
- 包容与聚合:
-
接口指针类(智能接口指针):
-
ATL中有 CComPrt 和 CComQIprt(#include <ATLBASE.H>)
template <class T>class CComPtr{public:typedef T _PtrClass;CComPtr(){p=NULL;}CComPtr(T* lp){if ((p = lp) != NULL)p->AddRef();}CComPtr(const CComPtr<T>& lp){if ((p = lp.p) != NULL)p->AddRef();}~CComPtr(){if (p)p->Release();}void Release(){IUnknown* pTemp = p;if (pTemp){p = NULL;pTemp->Release();}}operator T*() const{return (T*)p;}T& operator*() const{ATLASSERT(p!=NULL);return *p;}//The assert on operator& usually indicates a bug. If this is really//what is needed, however, take the address of the p member explicitly.T** operator&(){ATLASSERT(p==NULL);return &p;}_NoAddRefReleaseOnCComPtr<T>* operator->() const{ATLASSERT(p!=NULL);return (_NoAddRefReleaseOnCComPtr<T>*)p;}T* operator=(T* lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp);}T* operator=(const CComPtr<T>& lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp.p);}bool operator!() const{return (p == NULL);}bool operator<(T* pT) const{return p < pT;}bool operator==(T* pT) const{return p == pT;}// Compare two objects for equivalencebool 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;}void Attach(T* p2){if (p)p->Release();p = p2;}T* Detach(){T* pt = p;p = NULL;return pt;}HRESULT CopyTo(T** ppT){ATLASSERT(ppT != NULL);if (ppT == NULL)return E_POINTER;*ppT = p;if (p)p->AddRef();return S_OK;}HRESULT SetSite(IUnknown* punkParent){return AtlSetChildSite(p, punkParent);}HRESULT Advise(IUnknown* pUnk, const IID& iid, LPDWORD pdw){return AtlAdvise(p, pUnk, iid, pdw);}HRESULT CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){ATLASSERT(p == NULL);return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);}HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){CLSID clsid;HRESULT hr = CLSIDFromProgID(szProgID, &clsid);ATLASSERT(p == NULL);if (SUCCEEDED(hr))hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);return hr;}template <class Q>HRESULT QueryInterface(Q** pp) const{ATLASSERT(pp != NULL && *pp == NULL);return p->QueryInterface(__uuidof(Q), (void**)pp);}T* p;};
template <class T, const IID* piid = &__uuidof(T)>class CComQIPtr{public:typedef T _PtrClass;CComQIPtr(){p=NULL;}CComQIPtr(T* lp){if ((p = lp) != NULL)p->AddRef();}CComQIPtr(const CComQIPtr<T,piid>& lp){if ((p = lp.p) != NULL)p->AddRef();}CComQIPtr(IUnknown* lp){p=NULL;if (lp != NULL)lp->QueryInterface(*piid, (void **)&p);}~CComQIPtr(){if (p)p->Release();}void Release(){IUnknown* pTemp = p;if (pTemp){p = NULL;pTemp->Release();}}operator T*() const{return p;}T& operator*() const{ATLASSERT(p!=NULL); return *p;}//The assert on operator& usually indicates a bug. If this is really//what is needed, however, take the address of the p member explicitly.T** operator&(){ATLASSERT(p==NULL);return &p;}_NoAddRefReleaseOnCComPtr<T>* operator->() const{ATLASSERT(p!=NULL);return (_NoAddRefReleaseOnCComPtr<T>*)p;}T* operator=(T* lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp);}T* operator=(const CComQIPtr<T,piid>& lp){return (T*)AtlComPtrAssign((IUnknown**)&p, lp.p);}T* operator=(IUnknown* lp){return (T*)AtlComQIPtrAssign((IUnknown**)&p, lp, *piid);}bool operator!() const{return (p == NULL);}bool operator<(T* pT) const{return p < pT;}bool operator==(T* pT) const{return p == pT;}// Compare two objects for equivalencebool 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;}void Attach(T* p2){if (p)p->Release();p = p2;}T* Detach(){T* pt = p;p = NULL;return pt;}HRESULT CopyTo(T** ppT){ATLASSERT(ppT != NULL);if (ppT == NULL)return E_POINTER;*ppT = p;if (p)p->AddRef();return S_OK;}HRESULT SetSite(IUnknown* punkParent){return AtlSetChildSite(p, punkParent);}HRESULT Advise(IUnknown* pUnk, const IID& iid, LPDWORD pdw){return AtlAdvise(p, pUnk, iid, pdw);}HRESULT CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){ATLASSERT(p == NULL);return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);}HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){CLSID clsid;HRESULT hr = CLSIDFromProgID(szProgID, &clsid);ATLASSERT(p == NULL);if (SUCCEEDED(hr))hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);return hr;}template <class Q>HRESULT QueryInterface(Q** pp){ATLASSERT(pp != NULL && *pp == NULL);return p->QueryInterface(__uuidof(Q), (void**)pp);}T* p;};
//Specialization to make it worktemplate<>class CComQIPtr<IUnknown, &IID_IUnknown>{public:typedef IUnknown _PtrClass;CComQIPtr(){p=NULL;}CComQIPtr(IUnknown* lp){//Actually do a QI to get identityp=NULL;if (lp != NULL)lp->QueryInterface(IID_IUnknown, (void **)&p);}CComQIPtr(const CComQIPtr<IUnknown,&IID_IUnknown>& lp){if ((p = lp.p) != NULL)p->AddRef();}~CComQIPtr(){if (p)p->Release();}void Release(){IUnknown* pTemp = p;if (pTemp){p = NULL;pTemp->Release();}}operator IUnknown*() const{return p;}IUnknown& operator*() const{ATLASSERT(p!=NULL);return *p;}//The assert on operator& usually indicates a bug. If this is really//what is needed, however, take the address of the p member explicitly.IUnknown** operator&(){ATLASSERT(p==NULL);return &p;}_NoAddRefReleaseOnCComPtr<T>* operator->() const{ATLASSERT(p!=NULL);return (_NoAddRefReleaseOnCComPtr<T>*)p;}IUnknown* operator=(IUnknown* lp){//Actually do a QI to get identityreturn (IUnknown*)AtlComQIPtrAssign((IUnknown**)&p, lp, IID_IUnknown);}IUnknown* operator=(const CComQIPtr<IUnknown,&IID_IUnknown>& lp){return (IUnknown*)AtlComPtrAssign((IUnknown**)&p, lp.p);}bool operator!() const{return (p == NULL);}bool operator<(IUnknown* pT) const{return p < pT;}bool operator==(IUnknown* pT) const{return p == pT;}// Compare two objects for equivalencebool 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;}IUnknown* Detach(){IUnknown* pt = p;p = NULL;return pt;}HRESULT CopyTo(T** ppT){ATLASSERT(ppT != NULL);if (ppT == NULL)return E_POINTER;*ppT = p;if (p)p->AddRef();return S_OK;}HRESULT SetSite(IUnknown* punkParent){return AtlSetChildSite(p, punkParent);}HRESULT Advise(IUnknown* pUnk, const IID& iid, LPDWORD pdw){return AtlAdvise(p, pUnk, iid, pdw);}HRESULT CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){ATLASSERT(p == NULL);return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);}HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL){CLSID clsid;HRESULT hr = CLSIDFromProgID(szProgID, &clsid);ATLASSERT(p == NULL);if (SUCCEEDED(hr))hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);return hr;}template <class Q>HRESULT QueryInterface(Q** pp){ATLASSERT(pp != NULL && *pp == NULL);return p->QueryInterface(__uuidof(Q), (void**)pp);}IUnknown* p;};
#define com_cast CComQIPtr
-
MFC中有CIP(#include <afxcom_.h>)
// This is a part of the Microsoft Foundation Classes C++ library.// Copyright (C) 1992-1998 Microsoft Corporation// All rights reserved.//// This source code is only intended as a supplement to the// Microsoft Foundation Classes Reference and related// electronic documentation provided with the library.// See these sources for detailed information regarding the// Microsoft Foundation Classes product.
/////////////////////////////////////////////////////////////////////////////// AFXCOM_.H//// THIS FILE IS FOR MFC IMPLEMENTATION ONLY.
#ifndef __AFXCOM_H__#define __AFXCOM_H__
#ifndef _OBJBASE_H_#include <objbase.h>#endif
/////////////////////////////////////////////////////////////////////////////
#ifdef _AFX_MINREBUILD#pragma component(minrebuild, off)#endif#ifndef _AFX_FULLTYPEINFO#pragma component(mintypeinfo, on)#endif
/////////////////////////////////////////////////////////////////////////////
#ifndef _AFX_NOFORCE_LIBS#pragma comment(lib, "uuid.lib")#endif
/////////////////////////////////////////////////////////////////////////////
#ifdef _AFX_PACKING#pragma pack(push, _AFX_PACKING)#endif
#ifndef ASSERT#ifndef _INC_CRTDBG#include <crtdbg.h>#endif // _INC_CRTDBG#define ASSERT(x) _ASSERT(x)#endif // ASSERT
/////////////////////////////////////////////////////////////////////////////
template<class _Interface, const IID* _IID>class _CIP{public:// Declare interface type so that the type may be available outside// the scope of this template.typedef _Interface Interface;
// When the compiler supports references in template params,// _CLSID will be changed to a reference. To avoid conversion// difficulties this function should be used to obtain the// CLSID.static const IID& GetIID(){ ASSERT(_IID != NULL); return *_IID; }
// Construct empty in preperation for assignment._CIP();
// Copy the pointer and AddRef()._CIP(const _CIP& cp) : _pInterface(cp._pInterface){ _AddRef(); }
// Saves and AddRef()'s the interface_CIP(Interface* pInterface) : _pInterface(pInterface){ _AddRef(); }
// Copies the pointer. If bAddRef is TRUE, the interface will// be AddRef()ed._CIP(Interface* pInterface, BOOL bAddRef): _pInterface(pInterface){if (bAddRef){ASSERT(pInterface != NULL);_AddRef();}}
// Calls CoCreateClass with the provided CLSID._CIP(const CLSID& clsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER): _pInterface(NULL){CreateObject(clsid, dwClsContext);}
// Calls CoCreateClass with the provided CLSID retrieved from// the string._CIP(LPOLESTR str, DWORD dwClsContext = CLSCTX_INPROC_SERVER): _pInterface(NULL){CreateObject(str, dwClsContext);}
// Saves and AddRef()s the interface._CIP& operator=(Interface* pInterface){if (_pInterface != pInterface){Interface* pOldInterface = _pInterface;_pInterface = pInterface;_AddRef();if (pOldInterface != NULL)pOldInterface->Release();}return *this;}
// Copies and AddRef()'s the interface._CIP& operator=(const _CIP& cp){ return operator=(cp._pInterface); }
// Releases any current interface and loads the class with the// provided CLSID._CIP& operator=(const CLSID& clsid){CreateObject(clsid);return *this;}
// Calls CoCreateClass with the provided CLSID retrieved from// the string._CIP& operator=(LPOLESTR str){CreateObject(str);return *this;}
~_CIP();
// Saves/sets the interface without AddRef()ing. This call// will release any previously aquired interface.void Attach(Interface* pInterface){_Release();_pInterface = pInterface;}
// Saves/sets the interface only AddRef()ing if bAddRef is TRUE.// This call will release any previously aquired interface.void Attach(Interface* pInterface, BOOL bAddRef){_Release();_pInterface = pInterface;if (bAddRef){ASSERT(pInterface != NULL);pInterface->AddRef();}}
// Simply NULL the interface pointer so that it isn't Released()'ed.void Detach(){ASSERT(_pInterface);_pInterface = NULL;}
// Return the interface. This value may be NULLoperator Interface*() const{ return _pInterface; }
// Queries for the unknown and return itoperator IUnknown*(){ return _pInterface; }
// Provides minimal level assertion before use.operator Interface&() const{ ASSERT(_pInterface); return *_pInterface; }
// Allows an instance of this class to act as though it were the// actual interface. Also provides minimal assertion verification.Interface& operator*() const{ ASSERT(_pInterface); return *_pInterface; }
// Returns the address of the interface pointer contained in this// class. This is useful when using the COM/OLE interfaces to create// this interface.Interface** operator&(){_Release();_pInterface = NULL;return &_pInterface;}
// Allows this class to be used as the interface itself.// Also provides simple assertion verification.Interface* operator->() const{ ASSERT(_pInterface != NULL); return _pInterface; }
// This operator is provided so that simple boolean expressions will// work. For example: "if (p) ...".// Returns TRUE if the pointer is not NULL.operator BOOL() const{ return _pInterface != NULL; }
// Returns TRUE if the interface is NULL.// This operator will be removed when support for type bool// is added to the compiler.BOOL operator!(){ return _pInterface == NULL; }
// Provides assertion verified, Release()ing of this interface.void Release(){ASSERT(_pInterface != NULL);_pInterface->Release();_pInterface = NULL;}
// Provides assertion verified AddRef()ing of this interface.void AddRef(){ ASSERT(_pInterface != NULL); _pInterface->AddRef(); }
// Another way to get the interface pointer without casting.Interface* GetInterfacePtr() const{ return _pInterface; }
// Loads an interface for the provided CLSID.// Returns an HRESULT. Any previous interface is released.HRESULT CreateObject(const CLSID& clsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER){_Release();HRESULT hr = CoCreateInstance(clsid, NULL, dwClsContext,GetIID(), reinterpret_cast<void**>(&_pInterface));ASSERT(SUCCEEDED(hr));return hr;}
// Creates the class specified by clsidString. clsidString may// contain a class id, or a prog id string.HRESULT CreateObject(LPOLESTR clsidString, DWORD dwClsContext=CLSCTX_INPROC_SERVER){ASSERT(clsidString != NULL);CLSID clsid;HRESULT hr;if (clsidString[0] == '{')hr = CLSIDFromString(clsidString, &clsid);elsehr = CLSIDFromProgID(clsidString, &clsid);ASSERT(SUCCEEDED(hr));if (FAILED(hr))return hr;return CreateObject(clsid, dwClsContext);}
// Performs a QI on pUnknown for the interface type returned// for this class. The interface is stored. If pUnknown is// NULL, or the QI fails, E_NOINTERFACE is returned and// _pInterface is set to NULL.HRESULT QueryInterface(IUnknown* pUnknown){if (pUnknown == NULL) // Can't QI NULL{operator=(static_cast<Interface*>(NULL));return E_NOINTERFACE;}
// Query for this interfaceInterface* pInterface;HRESULT hr = pUnknown->QueryInterface(GetIID(),reinterpret_cast<void**>(&pInterface));if (FAILED(hr)){// If failed intialize interface to NULL and return HRESULT.Attach(NULL);return hr;}
// Save the interface without AddRef()ing.Attach(pInterface);return hr;}
private:// Releases only if the interface is not null.// The interface is not set to NULL.void _Release(){if (_pInterface != NULL)_pInterface->Release();}
// AddRefs only if the interface is not NULLvoid _AddRef(){if (_pInterface != NULL)_pInterface->AddRef();}
// The Interface.Interface* _pInterface;}; // class _CIP
template<class _Interface, const IID* _IID>_CIP<_Interface, _IID>::_CIP<_Interface, _IID>(): _pInterface(NULL){}
template<class _Interface, const IID* _IID>_CIP<_Interface, _IID>::~_CIP<_Interface, _IID>(){// If we still have an interface then Release() it. The interface// may be NULL if Detach() has previosly been called, or if it was// never set.
_Release();}
template<class _Interface, const IID* _IID>class CIP : public _CIP<_Interface, _IID>{public:// Simplified name for base class and provide derived classes// access to base typetypedef _CIP<_Interface, _IID> BC;
// Provideds derived classes access to the interface type.typedef _Interface Interface;
// Construct empty in preperation for assignment.CIP() { }~CIP();
// Copy the pointer and AddRef().CIP(const CIP& cp) : _CIP<_Interface, _IID>(cp) { }
// Saves and AddRef()s the interface.CIP(Interface* pInterface) : _CIP<_Interface, _IID>(pInterface) { }
// Saves the interface and AddRef()s only if bAddRef is TRUE.CIP(Interface* pInterface, BOOL bAddRef): _CIP<_Interface, _IID>(pInterface, bAddRef) { }
// Queries for this interface.CIP(IUnknown* pUnknown){if (pUnknown == NULL)return;Interface* pInterface;HRESULT hr = pUnknown->QueryInterface(GetIID(),reinterpret_cast<void**>(&pInterface));ASSERT(SUCCEEDED(hr));Attach(pInterface);}
// Creates the interface from the CLSID.CIP(const CLSID& clsid) : _CIP<_Interface, _IID>(clsid) { }
// Creates the interface from the CLSID.CIP(LPOLESTR str) : _CIP<_Interface, _IID>(str) { }
// Copies and AddRef()'s the interface.CIP& operator=(const CIP& cp){ _CIP<_Interface, _IID>::operator=(cp); return *this; }
// Saves and AddRef()s the interface.CIP& operator=(Interface* pInterface){ _CIP<_Interface, _IID>::operator=(pInterface); return *this; }
CIP& operator=(IUnknown* pUnknown){HRESULT hr = QueryInterface(pUnknown);ASSERT(SUCCEEDED(hr));return *this;}
// Releases any current interface and loads the class with the// provided CLSID.CIP& operator=(const CLSID& clsid){ _CIP<_Interface, _IID>::operator=(clsid); return *this; }
// Releases any current interface and loads the class with the// provided CLSID.CIP& operator=(LPOLESTR str){ _CIP<_Interface, _IID>::operator=(str); return *this; }}; // class CIP
template<class _Interface, const IID* _IID>CIP<_Interface, _IID>::~CIP(){}
#if _MSC_VER > 1020template<>#endifclass CIP<IUnknown, &IID_IUnknown> : public _CIP<IUnknown, &IID_IUnknown>{public:// Simplified name for base class and provide derived classes// access to base typetypedef _CIP<IUnknown, &IID_IUnknown> BC;
// Provideds derived classes access to the interface type.typedef IUnknown Interface;
// Construct empty in preperation for assignment.CIP() { }
// Copy the pointer and AddRef().CIP(const CIP& cp) : _CIP<IUnknown, &IID_IUnknown>(cp) { }
// Saves and AddRef()s the interface.CIP(Interface* pInterface): _CIP<IUnknown, &IID_IUnknown>(pInterface) { }
// Saves and then AddRef()s only if bAddRef is TRUE.CIP(Interface* pInterface, BOOL bAddRef): _CIP<IUnknown, &IID_IUnknown>(pInterface, bAddRef) { }
// Creates the interface from the CLSID.CIP(const CLSID& clsid) : _CIP<IUnknown, &IID_IUnknown>(clsid) { }
// Creates the interface from the CLSID.CIP(LPOLESTR str) : _CIP<IUnknown, &IID_IUnknown>(str) { }
// Copies and AddRef()'s the interface.CIP& operator=(const CIP& cp){ _CIP<IUnknown, &IID_IUnknown>::operator=(cp); return *this; }
// Saves and AddRef()s the interface. The previously saved// interface is released.CIP& operator=(Interface* pInterface){ _CIP<IUnknown, &IID_IUnknown>::operator=(pInterface); return *this; }
// Releases any current interface and loads the class with the// provided CLSID.CIP& operator=(const CLSID& clsid){ _CIP<IUnknown, &IID_IUnknown>::operator=(clsid); return *this; }
// Releases any current interface and loads the class with the// provided CLSID.CIP& operator=(LPOLESTR str){ _CIP<IUnknown, &IID_IUnknown>::operator=(str); return *this; }
// Queries for the unknown and return itoperator IUnknown*(){ return GetInterfacePtr(); }
// Verifies that pUnknown is not null and performs assignment.HRESULT QueryInterface(IUnknown* pUnknown){_CIP<IUnknown, &IID_IUnknown>::operator=(pUnknown);return pUnknown != NULL ? S_OK : E_NOINTERFACE;}}; // CIP<IUnknown, &IID_IUnknown>
#define IPTR(x) CIP<x, &IID_##x>#define DEFINE_IPTR(x) typedef IPTR(x) x##Ptr;
/////////////////////////////////////////////////////////////////////////////
#ifdef _AFX_PACKING#pragma pack(pop)#endif
#ifdef _AFX_MINREBUILD#pragma component(minrebuild, on)#endif#ifndef _AFX_FULLTYPEINFO#pragma component(mintypeinfo, off)#endif
#endif // __AFXCOM_H__
/////////////////////////////////////////////////////////////////////////////
- 使用接口类的成员函数,用 . 操作符。例如:
CComQIPtr <InterfaceClass, &IID> spIF;
spIF.Release(); //释放接口指针 - 释放接口指针类(智能接口指针):
CComQIPtr <InterfaceClass, &IID> spIF;
spIF = NULL; //释放接口指针
-
-
C++包装类:(MFC OLE)
用嵌套类实现接口:
- 在CCmdTarget类和其派生类定义中使用宏 DECLARE_INTERFACE_MAP() 声明接口映射表使用的一些静态成员以及两个成员函数; #ifdef _AFXDLL
#define DECLARE_INTERFACE_MAP() /
private: /
static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; /
protected: /
static AFX_DATA const AFX_INTERFACEMAP interfaceMap; /
static const AFX_INTERFACEMAP* PASCAL _GetBaseInterfaceMap(); /
virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; /
#else
#define DECLARE_INTERFACE_MAP() /
private: /
static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; /
protected: /
static AFX_DATA const AFX_INTERFACEMAP interfaceMap; /
virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; /
#endif - 在类的实现文件中先定义接口的 IID
- 在类的实现部分使用 BEGIN_INTERFACE_MAP、INTERFACE_PART 和 END_INTERFACE_MAP 宏定义接口映射表; #ifdef _AFXDLL
#define BEGIN_INTERFACE_MAP(theClass, theBase) /
const AFX_INTERFACEMAP* PASCAL theClass::_GetBaseInterfaceMap() /
{ return &theBase::interfaceMap; } /
const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const /
{ return &theClass::interfaceMap; } /
AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP theClass::interfaceMap = /
{ &theClass::_GetBaseInterfaceMap, &theClass::_interfaceEntries[0], }; /
AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = /
{ /
#else
#define BEGIN_INTERFACE_MAP(theClass, theBase) /
const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const /
{ return &theClass::interfaceMap; } /
AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP theClass::interfaceMap = /
{ &theBase::interfaceMap, &theClass::_interfaceEntries[0], }; /
AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = /
{ /
#endif
#define INTERFACE_PART(theClass, iid, localClass) /
{ &iid, offsetof(theClass, m_x##localClass) }, /
#define INTERFACE_AGGREGATE(theClass, theAggr) /
{ NULL, offsetof(theClass, theAggr) }, /
#define END_INTERFACE_MAP() /
{ NULL, (size_t)-1 } /
}; /由这三步,实现接口映射(在 CCmdtarget 中,用接口映射表实现了 IUnknown->QueryInterface 操作)。
- 为每一个接口定义嵌套类成员(定义接口);
BEGIN_INTERFACE_PART()#define BEGIN_INTERFACE_PART(localClass, baseClass) /class X##localClass : public baseClass /{ /public: /STDMETHOD_(ULONG, AddRef)(); /STDMETHOD_(ULONG, Release)(); /STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); /
INIT_INTERFACE_PART()定义了记录偏移量的数据成员 m_nOffset,并在嵌套类的构造函数中对 m_nOffwet 进行初始赋值。所以根据此偏移经计算得到父类的指针 pThis#define METHOD_PROLOGUE_EX(theClass, localClass) /theClass* pThis = ((theClass*)((BYTE*)this - m_nOffset)); /AFX_MANAGE_STATE(pThis->m_pModuleState) /pThis; // avoid warning from compiler /
,然后利用父类的成员函数。
#ifndef _AFX_NO_NESTED_DERIVATION#define INIT_INTERFACE_PART(theClass, localClass) /size_t m_nOffset; /INIT_INTERFACE_PART_DERIVE(theClass, localClass) /
#define INIT_INTERFACE_PART_DERIVE(theClass, localClass) /X##localClass() /{ m_nOffset = offsetof(theClass, m_x##localClass); } /
#else#define INIT_INTERFACE_PART(theClass, localClass)#define INIT_INTERFACE_PART_DERIVE(theClass, localClass)
#endif
STEMETHOD_()
#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method#define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method
END_INTERFACE_PART() 注意:这里会在类中定义一个成员变量: m_xLocallClass 和一个友员类 XlocaalClass#define END_INTERFACE_PART(localClass) /} m_x##localClass; /friend class X##localClass; /
- 实现嵌套类。
在方法中先用宏 METHOD_PROLOGUE_EX_(theClass, localClass) 得到父指针 pThis,然后实现方法。QueryInterface, AddRef, 和 Release 的实现。
STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::AddRef(){ METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget) return pThis->ExternalAddRef();}STDMETHODIMP_(ULONG) COleDropTarget::XDropTarget::Release(){ METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget) return pThis->ExternalRelease();}STDMETHODIMP COleDropTarget::XDropTarget::QueryInterface( REFIID iid, LPVOID* ppvObj){ METHOD_PROLOGUE_EX_(COleDropTarget, DropTarget) return pThis->ExternalQueryInterface(&iid, ppvObj);}
- COM 引出函数和类厂的实现。
- 类厂
COleObjectFactory cf ( CLSID_Math, // The object's CLSID RUNTIME_CLASS (CComClass), // Class representing the object FALSE, // Many clients, one EXE _T ("Math.Object") // The object's ProgID);
- 定义一个内嵌的类厂对象,在类的定义中用 DECLARE_OLECREATE
#define DECLARE_OLECREATE(class_name) /public: /static AFX_DATA COleObjectFactory factory; /static AFX_DATA const GUID guid; /
- 实现类厂对象,在实现文件中用 IMPLEMENT_OLECREATE ,external_name :ProgID;class_name:CLSID
#define IMPLEMENT_OLECREATE(class_name, external_name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) /AFX_DATADEF COleObjectFactory class_name::factory(class_name::guid, /RUNTIME_CLASS(class_name), FALSE, _T(external_name)); /AFX_COMDAT const AFX_DATADEF GUID class_name::guid = /{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; /
- 类厂
建立连接点
- 建立源对象,参见潘爱民的《COM原理及应用》的第 192 页的 6.4.3 节
-
用向导生成一个 DLL 工程,注意要选中自动化。见图
点完成。向导自动在初始化函数中加入了下面的红色部分。
BOOL CKeyInputApp::InitInstance(){CWinApp::InitInstance();
// 将所有 OLE 服务器(工厂)注册为运行。这将使// OLE 库得以从其他应用程序创建对象。COleObjectFactory::RegisterAll();
return TRUE;}
-
用向导加入一个从 CCmdTarget 派生的新类,见图:
它自动完成了类厂的建立和 Disptach 接口。如下: 头文件:#pragma once
// CKeyInput 命令目标
class CKeyInput : public CCmdTarget{DECLARE_DYNCREATE(CKeyInput)
public:CKeyInput();virtual ~CKeyInput();
virtual void OnFinalRelease();
protected:DECLARE_MESSAGE_MAP()DECLARE_OLECREATE(CKeyInput)DECLARE_DISPATCH_MAP()DECLARE_INTERFACE_MAP()};
实现文件:// CKeyInput.cpp : 实现文件//
#include "stdafx.h"#include "KeyInput.h"#include "CKeyInput.h"
// CKeyInput
IMPLEMENT_DYNCREATE(CKeyInput, CCmdTarget)CKeyInput::CKeyInput(){EnableAutomation();
// 为了使应用程序在 OLE 自动化对象处于活动状态时保持//运行,构造函数调用 AfxOleLockApp。AfxOleLockApp();}
CKeyInput::~CKeyInput(){// 为了在用 OLE 自动化创建所有对象后终止应用程序,// 析构函数调用 AfxOleUnlockApp。AfxOleUnlockApp();}
void CKeyInput::OnFinalRelease(){// 释放了对自动化对象的最后一个引用后,将调用// OnFinalRelease。基类将自动// 删除该对象。在调用该基类之前,请添加您的// 对象所需的附加清除代码。CCmdTarget::OnFinalRelease();}
BEGIN_MESSAGE_MAP(CKeyInput, CCmdTarget)END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CKeyInput, CCmdTarget)END_DISPATCH_MAP()
// 注意: 我们添加 IID_IKeyInput 支持//以支持来自 VBA 的类型安全绑定。此 IID 必须同附加到 .IDL 文件中的//调度接口的 GUID 匹配。// {87741D4A-7277-4D93-98F0-D116B995FD91}static const IID IID_IKeyInput ={ 0x87741D4A, 0x7277, 0x4D93, { 0x98, 0xF0, 0xD1, 0x16, 0xB9, 0x95, 0xFD, 0x91 } };
BEGIN_INTERFACE_MAP(CKeyInput, CCmdTarget)INTERFACE_PART(CKeyInput, IID_IKeyInput, Dispatch)END_INTERFACE_MAP()
// {7C6F1364-8C73-4335-B6FD-C61D53681573}IMPLEMENT_OLECREATE_FLAGS(CKeyInput, "KeyInput.KeyInput", afxRegApartmentThreading, 0x7c6f1364, 0x8c73, 0x4335, 0xb6, 0xfd, 0xc6, 0x1d, 0x53, 0x68, 0x15, 0x73)
// CKeyInput 消息处理程序
-
建立连接点容器
- 在实现文件中的接口映射表中定义:INTERFACE_PART(theClass, IID_IConnectionPointContainer, ConnPtContainer)
BEGIN_INTERFACE_MAP(theClass, theBase)INTERFACE_PART(theClass, IID, Dispatch) //这是向导加的INTERFACE_PART(theClass, IID_IConnectionPointContainer, ConnPtContainer)END_INTERFACE_MAP()
- 在类 theClass 的构造函数中加入:
EnableAutomation();
EnableConnections();
- 在实现文件中的接口映射表中定义:INTERFACE_PART(theClass, IID_IConnectionPointContainer, ConnPtContainer)
- 建立连接点
- 在头文件中声明连接点映射表:DELARE_CONNECTION_MAP()
- 在实现文件中定义连接点的 IID 和 在 odl(idl) 文件中定义连接点接口
- 在实现文件中定义连接点映射表:
- BEGIN_CONNECTION_MAP(theClass, theBase)
- CONNECTION_PART(theClass, IID, LocalClass)
- END_CONNECTION_MAP()
- 在头文件中定义连接点对象:
- BEGIN_CONNECTION_PART(theClass,LocalClass)
- CONNECTION_IID(IID)
- END_CONNECTION_PART(LocalClass) 注意:这里会在类中定义一个成员变量: m_xLocallClass 和一个友员类 XlocaalClass
-
- 实现接收器,参见 195 页的 6.4.4 节
- 加入 COM 库初始化函数:AfxOleInit()
- 加入接收器对象:
- BEGIN_INTERFACE_PART(theEvent, IDispatch) //从 IDispatch 派生出来的
- INIT_INTERFACE_PART(theClass, theEvent)
- 接收器的方法:STDMETHOD(...)
- END_INTERFACE_PART(theEvent)
- 实现接收器成员:Invoke 等。
用 ATL 实现接口
VC6.0
-
建立 ATL 工程
- 操作步骤
- 增加的内容
- 操作步骤
- 增加的内容
其它文章索引
- 字符串的处理,见 VC知识库第九期 《COM编程入门——第一部分》
- 用ATL建立轻量级的COM对,见 VC 知识库第十三期
- COM学习笔记
- COM+ 学习笔记
- COM学习笔记
- COM学习笔记
- COM学习笔记
- COM学习笔记
- COM学习笔记
- COM学习笔记
- COM+学习笔记
- com学习笔记之一
- 学习COM+的笔记
- COM+学习笔记
- COM学习笔记
- com学习笔记一
- COM 学习笔记(2)
- COM 学习笔记(3)
- COM学习笔记
- COM学习笔记
- |转| 传说中的Vitas
- 踢毽球去了...
- 數學分布特點
- 指针函数和函数指针有什么区别(转载)
- 过年前收到的一条短信,传说是出自一个MM之手,做个留念
- COM学习笔记
- 情人节快乐
- IadHide5.dll解答
- 节日快乐
- [原创]手工杀毒技术---2006情人节手记
- 水滴石穿C语言之指针、数组和函数(转载)
- 猴子偷桃问题
- 指针作为函数参数传递 (转载)
- 第一课 ADO.NET简介(翻译)