This is for a friend on another forum, here's his question:
Quote:
Anyone here dealt with event trapping in C++? I keep getting a Catastrophic Error on my friggin' Advise statement.
I'm trying to trap the event of an ADO connection object.
Printable View
This is for a friend on another forum, here's his question:
Quote:
Anyone here dealt with event trapping in C++? I keep getting a Catastrophic Error on my friggin' Advise statement.
I'm trying to trap the event of an ADO connection object.
What kind of event trapping? Since C++ has no built-in event system, you must mean that of a third-party library.
Seems to be ADO, so it's ActiveX events. Can't help you there, though.
here's the thread:
http://js-x.com/forum/viewtopic.php?...98bda6397#1529
can you see what should be done?
Allright, maybe you can get the guy to post a bit of code?
He's right, error handling for ActiveX IS easier in VB than C++, but that's because of COM's architecture, not because of C++.
Every ActiveX method has a return value of type HRESULT. VB hides this fact, it uses specially marked parameters as return values instead. However, C++ doesn't hide it. To detect every error you have to check every return value with the SUCCEEDED or the FAILED macro, which tell you if a HRESULT is an error value or not.
Here is some of my code. m_pAdoCon is my ADO connection object. After I create the hADOEventHandle I pass it to WaitForSingleObject where the code waits for the connect to fire.
It would work but it yarfs on my Advise statement.
This code is based upon the ado event trapping example in MSDN.
***.CPP
***.HCode:DWORD dwConnEvt = NULL;
IConnectionPointContainer *pCPC = NULL;
IConnectionPoint *pCP = NULL;
IUnknown *pUnk = NULL;
CConnEvent *pConnEvent= NULL;
int rc = 0;
//ConnectComplete Event for ADO
STDMETHODIMP CConnEvent::raw_ConnectComplete(
struct Error *pError,
ADODB::EventStatusEnum *adStatus,
struct _Connection *pConnection)
{
*adStatus = ADODB::adStatusOK;
SetEvent(hADOEventHandle); //Set the event handle
return S_OK;
};
//Disconnect Event for ADO
STDMETHODIMP CConnEvent::raw_Disconnect(
ADODB::EventStatusEnum *adStatus,
struct _Connection *pConnection)
{
*adStatus = ADODB::adStatusUnwantedEvent;
return S_OK;
};
//QueryInterface Function for CConnEvent
STDMETHODIMP CConnEvent::QueryInterface(REFIID riid, void ** ppv)
{
*ppv = NULL;
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(ADODB::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;
}
......
......
//QueryInterface function is overridden and up above in this code
hr = m_pAdoCon->QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC);
if (FAILED(hr)) return rc;
hr = pCPC->FindConnectionPoint(__uuidof(ADODB::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;
//hADOEventHandle gets set in the raw_ConnectComplete event
pConnEvent->hADOEventHandle = CreateEvent(NULL, false, false, NULL);
if(pConnEvent->hADOEventHandle == NULL)
CBUDNETStdException::BUDNETThrowException(E_FAIL,"Could not open connection.", BudNETMessage);
Thanks for any help you can provide!Code:class CConnEvent :
public CComCoClass<ADODB::ConnectionEventsVt>
{
private:
ULONG m_cRef;
public:
CConnEvent() { m_cRef = 0; };
~CConnEvent() {};
HANDLE hADOEventHandle;
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP raw_ConnectComplete(struct Error *pError, ADODB::EventStatusEnum *adStatus, struct _Connection *pConnection);
STDMETHODIMP raw_Disconnect(ADODB::EventStatusEnum *adStatus, struct _Connection *pConnection);
};
Get me the HRESULT Advise returns, it's in the hr variable directly after the call. It might contain information on the error.
It doesn't even get to the point of returning an HRESULT. It blows up when attempting to execute Advise. It isn't even possible to step into in when debugging.
Now that's really odd. Sorry, don't know then...
OK, well thanks for your efforts anyways.
Alrighty...I'm the guy Acidic was helping over on js-x.com. I got the events working but still with one problem. Everything works great if I use a sychronous connection to the database but I need to use an asynchronous connection.
What happens when I use async is that the ConnectComplete event doesn't fire until I call Close()! Help would be greatly appreciated.
Code:#undef EOF
#import "msado15.dll" rename("EOF","ADOEOF")
HRESULT SetConnectionEvents();
HRESULT ClearConnectionEvents();
HANDLE hADOEventHandle;
ADODB::_ConnectionPtr spConn;
#include "ADOConnEvts.h"
class CCnEvents: public CADOConnectionEvents
{
public:
STDMETHOD(WillConnect)(
BSTR * ConnectionString,
BSTR * UserID,
BSTR * Password,
long * Options,
EventStatusEnum * adStatus,
_ADOConnection *pConnection)
{
OutputDebugString("WillConnect event fired.\n");
return S_OK;
}
STDMETHOD(ConnectComplete)(
ADOError * pError,
EventStatusEnum * adStatus,
_ADOConnection * pConnection)
{
SetEvent(hADOEventHandle);
OutputDebugString("ConnectComplete event fired.\n");
return S_OK;
}
STDMETHOD(Disconnect)(
EventStatusEnum * adStatus,
_ADOConnection * pConnection)
{
OutputDebugString("Disconnect event fired.\n");
return S_OK;
}
};
int main(int argc, char* argv[])
{
DWORD waitRtn = 0;
int x = 0;
CoInitialize(NULL);
spConn.CreateInstance("ADODB.Connection");
hADOEventHandle = CreateEvent(NULL, false, false, NULL);
SetConnectionEvents();
spConn->Open(L"Provider=MSDAORA; Data Source=****;", L"****", L"****", adAsyncConnect);
//spConn->Open(L"DSN=AccessTest", L"", L"", adAsyncConnect);
if (spConn->State != ADODB::adStateOpen)
{
if (spConn->State == ADODB::adStateConnecting)
{
waitRtn = WaitForSingleObject(hADOEventHandle, 15000);
if (spConn->State != ADODB::adStateOpen)
{
spConn->Cancel();//Connection failed
}
else if(waitRtn == WAIT_ABANDONED)
{
spConn->Cancel();//Connection failed
}
else if(waitRtn == WAIT_FAILED)
{
spConn->Cancel();//Connection failed
}
else if(waitRtn == WAIT_OBJECT_0)
{
spConn->Cancel();//Connection failed
}
else if(waitRtn == WAIT_TIMEOUT)
{
spConn->Cancel();//Connection failed
}
}
else
{
//Connection failed
}
}
else
OutputDebugString("Connected.\n");
spConn->Close();
ClearConnectionEvents();
return 0;
}
DWORD gdwEvtClass;
DWORD gdwCnEvents;
HRESULT SetConnectionEvents()
{
IConnectionPointContainer *pCPC = NULL;
IConnectionPoint *pCP = NULL;
HRESULT hr;
hr = spConn->QueryInterface(IID_IConnectionPointContainer, (LPVOID *) &pCPC);
if (FAILED(hr))
return hr;
hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP);
pCPC->Release();
if (FAILED(hr))
return hr;
hr = pCP->Advise(new CCnEvents, &gdwCnEvents);
pCP->Release();
return hr;
}
HRESULT ClearConnectionEvents()
{
IConnectionPointContainer *pCPC = NULL;
IConnectionPoint *pCP = NULL;
HRESULT hr;
hr = spConn->QueryInterface(IID_IConnectionPointContainer, (LPVOID *) &pCPC);
if (FAILED(hr))
return hr;
hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP);
pCPC->Release();
if (FAILED(hr))
return hr;
hr = pCP->Unadvise(gdwCnEvents);
pCP->Release();
return hr;
}