COM 学习笔记
康 林 2004年11月
关键词:组件、接口、动态链接库、注册表、CLSID、GUID、IID、UUID
概念:
类型库:
组件:是一个接口的集合。
接口:是一个包含一个函数接针数组的内存结构。每一个数组元素包含的是一个由组件所实现的函数的地址。
组件是接口的集合,接口是函数的集合。
QueryInterface 的实现规则:
QueryInterface 返回的总是同一个 IUnknown 指针。
若客户曾经获得过某个接口,那么它将总能获取此接口。
客户可以再次获得已经拥有的接口。
客户可以返回到起始接口。
若能够从某个接口获得某按按特定接口,那么可以从任意接口都将可以获得此接口。
ProgID 与 CLSID的转换:
ProgIDFromCLSIDHRESULT 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
);
StringFromCLSIDWINOLEAPI StringFromCLSID(
REFCLSID rclsid, //CLSID to be converted
LPOLESTR * ppsz //Address of output variable that receives a
// pointer to the resulting string
);
StringFromGUID2int 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
);
IIDFromStringWINOLEAPI 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 实际上是调用
CoGetClassObjectSTDAPI 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
);
接口指针类(智能接口指针):
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__ ///////////////////////////////////////////////////////////////////////////// |
C++包装类:(MFC OLE)
用嵌套类实现接口:
#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 |
#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 操作)。
#define BEGIN_INTERFACE_PART(localClass, baseClass) / class X##localClass : public baseClass / { / public: / STDMETHOD_(ULONG, AddRef)(); / STDMETHOD_(ULONG, Release)(); / STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); / |
#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 |
#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method #define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method |
#define END_INTERFACE_PART(localClass) / } m_x##localClass; / friend class X##localClass; / |
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); } |
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 ); |
#define DECLARE_OLECREATE(class_name) / public: / static AFX_DATA COleObjectFactory factory; / static AFX_DATA const GUID guid; / |
#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 } }; / |
建立连接点
用向导生成一个 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 消息处理程序 |
建立连接点容器
BEGIN_INTERFACE_MAP(theClass, theBase) INTERFACE_PART(theClass, IID, Dispatch) //这是向导加的 INTERFACE_PART(theClass, IID_IConnectionPointContainer, ConnPtContainer) END_INTERFACE_MAP() |
用 ATL 实现接口
VC6.0
建立 ATL 工程
import "oaidl.idl"; import "ocidl.idl"; [ uuid(607C0BF2-5E09-42E7-A62F-407036FFAAD3), version(1.0), helpstring("ATLCOM 1.0 Type Library") ] library ATLCOMLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); };ATLCOM.CPP:实现了COM对象实例和动态库的入口和导出函数的实现。
// Fun.h : Declaration of the CFun #ifndef __FUN_H_ #define __FUN_H_ #include "resource.h" // main symbols ///////////////////////////////////////////////////////////////////////////// // CFun class ATL_NO_VTABLE CFun : public CComObjectRootEx , public CComCoClass, public IFun { public: CFun() { } DECLARE_REGISTRY_RESOURCEID(IDR_FUN) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CFun) COM_INTERFACE_ENTRY(IFun) END_COM_MAP() // IFun public: }; #endif //__FUN_H_Fun.rgs:关于注册值:
HKCR { ATLCOM.Fun.1 = s 'Fun Class' { CLSID = s '{00B276CB-650D-4E84-8B8F-A005D4C06C7C}' } ATLCOM.Fun = s 'Fun Class' { CLSID = s '{00B276CB-650D-4E84-8B8F-A005D4C06C7C}' CurVer = s 'ATLCOM.Fun.1' } NoRemove CLSID { ForceRemove {00B276CB-650D-4E84-8B8F-A005D4C06C7C} = s 'Fun Class' { ProgID = s 'ATLCOM.Fun.1' VersionIndependentProgID = s 'ATLCOM.Fun' InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } 'TypeLib' = s '{607C0BF2-5E09-42E7-A62F-407036FFAAD3}' } } }
ATLCOM.idl文件中增加的内容:
import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(2EAC391A-5129-4EF8-BF2B-6E22DEC145DD), helpstring("IFun Interface"), pointer_default(unique) ] interface IFun : IUnknown { }; [ uuid(607C0BF2-5E09-42E7-A62F-407036FFAAD3), version(1.0), helpstring("ATLCOM 1.0 Type Library") ] library ATLCOMLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(00B276CB-650D-4E84-8B8F-A005D4C06C7C), helpstring("Fun Class") ] coclass Fun { [default] interface IFun; }; };
ATLCOM.CPP增加的内容:
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_Fun, CFun)
END_OBJECT_MAP()
编译后增加的文件:
|
// ATLCOM.idl : IDL source for ATLCOM.dll // // This file will be processed by the MIDL tool to // produce the type library (ATLCOM.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(2EAC391A-5129-4EF8-BF2B-6E22DEC145DD), helpstring("IFun Interface"), pointer_default(unique) ] interface IFun : IUnknown { [helpstring("method Add")] HRESULT Add([in]long n1,[in]long n2,[out,retval]long*pval); }; [ uuid(607C0BF2-5E09-42E7-A62F-407036FFAAD3), version(1.0), helpstring("ATLCOM 1.0 Type Library") ] library ATLCOMLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(00B276CB-650D-4E84-8B8F-A005D4C06C7C), helpstring("Fun Class") ] coclass Fun { [default] interface IFun; }; };Fun.h文件增加内容
// Fun.h : Declaration of the CFun #ifndef __FUN_H_ #define __FUN_H_ #include "resource.h" // main symbols ///////////////////////////////////////////////////////////////////////////// // CFun class ATL_NO_VTABLE CFun : public CComObjectRootEx , public CComCoClass, public IFun { public: CFun() { } DECLARE_REGISTRY_RESOURCEID(IDR_FUN) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CFun) COM_INTERFACE_ENTRY(IFun) END_COM_MAP() // IFun public: STDMETHOD(Add)(/*[in]*/long n1,/*[in]*/long n2,/*[out,retval]*/long*pval); }; #endif //__FUN_H_Fun.cpp增加内容
// Fun.cpp : Implementation of CFun #include "stdafx.h" #include "ATLCOM.h" #include "Fun.h" ///////////////////////////////////////////////////////////////////////////// // CFun STDMETHODIMP CFun::Add(long n1, long n2, long *pval) { // TODO: Add your implementation code here return S_OK; }
其它文章索引