Kirjoittaja: Asko Telinen
Kirjoitettu: 18.05.2004 – 18.05.2004
Tagit: koodi näytille, vinkki
Käyttö:
Peri luokkasi CConnectionEventListener tai CRstEventListener luokasta
ja käsittele halutut tapahtumat perityssä luokassa.
Luo uusi ilmentymä CConnEvents tai CRstEvent luokasta,
liitä joko _ConnectionPtr tai _RecordsetPtr luokkiin
(Attach), jolloin
ne rekisteröidään tapahtumien lähteeksi. Poista lähde ennen
luokan tuhoamista (Detach).
ADOEvents.h
////////////////////////////////////////////////////////////////////// // // ADOEvents.h: interface for the CEvents class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_EVENTS_H__A3336C3A_0202_461B_9959_9747D3103A60__INCLUDED_) #define AFX_EVENTS_H__A3336C3A_0202_461B_9959_9747D3103A60__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #pragma warning(disable: 4786) // identifier was truncated to '255' characters in the debug information #pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #pragma warning(disable : 4192) // automatically excluding 'name' while importing type library 'library' // ADO COM library #import <c:\\program files\\common files\\system\\ado\\msado15.dll> no_namespace rename("EOF", "adoEOF") #include <map> #include <vector> typedef std::map<DWORD, DWORD> EVENTMAP; typedef EVENTMAP::iterator EVENTITERATOR; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Connection events listener ( to listen connection events, derive from this class and add listener // to connection manager ) // class CConnectionEventListener //: public CEventListener { public: // event handlers STDMETHOD_(VOID, InfoMessage)(struct Error* pError, EventStatusEnum* adStatus, struct _Connection* pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, WillConnect)(BSTR* ConnectionString, BSTR * UserID, BSTR* Password,long* Options,EventStatusEnum* adStatus, struct _Connection * pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, ConnectComplete)(struct Error* pError,EventStatusEnum* adStatus, struct _Connection* pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, Disconnect)(EventStatusEnum* adStatus, struct _Connection* pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, BeginTransComplete)(LONG TransactionLevel, struct Error* pError, EventStatusEnum* adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, CommitTransComplete)(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, RollbackTransComplete)(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, WillExecute)(BSTR *Source, CursorTypeEnum *CursorType, LockTypeEnum *LockType, long *Options, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, ExecuteComplete)(LONG RecordsAffected, struct Error *pError, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Recordset events listener ( to listen recordset events, derive from this class and add listener // to recordset manager ) // class CRstEventListener //: public CEventListener { public: // event handlers STDMETHOD_(VOID, WillChangeField)(LONG cFields, VARIANT Fields, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, FieldChangeComplete)(LONG cFields,VARIANT Fields,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, WillChangeRecord)(EventReasonEnum adReason,LONG cRecords,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, RecordChangeComplete)(EventReasonEnum adReason,LONG cRecords,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, WillChangeRecordset)(EventReasonEnum adReason,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, RecordsetChangeComplete)(EventReasonEnum adReason,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, WillMove)(EventReasonEnum adReason,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, MoveComplete)(EventReasonEnum adReason,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, EndOfRecordset)(VARIANT_BOOL *fMoreData,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, FetchProgress)(long Progress,long MaxProgress,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } STDMETHOD_(VOID, FetchComplete)(struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // IUnknown interface implemetation for event handlers // template<class EventType> class CEventIUnknownImpl : public EventType { private: ULONG m_ulRefCount; public: CEventIUnknownImpl() : m_ulRefCount(1) { } virtual ~CEventIUnknownImpl() { } STDMETHOD(QueryInterface)(REFIID iid, LPVOID * ppvObject) { if ( ::IsEqualIID(__uuidof(IUnknown), iid) || IsEqualIID(__uuidof(EventType), iid) ) { *ppvObject = this; return S_OK; } return E_NOINTERFACE; } STDMETHOD_(ULONG, AddRef)() { return m_ulRefCount++; } STDMETHOD_(ULONG, Release)() { if ( --m_ulRefCount == 0 ) { delete this; return 0; } return m_ulRefCount; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Container for event listeners // template<class ListenerType> class CListenerContainer { typedef std::vector<ListenerType *> list; typedef list::iterator iterator; private: list m_Listeners; public: CListenerContainer() { } virtual ~CListenerContainer() { Clear(); } STDMETHOD_(long, AddListener)(ListenerType *Listener) { if ( !Listener ) { return -1; } for ( long m = 0; m < m_Listeners.size(); m++ ) { if ( m_Listeners.at(m) == Listener ) { return m; } } m_Listeners.push_back(Listener); return GetListenerCount() - 1; } STDMETHOD_(bool, RemoveListener)(ListenerType *Listener) { for ( long m = 0; m < m_Listeners.size(); m++ ) { if ( m_Listeners.at(m) == Listener ) { m_Listeners.erase(m_Listeners.begin() + m); return true; } } return false; } STDMETHOD_(ListenerType *, GetListener)(long index) { if ( index < 0 || index >= GetListenerCount() ) { return NULL; } return m_Listeners.at(index); } STDMETHOD_(long, GetListener)(ListenerType *Listener) { if ( Listener ) { for ( long m = 0; m < GetListenerCount(); m++ ) { if ( m_Listeners.at(m) == Listener ) { return m; } } } return -1; } STDMETHOD_(long, GetListenerCount)() { return m_Listeners.size(); } STDMETHOD_(void, Clear)() { while ( GetListenerCount() > 0 ) { m_Listeners.erase(m_Listeners.begin()); } } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Event source implementation template<class ClassPtr, class EventClassVt, class EventType> class CEventSourceImpl : public CEventIUnknownImpl<EventClassVt> { protected: EVENTMAP *m_Events; public: CEventSourceImpl() : m_Events(NULL) { m_Events = new EVENTMAP(); } virtual ~CEventSourceImpl() { delete m_Events; } STDMETHOD_(IUnknown *, GetIUnknown)() = 0; STDMETHOD(Attach)(ClassPtr &pItem) { if ( !pItem.GetInterfacePtr() ) { return E_NOINTERFACE; } HRESULT hr = S_OK; IConnectionPointContainer *pCPC = NULL; IConnectionPoint *pCP = NULL; hr = pItem->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC); if ( SUCCEEDED(hr) ) { hr = pCPC->FindConnectionPoint(__uuidof(EventType), &pCP); pCPC->Release(); // Always Release now, even before checking. if ( SUCCEEDED(hr) ) { IUnknown *pUnk = GetIUnknown(); DWORD dwEvtClass = 0; hr = pCP->Advise(pUnk, &dwEvtClass); //Turn on event support. pCP->Release(); if ( SUCCEEDED(hr) ) { DWORD dwKey = (LONG)((VOID *)pItem.GetInterfacePtr()); m_Events->insert(EVENTMAP::value_type(dwKey, dwEvtClass)); CEventIUnknownImpl<EventClassVt>::AddRef(); // Add reference. This will prevent connection object from releasing CConnEvents instance } } } return hr; } STDMETHOD(Detach)(ClassPtr &pItem) { if ( !pItem.GetInterfacePtr() ) { return E_NOINTERFACE; } HRESULT hr = S_OK; IConnectionPointContainer *pCPC = NULL; IConnectionPoint *pCP = NULL; hr = pItem->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC); if ( SUCCEEDED(hr) ) { hr = pCPC->FindConnectionPoint(__uuidof(EventType), &pCP); pCPC->Release(); // Always Release now, even before checking. if ( SUCCEEDED(hr) ) { DWORD dwKey = (LONG)((VOID *)pItem.GetInterfacePtr()); EVENTITERATOR iItem = m_Events->find(dwKey); // Find Item if ( iItem != m_Events->end() ) { hr = pCP->Unadvise(iItem->second); // Connection object decreases reference count } else { hr = E_INVALIDARG; // Connection not found. Return invalid argument } pCP->Release(); } } return hr; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Connection event handler // class CConnEvents : public CListenerContainer<CConnectionEventListener>, public CEventSourceImpl<_ConnectionPtr, ConnectionEventsVt, ConnectionEvents> { public: CConnEvents(); virtual ~CConnEvents(); STDMETHOD_(IUnknown *, GetIUnknown)() { return this; } public: // Event wrappers STDMETHOD(raw_InfoMessage)(struct Error* pError, EventStatusEnum* adStatus, struct _Connection* pConnection); STDMETHOD(raw_WillConnect)(BSTR* ConnectionString, BSTR * UserID, BSTR* Password,long* Options, EventStatusEnum* adStatus, _Connection * pConnection); STDMETHOD(raw_ConnectComplete)(Error* pError,EventStatusEnum* adStatus, _Connection* pConnection); STDMETHOD(raw_Disconnect)(EventStatusEnum* adStatus,_Connection* pConnection); STDMETHOD(raw_BeginTransComplete)(LONG TransactionLevel, struct Error* pError, EventStatusEnum* adStatus, struct _Connection *pConnection); STDMETHOD(raw_CommitTransComplete)(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHOD(raw_RollbackTransComplete)(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHOD(raw_WillExecute)(BSTR *Source, CursorTypeEnum *CursorType, LockTypeEnum *LockType, long *Options, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection); STDMETHOD(raw_ExecuteComplete)(LONG RecordsAffected, struct Error *pError, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection); }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // recordset event handler // class CRstEvents : public CListenerContainer<CRstEventListener>, public CEventSourceImpl<_RecordsetPtr, RecordsetEventsVt, RecordsetEvents> { public: CRstEvents(); virtual ~CRstEvents(); STDMETHOD_(IUnknown *, GetIUnknown)() { return this; } public: STDMETHOD(raw_WillChangeField)(LONG cFields, VARIANT Fields, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHOD(raw_FieldChangeComplete)(LONG cFields,VARIANT Fields,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_WillChangeRecord)(EventReasonEnum adReason,LONG cRecords,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_RecordChangeComplete)(EventReasonEnum adReason,LONG cRecords,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_WillChangeRecordset)(EventReasonEnum adReason,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_RecordsetChangeComplete)(EventReasonEnum adReason,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_WillMove)(EventReasonEnum adReason,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_MoveComplete)(EventReasonEnum adReason,struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_EndOfRecordset)(VARIANT_BOOL *fMoreData,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_FetchProgress)(long Progress,long MaxProgress,EventStatusEnum *adStatus,struct _Recordset *pRecordset); STDMETHOD(raw_FetchComplete)(struct Error *pError,EventStatusEnum *adStatus,struct _Recordset *pRecordset); }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif // !defined(AFX_EVENTS_H__A3336C3A_0202_461B_9959_9747D3103A60__INCLUDED_)
ADOEvents.cpp
////////////////////////////////////////////////////////////////////// // // Events.cpp: implementation of the CEvents class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ADOEvents.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Connection event handler // CConnEvents::CConnEvents() { } CConnEvents::~CConnEvents() { } // Error event STDMETHODIMP CConnEvents::raw_InfoMessage(struct Error* pError, EventStatusEnum* adStatus, struct _Connection* pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->InfoMessage(pError, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } // Connection events STDMETHODIMP CConnEvents::raw_WillConnect(BSTR* ConnectionString, BSTR * UserID, BSTR* Password,long* Options, EventStatusEnum* adStatus, _Connection * pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillConnect(ConnectionString, UserID, Password, Options, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_ConnectComplete(Error* pError,EventStatusEnum* adStatus, _Connection* pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->ConnectComplete(pError, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } // Disconnect STDMETHODIMP CConnEvents::raw_Disconnect(EventStatusEnum* adStatus,_Connection* pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->Disconnect(adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_BeginTransComplete(LONG TransactionLevel, struct Error* pError, EventStatusEnum* adStatus, struct _Connection *pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->BeginTransComplete(TransactionLevel, pError, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_CommitTransComplete(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->CommitTransComplete(pError, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_RollbackTransComplete(struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->RollbackTransComplete(pError, adStatus, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_WillExecute(BSTR *Source, CursorTypeEnum *CursorType, LockTypeEnum *LockType, long *Options, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillExecute(Source, CursorType, LockType, Options, adStatus, pCommand, pRecordset, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; } STDMETHODIMP CConnEvents::raw_ExecuteComplete(LONG RecordsAffected, struct Error *pError, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->ExecuteComplete(RecordsAffected, pError, adStatus, pCommand, pRecordset, pConnection); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Recordset event listener // CRstEvents::CRstEvents() { } CRstEvents::~CRstEvents() { } // Event handlers STDMETHODIMP CRstEvents::raw_WillChangeField(LONG cFields, VARIANT Fields, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillChangeField(cFields, Fields, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_FieldChangeComplete(LONG cFields, VARIANT Fields, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->FieldChangeComplete(cFields, Fields, pError, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_WillChangeRecord(EventReasonEnum adReason, LONG cRecords, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillChangeRecord(adReason, cRecords, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_RecordChangeComplete(EventReasonEnum adReason, LONG cRecords, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->RecordChangeComplete(adReason, cRecords, pError, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_WillChangeRecordset(EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillChangeRecordset(adReason, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_RecordsetChangeComplete(EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->RecordsetChangeComplete(adReason, pError, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_WillMove(EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->WillMove(adReason, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_MoveComplete(EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->MoveComplete(adReason, pError, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_EndOfRecordset(VARIANT_BOOL *fMoreData, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->EndOfRecordset(fMoreData, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_FetchProgress(long Progress, long MaxProgress, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->FetchProgress(Progress, MaxProgress, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; STDMETHODIMP CRstEvents::raw_FetchComplete(struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { for ( LONG m = 0; m < GetListenerCount(); m++ ) { GetListener(m)->FetchComplete(pError, adStatus, pRecordset); } if ( GetListenerCount() == 0 ) { *adStatus = adStatusUnwantedEvent; } return S_OK; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////
Ihan hyvä vinkki.
Tarpeellinen niille, jotka harkitsevat perinpohjaisen windowsohjelmoinnin aloittamista.
Vinkki ei ehkä ole niin tarpeellinen kuitenkaan peli/demo/grafiikka koodaajille.