ADO Events Model Example (VC++)

Microsoft ActiveX Data Objects (ADO)

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;", "sa", "", 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;
}