ADO Events Model Example (VC++)
The Visual C++ section of ADO Event Instantiation by Language gives a general description of how to instantiate the ADO event model. The following is a specific example of instantiating the event model within the environment created by the #import directive.
The general description uses adoint.h as a reference for method signatures. However, a few details in the general description change slightly as a result of using the #import directive:
- The #import directive resolves typedef's, and method signature data types and modifiers to their fundamental forms.
- The pure virtual methods that must be overwritten are all prefixed by "raw_".
Some of the code simply reflects coding style.
- The pointer to IUnknown used by the Advise method is obtained explicitly with a call to QueryInterface.
- You don't need to explicitly code a destructor in the class definitions.
- You may want to code more robust implementations of QueryInterface, AddRef, and Release.
- The __uuidof() directive is used extensively to obtain interface IDs.
Finally, the example contains some working code.
- The example is written as a console application.
- You should insert your own code under the comment, "
// Do some work
". - All the event handlers default to doing nothing, and canceling further notifications. You should insert the appropriate code for your application, and allow notifications if required.
// eventmodel.cpp : Defines the entry point for the console application. // #import "c:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "EndOfFile") #include <comdef.h> #include <stdio.h> //----The Connection events---------------------------------------------- class CConnEvent : public ConnectionEventsVt { private: ULONG m_cRef; public: CConnEvent() { m_cRef = 0; }; ~CConnEvent() {}; STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_BeginTransComplete( LONG TransactionLevel, struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_CommitTransComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_RollbackTransComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_WillExecute( BSTR *Source, CursorTypeEnum *CursorType, LockTypeEnum *LockType, long *Options, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection); STDMETHODIMP raw_ExecuteComplete( LONG RecordsAffected, struct Error *pError, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection); STDMETHODIMP raw_WillConnect( BSTR *ConnectionString, BSTR *UserID, BSTR *Password, long *Options, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_ConnectComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_Disconnect( EventStatusEnum *adStatus, struct _Connection *pConnection); }; //-----The Recordset events---------------------------------------------- class CRstEvent : public RecordsetEventsVt { private: ULONG m_cRef; public: CRstEvent() { m_cRef = 0; }; ~CRstEvent() {}; STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP raw_WillChangeField( LONG cFields, VARIANT Fields, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_FieldChangeComplete( LONG cFields, VARIANT Fields, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_WillChangeRecord( EventReasonEnum adReason, LONG cRecords, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_RecordChangeComplete( EventReasonEnum adReason, LONG cRecords, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_WillChangeRecordset( EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_RecordsetChangeComplete( EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_WillMove( EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_MoveComplete( EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_EndOfRecordset( VARIANT_BOOL *fMoreData, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_FetchProgress( long Progress, long MaxProgress, EventStatusEnum *adStatus, struct _Recordset *pRecordset); STDMETHODIMP raw_FetchComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset); }; //-----Implement each connection method---------------------------------- STDMETHODIMP CConnEvent::raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_BeginTransComplete( LONG TransactionLevel, struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_CommitTransComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_RollbackTransComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_WillExecute( BSTR *Source, CursorTypeEnum *CursorType, LockTypeEnum *LockType, long *Options, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_ExecuteComplete( LONG RecordsAffected, struct Error *pError, EventStatusEnum *adStatus, struct _Command *pCommand, struct _Recordset *pRecordset, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_WillConnect( BSTR *ConnectionString, BSTR *UserID, BSTR *Password, long *Options, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_ConnectComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CConnEvent::raw_Disconnect( EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; //-----Implement each recordset method----------------------------------- STDMETHODIMP CRstEvent::raw_WillChangeField( LONG cFields, VARIANT Fields, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_FieldChangeComplete( LONG cFields, VARIANT Fields, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_WillChangeRecord( EventReasonEnum adReason, LONG cRecords, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_RecordChangeComplete( EventReasonEnum adReason, LONG cRecords, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_WillChangeRecordset( EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_RecordsetChangeComplete( EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_WillMove( EventReasonEnum adReason, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_MoveComplete( EventReasonEnum adReason, struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_EndOfRecordset( VARIANT_BOOL *fMoreData, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_FetchProgress( long Progress, long MaxProgress, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; STDMETHODIMP CRstEvent::raw_FetchComplete( struct Error *pError, EventStatusEnum *adStatus, struct _Recordset *pRecordset) { *adStatus = adStatusUnwantedEvent; return S_OK; }; //-----Implement QueryInterface, AddRef, and Release--------------------- STDMETHODIMP CRstEvent::QueryInterface(REFIID riid, void ** ppv) { *ppv = NULL; if (riid == __uuidof(IUnknown) || riid == __uuidof(RecordsetEventsVt)) *ppv = this; if (*ppv == NULL) return ResultFromScode(E_NOINTERFACE); AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CRstEvent::AddRef(void) { return ++m_cRef; }; STDMETHODIMP_(ULONG) CRstEvent::Release() { if (0 != --m_cRef) return m_cRef; delete this; return 0; } STDMETHODIMP CConnEvent::QueryInterface(REFIID riid, void ** ppv) { *ppv = NULL; if (riid == __uuidof(IUnknown) || riid == __uuidof(ConnectionEventsVt)) *ppv = this; if (*ppv == NULL) return ResultFromScode(E_NOINTERFACE); AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CConnEvent::AddRef() { return ++m_cRef; }; STDMETHODIMP_(ULONG) CConnEvent::Release() { if (0 != --m_cRef) return m_cRef; delete this; return 0; } //-----Write your main block of code------------------------------------- int main(int argc, char* argv[]) { HRESULT hr; DWORD dwConnEvt; DWORD dwRstEvt; IConnectionPointContainer *pCPC = NULL; IConnectionPoint *pCP = NULL; IUnknown *pUnk = NULL; CRstEvent *pRstEvent = NULL; CConnEvent *pConnEvent= NULL; int rc = 0; _RecordsetPtr pRst; _ConnectionPtr pConn; ::CoInitialize(NULL); hr = pConn.CreateInstance(__uuidof(Connection)); if (FAILED(hr)) return rc; hr = pRst.CreateInstance(__uuidof(Recordset)); if (FAILED(hr)) return rc; // Start using the Connection events hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC); if (FAILED(hr)) return rc; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; pConnEvent = new CConnEvent(); hr = pConnEvent->QueryInterface(__uuidof(IUnknown), (void **) &pUnk); if (FAILED(hr)) return rc; hr = pCP->Advise(pUnk, &dwConnEvt); pCP->Release(); if (FAILED(hr)) return rc; // Start using the Recordset events hr = pRst->QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC); if (FAILED(hr)) return rc; hr = pCPC->FindConnectionPoint(__uuidof(RecordsetEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; pRstEvent = new CRstEvent(); hr = pRstEvent->QueryInterface(__uuidof(IUnknown), (void **) &pUnk); if (FAILED(hr)) return rc; hr = pCP->Advise(pUnk, &dwRstEvt); pCP->Release(); if (FAILED(hr)) return rc; // Do some work pConn->Open("dsn=Pubs;", "MyUserName", "MyPassword", adConnectUnspecified); pRst->Open("SELECT * FROM authors", (IDispatch *) pConn, adOpenStatic, adLockReadOnly, adCmdText); pRst->MoveFirst(); while (pRst->EndOfFile == FALSE) { wprintf(L"Name = '%s'\n", (wchar_t*) ((_bstr_t) pRst->Fields->GetItem("au_lname")->Value)); pRst->MoveNext(); } pRst->Close(); pConn->Close(); // Stop using the Connection events hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **) &pCPC); if (FAILED(hr)) return rc; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; hr = pCP->Unadvise( dwConnEvt ); pCP->Release(); if (FAILED(hr)) return rc; // Stop using the Recordset events hr = pRst->QueryInterface(__uuidof(IConnectionPointContainer), (void **) &pCPC); if (FAILED(hr)) return rc; hr = pCPC->FindConnectionPoint(__uuidof(RecordsetEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; hr = pCP->Unadvise( dwRstEvt ); pCP->Release(); if (FAILED(hr)) return rc; CoUninitialize(); return 1; }