, C++. , C++, , QueryInterface. . , , , DLL, . , , ( 1). , .
, , ICar:
class Car : public ICar { LONG m_cRef; Car(void) : m_cRef(0) {} STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP GetMaxSpeed(long *pn); STDMETHODIMP Brake(void); }; STDMETHODIMP Car::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(this); else if (riid == IID_IVehicle) *ppv = static_cast<IVehicle*>(this); else if (riid == IID_ICar) *ppv = static_cast<ICar*>(this); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; } // car class object's IClassFactory::CreateInstance // IClassFactory::CreateInstance // car STDMETHODIMP CarClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) { Car *pCar = new Car; if (*pCar) return (*ppv = 0), E_OUTOFMEMORY; pCar->AddRef(); HRESULT hr = pCar->QueryInterface(riid, ppv); pCar->Release(); return hr; }
QueryInterface, AddRef Release.
C++, Car :
class CarBoat : public IBoat { LONG m_cRef; Unknown *m_pUnkCar; CarBoat(void); virtual ~CarBoat(void); STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP GetMaxSpeed(long *pn); STDMETHODIMP Sink(void); };
Car, :
CarBoat::CarBoat (void) : m_cRef(0) { HRESULT hr = CoCreateInstance(CLSID_Car, 0, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar); assert(SUCCEEDED(hr)); } CarBoat::~CarBoat(void) { if (m_pUnkCar) m_pUnkCar->Release(); }
QueryInterface:
STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(this); else if (riid == IID_IVehicle) *ppv = static_cast<IVehicle*>(this); else if (riid == IID_IBoat) *ppv = static_cast<IBoat*>(this); else if (riid == IID_ICar) // forward request... // ... return m_pUnkCar->QueryInterface(riid, ppv); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; }
Car , (identity) , QueryInterface IBoat. ,
QI(IBoat)->ICar
,
QI(QI(IBoat)->ICar)->IBoat
, QueryInterface . QueryInterface IUnknown ICar IBoat , , . IUnknown , CarBoat .
. , , . QueryInterface - . - , ( ) ( ). - IUnknown, (identity) .
. . - . :
class Handlebar : public IHandlebar { ... }; class Wheel : public IWheel {}; class Bicycle : public IBicycle { IHandlebar * m_pHandlebar; IWheel *m_pFrontWheel; IWheel *m_pBackWheel; }
icycle IHandlebar ( ) IWheel ( ) QueryInterface. QueryInterface " " (is-a), (bicycle) (wheel) (handlebar). Bicycle , IBicycle :
[object, uuid(753A8A60-A7FF-11d0-8C30-0080C73925BA)] interface IBicycle : IVehicle { HRESULT GetHandlebar([out,retval] IHandlebar **pph); HRESULT GetWheels([out] IWheel **ppwFront, [out] IWheel **ppwBack); }
Bicycle :
STDMETHODIMP Bicycle::GetHandlebar(IHandlebar **pph) { if (*pph = m_pHandlebar) (*pph)->AddRef(); return S_OK; } STDMETHODIMP Bicycle::GetWheels(IWheel **ppwFront, IWheel **ppwBack) { if (*ppwFront = m_pFrontWheel) (*ppwFront)->AddRef(); if (*ppwBack = m_pBackWheel) (*ppwBack)->AddRef(); return S_OK; }
- . , QueryInterface, .
, , , . , - , ( ) , . , (creation function), , : IUnknown , QueryInterface, AddRef Release. CreateInstance IClassFactory:
HRESULT CreateInstance([in] Unknown *pUnkOuter, [in] REFIID riid, [out, iid_is(riid)] void **ppv);
( API- CoCreateInstanceEx CoCreateInstance) (stand-alone) . CreateInstance (pUnkOuter), . , , pUnkOuter. QueryInterface, AddRef Release pUnkOuter. .
, , CarBoat :
CarBoat::CarBoat(void) : m_cRef(0) { // need to pass identity of self to Create routine // to notify car object it 1s an aggregate // // Create car, - HRESULT hr = CoCreateInstance(CLSID_Car, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar); assert(SUCCEEDED(hr)); }
CarBoat QueryInterface ICar :
STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(this); else if (riid == IID_ICar) // forward request... // ... return m_pUnkCar->QueryInterface(riid, ppv); else if (riid == IID_IBoat) : : :
, QueryInterface , .
CreateInstance Car , IUnknown. IUnknown , : 1) , ; 2) . QueryInterface , , .
, , , IUnknown . , , - , IUnknown. , , QueryInterface, AddRef Release . , vtbl , , . IUnknown, .
IUnknown . 1 IUnknown. Car, :
class Car : public ICar { LONG m_cRef; IUnknown *m_pUnk0uter; public: Car(IUnknown *pUnk0uter); // non-delegating IUnknown methods // IUnknown STDMETHODIMP InternalQueryInterface(REFIID, void **); STDMETHODIMP (ULONG) InternalAddRef(void); STDMETHODIMP_(ULONG) InternalRelease(void); // delegating IUnknown methods // IUnknown STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP GetMaxSpeed(*long *pn); STDMETHODIMP Brake(void); // composite to map distinguished IUnknown vptr to // non-delegating InternalXXX routines 1n main object // vptr IUnknown // InternalXXX // class XNDUnknown : public IUnknown { Car* This() { return (Car*)((BYTE*)this - offsetof(Car, m_innerUnknown));} STDMETHODIMP QueryInterface(REFIID r, void**p) { return This()->InternalQueryInterface(r,p); } STDMETHODIMP_(ULONG) AddRef(void) { return This()->InternalAddRef(); } STDMETHODIMP_(ULONG) Release(void) { return This()->InternalRelease(); } }; XNDUnknown m_innerUnknown; // composite instance // };
. 4.8. :
STDMETHODIMP Car::QueryInterface(REFIID riid, void **ppv) { return m_pUnkOuter->QueryInterface(riid, ppv); } STDMETHODIMP_(ULONG) Car::AddRef(void) { return m_pUnkOuter->AddRef(); } STDMETHODIMP_(ULONG) Car::Release (void) { return m_pUnkOuter->Release(); }
, vtbl , , IUnknown .
m_pUnkOuter , IUnknown:
Car::Car(IUnknown *pUnkOuter) { if (pUnkOuter) // delegate to pUnkOuter // pUnkOuter m_pUnkOuter = pUnkOuter; else // delegate to non-delegating self // m_pUnkOuter = &m_innerUnknown; }
, m_pUnkOuter QueryInterface, AddRef Release.
QueryInterface, AddRef Release :
STDMETHODIMP Car::InternalQueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(&m_innerUnknown); else if (riid = IID_IVehicle) *ppv = static_cast<IVehicle*>(this); else if (riid == IID_ICar) *ppv = static_cast<ICar*>(this); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; } STDMETHODIMP_(ULONG) Car::InternalAddRef(void) { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) Car::InternalRelease(void) { ULONG res = InterlockedDecrement(&m_cRef); if (res == 0) delete this; return res; }
( ) , InternalQueryInterface IUnknown Unknown. , .
, Car :
STDMETHODIMP CarClass::CreateInstance(IUnknown *punk0uter, REFIID riid, void **ppv) { // verify that aggregator only requests IUnknown as // initial interface // , IUnknown // if (pUnkOuter != 0 && riid != IID_IUnknown) return (*ppv = 0), E_INVALIDARG; // create new object/aggregate // Car * = new Car(pUnkOuter); if (!p) return (*ppv = 0), E_OUTOFMEMORY; // return resultant pointer // p->InternalAddRef(); HRESULT hr = p->InternalQueryInterface(riid, ppv); p->InternalRelease(); return hr; }
, QueryInterface, AddRef Release. , , , . , , AddRef , . , IUnknown. . , vptr: QueryInterface, AddRef Release, . IUnknown vptr, IUnknown.
- , . , , AddRef. AddRef , AddRef, . , IUnknown ( , ) . IUnknown . . - , . , (identities) , .
, . , QueryInterface IUnknown. QueryInterface AddRef , AddRef. , , AddRef. , . , , :
STDMETHODIMP Inner::MethodX(void) { ITruck *pTruck = 0; // outer object will be AddRefed after this call... // // AddRef... HRESULT hr = m_pUnkOuter->QueryInterface(IID_ITruck, (void**)&pTruck); if (SUCCEEDED(hr)) { pTruck->ShiftGears(); pTruck->HaulDirt(); // release reference to outer object // pTruck->Release(); } }
, .
HRESULT Inner::Initialize(void) { // outer object will be AddRefed after this call... // // AddRef... HRESULT hr = m_pUnkOuter->QueryInterface(IID_ITruck, (void**)&m_pTruck); // release reference to outer object here and DO NOT // release it later in the object's destructor // // if (SUCCEEDED(hr)) m_pTruck->Release(); }
, . , m_pTruck . , ITruck , , Release .
, , , . , . , . , . , QueryInterface, AddRef , . , , , , , . , , , :
Outer::Outer(void) { ++m_cRef; // protect against delete this // this CoCreateInstance(CLSID_Inner, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkInner); --m_cRef; // allow delete this // this }
, , , , . , - (overridable), / . MFC (Microsoft Foundation Classes Microsoft) CreateAggregates, ATL FinalConstruct.
, C++, IMPLEMENT_UNKNOWN IUnknown. :
class Car : public ICar { Car(void); IMPLEMENT_UNKNOWN(Car) BEGIN_INTERFACE_TABLE(Car) IMPLEMENTS_INTERFACE(ICar) IMPLEMENTS_INTERFACE(IVehicle) END_INTERFACE() // IVehicle methods // IVehicle STDMETHODIMP GetMaxSpeed(long *pn); // ICar methods // ICar STDMETHODIMP Brake(void); };
:
class Car : public ICar { Car(void); //indicate that aggregation is required // , IMPLEMENT_AGGREGATABLE_UNKNOWN(Car) BEGIN_INTERFACE_TABLE(Car) IMPLEMENTS_INTERFACE(ICar) IMPLEMENTS_INTERFACE(IVehicle) END_INTERFACE() // IVehicle methods // IVehicle STDMETHODIMP GetMaxSpeed(long *pn); // ICar methods // ICar STDMETHODIMP Brake(void); };
IMPLEMENT_AGGREGATABLE_UNKNOWN , .
1 , (coloring) IUnknown. , , .