+ All Categories
Home > Documents > Connection Points i COM

Connection Points i COM

Date post: 11-Jan-2016
Category:
Upload: joshwa
View: 26 times
Download: 0 times
Share this document with a friend
Description:
Connection Points i COM. Bakgrunn Begrunnelse Bruk. Oversikt over foredrag. Observer pattern Bruk Begrunnelse Variasjoner Løsninger i COM Advise sinks Connection Points Begrunnelse + oversikt Bruk. Noen forutsetninger. Relativt god kjennskap til COM IUnknown IDispatch - PowerPoint PPT Presentation
36
Connection Points i COM Bakgrunn Begrunnelse Bruk
Transcript
Page 1: Connection Points i COM

Connection Points i COM

Bakgrunn

Begrunnelse

Bruk

Page 2: Connection Points i COM

Oversikt over foredrag

Observer pattern– Bruk

– Begrunnelse

– Variasjoner

Løsninger i COM– Advise sinks

– Connection Points• Begrunnelse + oversikt

• Bruk

Page 3: Connection Points i COM

Noen forutsetninger

Relativt god kjennskap til COM– IUnknown– IDispatch– Formål og bruk (løs kobling mellom klient og

tjener, transpartent distribuering)– IEnumXXX interfaces

Page 4: Connection Points i COM

Bakgrunn - Observer

Observer er et av “Patterns” som er beskrevet i Gamma, et al “Design Patterns” [GOF]

Fra Design Patterns:– “Intent: Define a one-to-many dependency between

objects so that when one object changes state, all its dependents are notified and updated automatically.”

Det vil si: Vi ønsker et design der noen objekter (Observers) ønsker å bli informert når “ting skjer” med et annet object (Subject)

Page 5: Connection Points i COM

Observer - 2 (Arkitektur)

Observer har følgende design oversikt i “Design Patterns” (UML Static structure):

Page 6: Connection Points i COM

Observer - 3 (Bruk)

Sekvensdiagram (UML):

Page 7: Connection Points i COM

Observer 4 - faser

Oppkobling– Klienten registerer ønske om å motta informasjon om

hendelser (av en type) fra server

Hendelser– Serveren informerer klienten om ting som har skjedd

Nedkobling– Klienten informerer serveren om at den ikke lenger er

interessert i hendelser.

Page 8: Connection Points i COM

Observer - 5 (Eksempler)

Forhold mellom brukergrensesnitt og “modell”– Gir mulighet for bruk flere klienter mot samme state

uten unødvendig kommunikasjonsoverhead

Brukes i Microsoft’s “Document-View” arkitektur, og i den eldre (og bedre) “Controller-Model-View” arkitekturen.

Kan med fordel brukes i distribuerte systemer .

Page 9: Connection Points i COM

Observer - 6 Varianter

Flere Subjects, Observers, og Events.– Kan modifiseres med et “Subscription” object

– Kan “flates ut” for bruk i f.eks. C. Dette minner endel om Windows’ “WindowProc”

Asynkron oppdatering– Egen(e) tråd(er) for å la Subject oppdatere Observers

Informasjon om state kan sendes med Update Flere varianter til “Update” funksjonen

Page 10: Connection Points i COM

COM og Observer

Observer patternet egner seg godt for distribuert og/eller modulbasert bruk– Mulighet for asynkron oppdatering– Løs kobling (“coupling”) mellom klient og

tjener

Page 11: Connection Points i COM

COM og Observers - Problemer

Hvordan kan en scripting klient/dynamisk klient finne ut Run Time hvilke “Observer” interfaces en “Subject” støtter

Hvordan vil COM’s identitetregler fungere med Detach? (Jeg vet ikke)

Page 12: Connection Points i COM

COM Observer 1: Advise Sink

Den enkleste måten å lage en form for toveis kommunikasjon mellom klient og tjener

Eksempel:[ uuid(…), object, pointer_default(unique) ]interface IAdviseSink : IUnknown{ HRESULT StateIsChanged(IAdviseSource* pSource);};

[ uuid(…), object, pointer_default(unique) ]interface IAdviseSource : IUnknown{ HRESULT Attach(IAdviceSink* pSink); HRESULT Detach(IAdviceSink* pSink); // … + metoder for å endre tilstanden til objektet};

[ uuid(…) ]coclass AdviseSource{ [default] interface IAdviseSource;};

Page 13: Connection Points i COM

Advise Sink - Bruk

Lag en klasse som implementerer IAdviseSink Kall Subject’s IAdviseSource::Subscribe IAdviseSink::StateIsChanged vil bli kalt fra subject når nødvendig Før klientens Advise Sink slettes, kall IAdviseSource::Unsubscribe

class MyAdviseSink : public IAdviseSink{public: MyAdviseSink(IAdviseSource* pSource) : m_pSource(pSource) { m_pSource->Attach(this); } ~MyAdviseSink() { m_pSource->Detach(this); } STDMETHOD(StateIsChanged)(IAdviseSink*) { ::MessageBox(NULL, ”Server state has changed”, ””, MB_OK); }private: CComPtr<IAdviseSource> m_pSource;};

JMB:

Det kan hevdes at det ikke er så lurt å gjøre Attach og Detach i Constructoren og destructoren, ettersom disse funksjonene ikke er gode til å håntere feilsituasjoner.

JMB:

Det kan hevdes at det ikke er så lurt å gjøre Attach og Detach i Constructoren og destructoren, ettersom disse funksjonene ikke er gode til å håntere feilsituasjoner.

Page 14: Connection Points i COM

COM Observer 2: Connection Points (endelig!) Formålet med å bruke Connection Points over

Advise Sinks er hovedsaklig å gi støtte for Script klienter, og for å gi en dynamisk (run time) mulighet for å finne ut hvilke “observers” et objekt støtter.

Problemer som bør nevnes:– Mer komplisert enn Advise Sinks.

– “Unødvendige” kall gir performance hit med distribuert klient/tjener.

Page 15: Connection Points i COM

Connection Points - Interfaces

IConnectionPointContainer IEnumConnectionPoints IConnectionPoint IEnumConnections

I tilfellet med Advise Sinks er det vi som implementerer denne funksjonaliteten.

Page 16: Connection Points i COM

Connection points - Arkitektur

Page 17: Connection Points i COM

Connection Points - Arkitektur 2

En server kan ha flere connection points. En klient kan implementere flere Sources.

Page 18: Connection Points i COM

IConnectionPointContainer

[ object, uuid(…), pointer_default(unique) ]interface IConnectionPointContainer : IUnknown{ HRESULT EnumConnectionPoints ( [out] IEnumConnectionPoints ** ppEnum );

HRESULT FindConnectionPoint ( [in] REFIID riid, [out] IConnectionPoint ** ppCP );};

Page 19: Connection Points i COM

IEnumConnectionPoints

[ object, uuid(...), pointer_default(unique) ]interface IEnumConnectionPoints : IUnknown{ [local] HRESULT Next( [in] ULONG cConnections, [out, size_is(cConnections), length_is(*pcFetched)] IConnectionPoint** ppCP, [out] ULONG * pcFetched ); [call_as(Next)] HRESULT RemoteNext( [in] ULONG cConnections, [out, size_is(cConnections), length_is(*pcFetched)] IConnectionPoint** ppCP, [out] ULONG * pcFetched ); HRESULT Skip( [in] ULONG cConnections ); HRESULT Reset(); HRESULT Clone( [out] IEnumConnectionPoints ** ppEnum );};

Page 20: Connection Points i COM

IConnectionPoint

[ object, uuid(...), pointer_default(unique)]interface IConnectionPoint : IUnknown{ HRESULT GetConnectionInterface( [out] IID * pIID ); HRESULT GetConnectionPointContainer( [out] IConnectionPointContainer ** ppCPC ); HRESULT Advise( [in] IUnknown * pUnkSink, [out] DWORD * pdwCookie ); HRESULT Unadvise( [in] DWORD dwCookie ); HRESULT EnumConnections( [out] IEnumConnections ** ppEnum );};

Page 21: Connection Points i COM

IEnumConnections

[ object, uuid(…), pointer_default(unique) ]interface IEnumConnections : IUnknown{ typedef struct tagCONNECTDATA { IUnknown * pUnk; DWORD dwCookie; } CONNECTDATA;

[local]HRESULT Next( [in] ULONG cConnections, [out, size_is(cConnections), length_is(*pcFetched)]

CONNECTDATA* rgcd, [out] ULONG * pcFetched ); [call_as(Next)] HRESULT RemoteNext( [in] ULONG cConnections, [out, size_is(cConnections), length_is(*pcFetched)] LPCONNECTDATA rgcd, [out] ULONG * pcFetched ); HRESULT Skip([in] ULONG cConnections); HRESULT Reset(); HRESULT Clone([out] IEnumConnections ** ppEnum);};

Page 22: Connection Points i COM

Connection Points - Eksempel

[ uuid(…), object, dual, pointer_default(unique) ]interface IAdviseSink : IDispatch{ HRESULT StateIsChanged(IAdviceSource* pSource);};

[ uuid(…), object, dual, pointer_default(unique) ]interface IAdviseSource : IDispatch{ …};

[ uuid(…) ]coclass AdviseSource{ [default] interface IAdviseSource; [default, source] interface IAdviseSink; interface IConnectionPointContainer;};

Page 23: Connection Points i COM

Connection points og Advise Sinks - Forskjeller Både klient og tjener interface er Dispatch IAdviseSource’s metoder for registrering og

avregistrering er fjernet (Implementert i IConnectionPointContainer med venner)

Page 24: Connection Points i COM

Connection Points - C++ klient

Klient har implementert et objekt med IAdviseSink, og har en peker til en AdviseSource (coclass)

Denne metoden tar ikke hensyn til feilskjekkingDWORD Connect(IAdviseSource* pSource, IAdviseSink *pSink){ CComPtr<IConnectionPointContainer> pCPC; pSource->QueryInterface(__uuidof(IConnectionPointContainer), &pCPC);

CComPtr<IConnectionPoint> pCP; pCPC->FindConnectionPoint(__uuidof(IAdviseSink), &pCP);

DWORD dwCookie; pCP->Advice(pSink, &dwCookie);

return dwCookie;}

Page 25: Connection Points i COM

Connection points - Vurderinger 1

Endel lenger enn AdviseSink tilfellet (ville være en linje: pSource->Subscribe(pSink);)

QueryInterface, FindConnectionPoint og Advice fører alle til kall over nettverket.

I implementasjonen av Advice (eller hver gang IAdviseSource::StateIsChanged kalles), må serveren kalle QueryInterface for å få riktig interface (Advice tar en IUnknown* som argument)

Page 26: Connection Points i COM

Connection points - Vurderinger 2

IConnectionPointContainer og IConnectionPoint gir mulighet til å finne ut mer informasjon dynamisk, f.eks. hvilke Source interfaces som støttes (gjennom IConnectionPointContainer::EnumConnectionPoints og IConnectionPoint::EnumConnections)

Connection points støtter flere former for informasjon (flere connection points). Dette krever mer arbeid i tilfellet med Advise Sinks.

Page 27: Connection Points i COM

Connection Points Implementasjon - Server Implementasjon av Connection Points på en

server er relativt smertefritt med bruk av ATL. – (mk:@MSITStore:<MSDNDIR>\

VCMFC.CHM::/html/_atl_connection_points.htm)

ATL Wizard har støtte for connection points.

Page 28: Connection Points i COM

Connection Points Implementasjon - ATLclass CoAdviseSource : public CComObjectRootEx<CComObjectThreadModel>, public CComCoClass<CoAdviceSource, &CLSID_AdviseSource>, public IConnectionPointContainerImpl<CoAdviseSource>, public IConnectionPointImpl<CoAdviseSource,&IID_IAdviseSink>{public: ... BEGIN_COM_MAP(CoAdviseSource) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(CoAdviseSource) CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink) END_CONNECTION_POINT_MAP()...}; JMB:

De uthevede linjene gjentas for hvert connection point som skal implementeres

JMB:

De uthevede linjene gjentas for hvert connection point som skal implementeres

Page 29: Connection Points i COM

Advise Sinks - Implementasjonclass CoAdviseSource : public CComObjectRootEx<CComObjectThreadModel>, public CComCoClass<CoAdviceSource, &CLSID_AdviseSource> {public: ... BEGIN_COM_MAP(CoAdviseSource) COM_INTERFACE_ENTRY(IAdviseSource) END_COM_MAP()

class CSourceImpl : public IAdviseSink { public: typedef std::list< CComPtr<IAdviceSink> > SinkList;

STDMETHOD(StateIsChanged)(IAdviseSource* pSource); void Attach(IAdviseSink* pSink) { m_pSinkList.push_back(pSink); } HRESULT Detach(IAdviceSink* pSink) { SinkList::iterator it; it = std::find(m_pSinkList.begin(),m_pSinkList.end(), pSink); if ( it == m_pSinkList.end() ) return CONNECT_E_NOCONNECTION; m_pSinkList.erase(it); return S_OK; } private: SinkList m_pSinkList; } m_SourceImpl;

STDMETHOD(Attach)(IAdviceSink* pSink); STDMETHOD(Detach)(IAdviceSink* pSink);};

Page 30: Connection Points i COM

Advise Sink Implementasjon - sende event IAdviseSink:

STDMETHODIMP(CoAdviseSink::SourceImpl::StateIsChanged)(IAdviceSoure* pSource) { SinkList::iterator pSink = m_pSinkList.begin(); while ( pSink != m_pSinkList.end() ) (*pSink++)->StateIsChanged(pSource); return S_OK;}

{ // …

m_SourceImpl->StateIsChanged(this);

}

Page 31: Connection Points i COM

Connection Points ATL Implementasjon - Sende event

CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pCPC(pUnk);

if (!pCPC) return S_OK;

CComPtr<IConnectionPoint> pCP;pCPC->FindConnectionPoint(IID_IAdviseSink, &pCP);

if (!pCP) return S_OK;

CComPtr<IEnumConnections> pEnum;

if (FAILED(pCP->EnumConnections(&pEnum))) return S_OK;

CONNECTDATA cd;while (pEnum->Next(1, &cd, NULL) == S_OK) { if (cd.pUnk) { HRESULT hr = S_OK; CComQIPtr<IPropertyNotifySink, &IID_IAdviseSink> pSink(cd.pUnk); if (pSink) hr = pSink->StateIsChanged(dispID); cd.pUnk->Release();

if (hr == S_FALSE) return S_FALSE; }}return S_OK;

JMB:

Denne koden er hentet fra CFirePropNotifyEvent::FireOnRequestEdit og redigert til vårt formål

JMB:

Denne koden er hentet fra CFirePropNotifyEvent::FireOnRequestEdit og redigert til vårt formål

JMB:

Koden er komplisert, ettersom den ønsker at serveren skal bruke klientens rammeverk. Det er mulig at det allerede finnes enklere måter å gjøre dette på.

JMB:

Koden er komplisert, ettersom den ønsker at serveren skal bruke klientens rammeverk. Det er mulig at det allerede finnes enklere måter å gjøre dette på.

Page 32: Connection Points i COM

Betraktninger

ATL gir endel kode gratis, men gir også endel kompleksitet (tidliger diskusjon)

Det er imidlertid mulig å ha både en ConnectionPoint og en AdviseSink implementasjon av Observer, nemlig:

STDMETHODIMP(CoAdviseSource::Attach)(IAdviseSink* pSink, DWORD* pdwCookie){ typedef IConnectionPointImpl<CoAdviseSource,&IID_IAdviseSink> IAdviseSource; return ((IAdviseSource*)this)->Advise(pSink, pdwCookie);}

JMB:

Signaturen til Attach er modifisert med en Cookie for å ha en enklere mapping til connection points.

JMB:

Signaturen til Attach er modifisert med en Cookie for å ha en enklere mapping til connection points.

Page 33: Connection Points i COM

MSMQ (Preliminary)

Oppkobling:– Klient og tjener åpner den samme køen, uavhengig av hverandre

Events, sende:– Lag et objekt av typen MSMQMessage

– Sett label og body

– Body kan bl.a. være et COM objekt som implementerer IDispatch og IPersistStream eller IPersistStorage.

Events, motta:– Synkron: Kall MSMQQueue::Peek og så MSMQQueue::Receive

– Asynkron: Implementer MSMQEvent’s interface, og kall MSMQQueue::Receive når Arrived blir kalt

Nedkobling:– Klient og tjener kaller MSMQQueue::Close uavhengig av hverandre.

Page 34: Connection Points i COM

Sammenligning

Observer Synkronisitet Avstand Scriptklienter

AdviseSink

Primærtsynkron

Nær tilmiddels

Nei

ConnectionPoints

Primærtsynkron

Nær Ja

MSQM Asynkron Middels tilfjern

?

Page 35: Connection Points i COM

Noen merknader

Connection points vil antageligvis gjennomgå en større endring til COM+. For det meste gjennom endringer i C++ språket i VC++ (versjon 7?)

Advise Sinks går ann å bruke fra VB, men det krever mer arbeid enn Connection points.

Connection points er eneste muligheten fra script klienter. Connection points og Advise Sinks er kompatible, i det minste dersom

man lager sin egen implementasjon. Connection points er velegnet til ”nære” og ”synkrone” ting (f.eks.

Controls) MSMQ er velegnet til ”fjerne” og ”asynkrone” ting.

Page 36: Connection Points i COM

Oppsummering

Formålet med connection points er å åpne for to-veis kommunikasjon mellom klient og tjener i COM.

Den som implementerer tjeneren bestemmer Connection Point (Observer, Advise Sink) interfacet.

Connection points er en noe klønete og ineffektiv implementasjon av Observer Patternet i [GOF].

Dersom man skal støtte script-klienter må man bruke Connection Points, eller er man fri til å bruke en egen løsning, som Advise Sinks.

ATL har en standard implementasjon av Connection Points. Den er imidlertid ikke helt perfekt.


Recommended