5, , , , . , , , .
, , . , :
[uuid(75DA6457-DD0F-11d0-8C58-0080C73925BA),object] interface IProgrammer : IUnknown { HRESULT StartHacking(void); HRESULT IsProductDone([out, retval] BOOL *pbIsDone); }
:
HRESULT ShipSoftware(void) { IProgrammer *pp = 0; HRESULT hr = CoGetObject(OLESTR("programmer:Bob"), 0, IID_IProgrammer, (void**)&pp); if (SUCCEEDED(hr)) { hr = pp->StartHacking(); BOOL bIsDone = FALSE; while (!bIsDone && SUCCEEDED(hr)) { Sleep(15000); // wait 15 seconds // 15 hr = pp->IsProductDone(&bIsDone); // check status // } pp->Release(); } }
, , 15 . : , - (programmer object) , . , , - :
[uuid(75DA6458-DD9F-11d0-8C58-0080C73925BA),object] interface ISoftwareConsumer : IUnknown { HRESULT OnProductIsDone(void); HRESULT OnProductWillBeLate([in] hyper nMonths); }
- , ISoftwareConsumer, - . IProgrammer , , - (consumer object). Advise:
interface IProgrammer : IUnknown { HRESULT Advise ([in] ISoftwareConsumer *psc, [out] DWORD *pdwCookie); : : :
- , DWORD . DWORD Unadvise:
interface IProgrammer : IUnknown { : : : HRESULT Unadvise([in] DWORD dwCookie); }
, - . DWORD - .
IProgrammer, - Advise
STDMETHODIMP Programmer::Advise(ISoftwareConsumer *pcs, DWORD *pdwCookie) { assert(pcs); if (m_pConsumer != 0) // is there already a consumer? // ? return E_UNEXPECTED; (m_pConsumer = pcs)->AddRef(); // hold onto new consumer // *pdwCookie = DWORD(pcs); // make up a reasonable cookie // return S_OK; }
Unadvise :
STDMETHODIMP Programmer::Unadvise(DWORD dwCookie) { // does the cookie correspond to the current consumer? // ? if (DWORD(m_pConsumer) != dwCookie) return E_UNEXPECTED; (m_pConsumer)->Release(); // release current consumer // m_pConsumer = 0; return S_OK; }
. 7.7. , , , ISoftwareConsumer.
, StartHacking :
STDMETHODIMP Programmer::StartHacking (void) { assert(m_pConsumer); // preemptively notify of lateness // HRESULT hr = m_Consumer->OnProductWillBeLate(3); if (FAILED(hr)) return PROGRAMMER_E_UNREALISTICCONSUMER; // generate some code // extern char *g_rgpszTopFiftyStatements[]; for (int n = 0; n < 100000; n++) printf(g_rgpszTopFiftyStatements[rand() % 50]); // inform consumer of done-ness // hr = m_pConsumer->OnProductIsDone(); return S_OK; }
To , ISoftwareConsumer , - , . StartHacking , - , , , , . - , - - . , Unadvise, .
IProgrammer ISoftwareConsumer, , , IProgrammer - . , - , IProgrammer IProgrammer. , , , , . :
[uuid(75DA645D-DD0F-11d0-8C58-0080C73925BA),object ] interface IShutdownNotify : IUnknown { HRESULT OnObjectDestroyed([in] IUnknown *pUnk); }
, IShutdownNotify . , , , , . . 7.8, ( ) , :
[uuid(75DA645E-DD0F-11d0-8C58-0080C73925BA), object] interface IShutdownSource : IUnknown { HRESULT Advise([in] IShutdownNotify *psn, [out] DWORD *pdwCookie); HRESULT Unadvise([in] DWORD dwCookie); }
, , , (observers) IShutdownNotify . , . , : .
, . . . . IConnectionPoint:
[object, uuid(B196B286-BAB4-101A-B69C-00AA00341D07)] interface IConnectionPoint : IUnknown { // which type of interface can be connected // HRESULT GetConnectionInterface( [out] IID * pIID); // get a pointer to identity of "real" object // " " HRESULT GetConnectionPointContainer([out] IConnectionPointContainer ** ppCPC); // hold and use pUnkSink until notified otherwise // pUnkSink, HRESULT Advise([in] IUnknown * pUnkSink, [out] DWORD * pdwCookie); // stop holding/using the pointer associated with dwCookle // / , dwCookie HRESULT Unadvise([in] DWORD dwCookie); // get information about currently held pointers // HRESULT EnumConnections([out] IEnumConnections ** ppEnum); }
. 7.9, , . , IConnectionPoint , QueryInterface. , , IConnectionPoint, :
[object,uuid(B196B284-BAB4-101A-B69C-00AA00341D07)] interface IConnectionPointContainer : IUnknown { // get all possible IConnectionPoint implementations // IConnectionPoint HRESULT EnumConnectionPoints([out] IEnumConnectionPoints ** ppEnum); // get the IConnectionPoint implementation for riid // IConnectionPoint riid HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint ** ppCP); }
. 7.9, IConnectionPoint - .
IShutdownNotify :
HRESULT HookupShutdownCallback(IUnknown *pUnkObject, IShutdownNotify *pShutdownNotify, DWORD &rdwCookie) { IConnectionPointContainer *pcpc = 0; HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc); if (SUCCEEDED(hr)) { IConnectionPoint *pcp = 0; hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp); if (SUCCEEDED(hr)) { hr = pcp->Advise(pShutdownNotify, &rdwCookie); pcp->Release(); } pcpc->Release(); } }
:
HRESULT TeardownShutdownCallback(IUnknown *pUnkObject, DWORD dwCookie) { IConnectionPointContainer *pcpc = 0; HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc); if (SUCCEEDED(hr)) { IConnectionPoint *pcp = 0; hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp); if (SUCCEEDED(hr)) { hr = pcp->Unadvise(dwCookie); pcp->Release(); } pcpc->Release(); } }
, IConnectionPointContainer::FindConnectionPoint IShutdownNotify- IConnectionPoint. FindConnectionPoint, , IShutdownNotify. .
IUnknown, IConnectionPointContainer IConnectionPoint . C++ , . ConnectionPoint / , :
class Surfboard : public ISurfboard, public IHazardousDevice, public ISharkBait, public IConnectionPointContainer { LONG m_cRef; // M reference count // // Surfboards don't support multiple outbound interfaces // of a given type, so it simply declares single pointers // of each possible type of callback interface // Surfboard // , // // IShutdownNotify *m_pShutdownNotify; ISurfboardUser *m_pSurfer; // to deal with identity relationship of IConnectionPoint, // define an IShutdownNotify-specific nested class + member // // IConnectionPoint, // IShutdownNotify + class XCPShutdownNotify : public IConnectionPoint { Surfboard *This(void); // use fixed offset // // IUnknown methods... // IUnknown... // IConnectionPoint methods... // IConnectionPoint... } m_xcpShutdownNotify; // define an ISurfboardUser-specific nested class + member // IShutdownNotify + class XCPSurfboardUser : public IConnectionPoint { Surfboard *This(void); // use fixed offset // // IUnknown methods... // IUnknown... // IConnectionPoint methods... // IConnectionPoint... } m_xcpSurfboardUser; // IUnknown methods... // IUnknown... // ISurfboard methods... // ISurfboard... // IHazardousDevice methods... // IHazardousDevice... // ISharkBait methods... // ISharkBait... // IConnectionPointContainer methods... // IConnectionPointContainer... };
, Surfboard IConnectionPoint, IShutdownNotify, ISurfboardUser. C++, IConnectionPoint IUnknown IConnectionPoint. , QueryInterface , - .
QueryInterface-pea Surfboard:
STDMETHODIMP Surfboard::QueryInterface(REFIID riid, void**ppv) { if (riid == IID_IUnknown || riid == IID_ISurfboard) *ppv = static_cast<ISurfboard*>(this); else if (riid == IID_IHazardousDevice) *ppv = static_cast< IHazardousDevice *>(this); else if (riid == IID_ISharkBait) *ppv = static_cast<ISharkBait *>(this); else if (riid == IID_IConnectionPointContainer) *ppv = static_cast<IConnectionPointContainer *>(this); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; }
, IConnectionPoint QueryInterface. QueryInterface :
STDMETHODIMP Surfboard::XCPShutdownNotify::QueryInterface(REFIID riid, void**ppv) { if (riid == IID_IUnknown || riid == IID_IConnectionPoint) *ppv = static_cast<IConnectionPoint *>(this); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; }
XCPSurfboardUser. Surfboard , IConnectionPoint .
Surfboard , AddRef Release surfboard:
STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::AddRef(void) { return This()->AddRef(); /* AddRef containing object */ /* AddRef - */ } STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::Release(void) { return This()->Release(); /* Release containing object */ /* Release - */ }
, This - Surfboard, .
IConnectionPoint FindConnectionPoint, Surfboard :
STDMETHODIMP Surfboard::FindConnectionPoint(REFIID riid, IConnectionPoint **ppcp) { if (riid == IID_IShutdownNotify) *ppcp = IID_IShutdownNotify; else if (riid == IID_ISurfboardUser) *ppcp = &m_xcpSurfboardUser; else return (*ppcp = 0), CONNECT_E_NOCONNECTION; (*ppcp)->AddRef(); return S_OK; }
, IConnectionPoint , . QueryInterface. , QueryInterface (inbound) , FindConnectionPoint (outbound) .
IConnectionPoint::Advise IUnknown, 1, Advise QueryInterface , :
STDMETHODIMP Surfboard::XCPShutdownNotify::Advise(IUnknown *pUnk, DWORD *pdwCookie) { assert (pdwCookie && pUnk); *pdwCookie = 0; if (This()->m_pShutdownNotify) // already have one // return CONNECT_E_ADVISELIMIT; // QueryInterface for correct callback type // QueryInterface HRESULT hr = pUnk->QueryInterface(IID_IShutdownNotify, (void**)&(This()->m_pShutdownNotify)); if (hr == E_NOINTERFACE) hr = CONNECT_E_NOCONNECTION; if (SUCCEEDED(hr)) // make up a meaningful cookie // *pdwCookie = DWORD(This()->m_pShutdownNotify); return hr; }
, QueryInterface AddRef, : Surfboard , Advise. , , HRESULT CONNECT_E_NOCONNECTION. QueryInterface - , HRESULT QueryInterface 2.
Advise Unadvise :
STDMETHODIMP Surfboard::XCPShutdownNotify::Unadvise(DWORD dwCookie) { // ensure that the cookie corresponds to a valid connection // , if (DWORD (This()->m_pShutdownNotify) != dwCookie) return CONNECT_E_NOCONNECTION; // release the connection // This()->m_pShutdownNotify->Release(); This()->m_pShutdownNotify = 0; return S_OK; }
IConnectionPoint , :
STDMETHODIMP Surfboard::XCPShutdownNotify::GetConnectionInterface( IID *piid) { assert (piid); // return IID of the interface managed by this subobject // IID , *piid = IID_IShutdownNofify; return S_OK; } STDMETHODIMP Surfboard::XCPShutdownNotify::GetConnectionPointContainer( IConnectionPointContainer **ppcpc) { assert(ppcpc); (*ppcpc = This())->AddRef(); // return containing object // - return S_OK; }
, EnumConnections, . , E_NOTIMPL.
, , IDL [source]:
[uuid(315BC280-DEA7-11d0-8C5E-0080C73925BA) ] coclass Surfboard { [default] interface ISurfboard; interface IHazardousDevice; interface ISharkBait; [source] interface IShutdownNotify; [source, default] interface ISurfboardUser; }
, , (introspectively) :
[object,uuid(B196B283-BAB4-101A-B69C-00AA00341D07) ] interface IProvideClassInfo : Unknown { // return description of object's coclass // HRESULT GetClassInfo([out] ITypeInfo ** ppTI); } [object, uuid(A6BC3AC0-DBAA-11CE-9DE3-00M004BB851) ] interface IProvideClassInfo2 : IProvideClassInfo { typedef enum tagGUIDKIND { GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1 } GUIDKIND; // return IID of default outbound dispinterface // IID HRESULT GetGUID([in] DWORD dwGuidKind, [out] GUID * pGUID); }
:
STDMETHODIMP Surfboard::GetClassInfo(ITypeInfo **ppti) { assert(ppti != 0); ITypeLib *ptl = 0; HRESULT hr = LoadRegTypeLib(LIBID_BeachLib, 1, 0, 0, &ptl); if (SUCCEEDED(hr)) { hr = ptl->GetTypeInfoOfGuid(CLSID_Surfboard, ppti); ptl->Release(); } return hr; } STDMETHODIMP Surfboard::GetGUID (DWORD dwKind, GUID *pguid) { if (dwKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID || !pguid) return E_INVALIDARG; // ISurfboardUser must be defined as a dispinterface // ISurfboardUser *pguid = IID_ISurfboardUser; return S_OK; }
( ), , .
, ISurfboardUser :
[uuid(315BC28A-DEA7-11d0-8C5E-0080C73925BA)] dispinterface ISurfboardUser { methods: [id(1)] void OnTiltingForward( [in] long nAmount); [id(2)] void OnTiltingSideways( [in] long nAmount); }
Visual Basic , , , :
Dim WithEvents sb as Surfboard
Visual Basic . , VariableName_EventName. , iltingForward sb Visual Basic :
Sub sb_OnTiltingForward(ByVal nAmount as Long) MsgBox "The surfboard just tilted forward" End Sub
Visual Basic ISurfboardUser, .
1 . , FindConnectionPoint. , . , , .
2 , , , , .