Creación de instancias de eventos de ADO: Visual C++
Se trata de una descripción esquemática de cómo crear instancias de eventos de ADO en Visual C++. Consulte Ejemplo del modelo de eventos de ADO (VC++) para obtener una descripción completa.
Cree clases derivadas de las interfaces ConnectionEventsVt y RecordsetEventsVt que se encuentran en el archivo adoint.h.
// BeginEventExampleVC01
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);
...
}
// EndEventExampleVC01
Implemente cada uno de los métodos del controlador de eventos en ambas clases. Es suficiente que cada método simplemente devuelva un valor HRESULT de S_OK. Sin embargo, cuando se sepa que los controladores de eventos están disponibles, recibirán llamadas constantes de forma predeterminada. En su lugar, es posible que no quiera solicitar ninguna notificación adicional después de la primera; para ello, establezca adStatus en adStatusUnwantedEvent.
// BeginEventExampleVC02
STDMETHODIMP CConnEvent::ConnectComplete(
ADOError *pError,
EventStatusEnum *adStatus,
_ADOConnection *pConnection)
{
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
// EndEventExampleVC02
Las clases de eventos heredan de IUnknown, por lo que también debe implementar los métodos QueryInterface, AddRef y Release. Implemente también constructores y destructores de clases. Elija las herramientas de Visual C++ con las que le resulta más cómodo simplificar esta parte de la tarea.
Notifique que los controladores de eventos están disponibles mediante la emisión de QueryInterface en los objetos Recordset y Connection para las interfaces IConnectionPointContainer e IConnectionPoint. A continuación, emita IConnectionPoint::Advise para cada clase.
Por ejemplo, supongamos que usa una función booleana que devuelve True si informa correctamente a un objeto Recordset que tiene controladores de eventos disponibles.
// BeginEventExampleVC03
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, (LPVOID *)&pCPC);
if (FAILED(hr)) return FALSE;
hr = pCPC->FindConnectionPoint(RecordsetEvents, &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;
...
// EndEventExampleVC03
En este momento, los eventos de la familia RecordsetEvent están habilitados y se llamará a los métodos a medida que se produzcan eventos Recordset.
Más adelante, cuando quiera que los controladores de eventos no estén disponibles, vuelva a obtener el punto de conexión y emita el método IConnectionPoint::Unadvise.
// BeginEventExampleVC04
...
hr = pCP->Unadvise(dwEvtClass); //Turn off event support.
pCP->Release();
if (FAILED(hr)) return FALSE;
...
// EndEventExampleVC04
Debe liberar interfaces y destruir objetos de clase según corresponda.
En el código siguiente se muestra un ejemplo completo de una clase receptora de eventos de Recordset.
// BeginEventExampleVC05.cpp
// compile with: /LD
#include <adoint.h>
class CADORecordsetEvents : public RecordsetEventsVt {
public:
ULONG m_ulRefCount;
CADORecordsetEvents():m_ulRefCount(1){}
STDMETHOD(QueryInterface)(REFIID iid, LPVOID * ppvObject) {
if (IsEqualIID(__uuidof(IUnknown), iid) || IsEqualIID(__uuidof(RecordsetEventsVt), iid)) {
*ppvObject = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() {
return m_ulRefCount++;
}
STDMETHOD_(ULONG, Release)() {
if (--m_ulRefCount == 0) {
delete this;
return 0;
}
else
return m_ulRefCount;
}
STDMETHOD(WillChangeField)( LONG cFields,
VARIANT Fields,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(FieldChangeComplete)( LONG cFields,
VARIANT Fields,
ADOError *pError,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(WillChangeRecord)( EventReasonEnum adReason,
LONG cRecords,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(RecordChangeComplete)( EventReasonEnum adReason,
LONG cRecords,
ADOError *pError,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(WillChangeRecordset)( EventReasonEnum adReason,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(RecordsetChangeComplete)( EventReasonEnum adReason,
ADOError *pError,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(WillMove)( EventReasonEnum adReason,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(MoveComplete)( EventReasonEnum adReason,
ADOError *pError,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(EndOfRecordset)( VARIANT_BOOL *fMoreData,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(FetchProgress)( long Progress,
long MaxProgress,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
STDMETHOD(FetchComplete)( ADOError *pError,
EventStatusEnum *adStatus,
_ADORecordset *pRecordset) {
*adStatus = adStatusUnwantedEvent;
return S_OK;
}
};