ADO Event Instantiation by Language

Microsoft ActiveX Data Objects (ADO)

ADO Event Instantiation by Language

Each programming language creates instances of ADO events differently. All the examples that follow create a ConnectComplete event handler.

Visual Basic

There are two ways to create instances of ADO events in Visual Basic. Both require that the object variable that is declared using the WithEvents keyword be part of a Class module and that the object have scope that is visible to all code in the module. In the first instance, you create an events object and a separate object to work with. (Form objects are Classes in Visual Basic.)

Dim WithEvents connEvent as Connection
Dim conn as New Connection

Private Sub MySub()
    set connEvent = conn        ' Enable event support.
    conn.Open(...)
    ...
    set connEvent = Nothing    ' Disable event support.
    ...
End Sub

Private Sub connEvent_ConnectComplete(ByVal err as ADODB.Error, & _
 adStatus as ADODB.EventStatus, ByVal pConnection as ADODB.Connection)
    ' Check the error object only if adStatus 
    ' equals adStatusErrorsOccurred.
    ...
End Sub

The second uses only a single object.

Dim WithEvents conn as New Connection

Private Sub MySub()
    conn.Open(...)
    ...
    set conn = Nothing    ' Disable event support.
    ...
End Sub

Private Sub conn_ConnectComplete(ByVal err as ADODB.Error, & _
 adStatus as ADODB.EventStatus, ByVal pConnection as ADODB.Connection)
    ' Check the error object only if adStatus 
    ' equals adStatusErrorsOccurred.
    ...
End Sub

Visual C++

This is a schematic description of how to instantiate ADO events in Visual C++. See ADO Events Model Example (Visual C++) for a complete description.

Create classes derived from the ConnectionEventsVt and RecordsetEventsVt interfaces found in file adoint.h.

class CConnEvent : public ConnectionEventsVt
{
    public:
    STDMETHODIMP InfoMessage( 
            ADOError *pError,
            EventStatusEnum *adStatus,
            _ADOConnection *pConnection);
...
}

class CRstEvent : public RecordsetEventsVt 
{
    public:
        STDMETHODIMP WillChangeField( 
                LONG cFields,
                VARIANT Fields,
                EventStatusEnum *adStatus,
                _ADORecordset *pRecordset);
...
}

Implement each of the event handler methods in both classes. It is sufficient that each method merely return an HRESULT of S_OK. However, when you make it known that your event handlers are available, they will be called continuously by default. Instead, you may want to request no further notification after the first time by setting adStatus to adStatusUnwantedEvent.

STDMETHODIMP CConnEvent::ConnectComplete(
            ADOError *pError,
            EventStatusEnum *adStatus,
            _ADOConnection *pConnection) 
        {
        *adStatus = adStatusUnwantedEvent;
        return S_OK;
        }

The event classes inherit from IUnknown, so you must also implement the QueryInterface, AddRef, and Release methods. Also implement class constructors and destructors. Choose the Visual C++ tools with which you are most comfortable that will simplify this part of the task.

Make it known that your event handlers are available by issuing QueryInterface on the Recordset and Connection objects for the IConnectionPointContainer and IConnectionPoint interfaces. Then issue IConnectionPoint::Advise for each class.

For example, assume you are using a Boolean function that returns True if it successfully informs a Recordset object that you have event handlers available.

HRESULT    hr;
DWORD      dwEvtClass;
IConnectionPointContainer    *pCPC = NULL;
IConnectionPoint             *pCP = NULL;
CRstEvent                    *pRStEvent = NULL;
...
_RecordsetPtr                pRs;
pRs.CreateInstance(__uuidof(Recordset));
pRStEvent = new CRstEvent();
if (pRStEvent == NULL) return FALSE;
...
hr = pRs->QueryInterface(IID_IConnectionPointContainer, &pCPC);
if (FAILED(hr)) return FALSE;
hr = pCPC->FindConnectionPoint(IID_ADORecordsetEvents, &pCP);
pCPC->Release();    // Always Release now, even before checking.
if (FAILED(hr)) return FALSE;
hr = pCP->Advise(pRstEvent, &dwEvtClass);    //Turn on event support.
pCP->Release();
if (FAILED(hr)) return FALSE;
...
return TRUE;
...

At this point, events for the RecordsetEvent family are enabled and your methods will be called as Recordset events occur.

Later, when you want to make your event handlers unavailable, get the connection point again and issue the IConnectionPoint::Unadvise method.

...
hr = pCP->UnAdvise(dwEvtClass);    //Turn off event support.
pCP->Release();
if (FAILED(hr)) return FALSE;
...

Of course, you must release interfaces and destroy class objects as is appropriate.

Visual J++

import wfc.data.*;
public class MyClass
{
ConnectionEventHandler handler = 
    new ConnectionEventHandler(this,"onConnectComplete");

    public void onConnectComplete(Object sender,ConnectionEvent e)
    {
        if (e.adStatus == AdoEnums.EventStatus.ERRORSOCCURRED) 
            System.out.println("Connection failed");
        else
            System.out.println("Connection completed");
        return;
    }
    
    void main( void )
    {
        Connection conn = new Connection();
    
        conn.addOnConnectComplete(handler);     // Enable event support.
        conn.open("DSN=Pubs");
        conn.close();
        conn.removeOnConnectComplete(handler);  // Disable event support.
    }
}

Microsoft Visual Basic Scripting Edition

VBScript does not support events.