How to receive events from an OLE Automation object

by Theo Albers

When you write your own OLE Automation component in C++ (ATL 3.0 of Microsoft Visual Studio 6+) you will experience the problem that Progress doesn't handle the OLE-events. The "OLE COM"-viewer of Progress is able to show proper events and methods, but the 4GL code simply won't be triggered.

In cooperation with Progress I was able to figure out the problem: when Progress registers for event subscription, it needs to be called back using IDispatch. This is in contrast to other clients like Visual Basic or Windows Scripting Host, which implement the event interface. For more information see the Progress knowledge base entry P56004. For more information on IConnectionPointContainer.Advise() see for instance http:builder.com.com/5100-6373-1050003.html and http:www.techvanguards.com/com/concepts/connectionpoints.asp.

I have attached an ATL sample which shows the usage of a simple OLE component in VB, JavaScript and 4GL. When you want to write your own OLE Automation object, take a look at the Advise() code of MsgQueue.cpp. This is the only part that needs modification when your client is a Progress client.


Override this method to add another check for IDispatch when Progress is calling this method!
STDMETHODIMP CMsgQueue::Advise(IUnknown *pUnk, DWORD *pdwCookie)
{
#ifdef DEBUG_PRINT
AfxMessageBox("In Advise()");
#endif
OK. This function is the important one. This is the place
where we store event sink object for future reference.
HRESULT hr = E_UNEXPECTED;

First we need to make sure that our pointers are valid.
if (0 == pUnk) return E_POINTER;

if (0 == pdwCookie) return E_POINTER;
_IMsgQueueEvents *pEvt = 0;
INTEGER type = 0;

hr = pUnk->QueryInterface(__uuidof(_IMsgQueueEvents), (void **)&pEvt);
if (SUCCEEDED(hr))
{
#ifdef DEBUG_PRINT
AfxMessageBox("Advise()--> sink is IMsgQueueEvents");
#endif
type = 1;
}
else Workaround for Progress, which doesn't implement the event source, but simply provides IDispatch
{
#ifdef DEBUG_PRINT
AfxMessageBox("No");
#endif
hr = pUnk->QueryInterface(__uuidof(IDispatch), (void **)&pEvt);
if (SUCCEEDED(hr))
{
#ifdef DEBUG_PRINT
AfxMessageBox("Advise()--> sink is IDispatch (how do we trust this?)");
#endif
type = 2;
}
else
{
#ifdef DEBUG_PRINT
AfxMessageBox("Advise()--> sink is invalid");
#endif
return CONNECT_E_CANNOTCONNECT;
}
}
Lock();
*pdwCookie = m_vec.Add(pUnk);
hr = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;
Unlock();
if (hr != S_OK)
pUnk->Release();
if (FAILED(hr))
*pdwCookie = 0;
return hr;
}

Attachments

atlqueue.zip : C++ example of working OLE Automation events