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 equivalence bool 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 equivalence bool 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 work template<> class CComQIPtr<IUnknown, &IID_IUnknown> { public: typedef IUnknown _PtrClass; CComQIPtr() { p=NULL; } CComQIPtr(IUnknown* lp) { //Actually do a QI to get identity p=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 identity return (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 equivalence bool 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 NULL operator Interface*() const { return _pInterface; }
// Queries for the unknown and return it operator 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); else hr = 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 interface Interface* 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 NULL void _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 type typedef _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 > 1020 template<> #endif class CIP<IUnknown, &IID_IUnknown> : public _CIP<IUnknown, &IID_IUnknown> { public: // Simplified name for base class and provide derived classes // access to base type typedef _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 it operator 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 工程
- 操作步骤
- 增加的内容
- 操作步骤
- 增加的内容