Discussion:
Catching C# generated events with an ATL COM Sink
(too old to reply)
dbcarter
2005-07-07 21:01:06 UTC
Permalink
Hi All,
I have been trying for quite some time to generate events in
a managed C# assembly and Sink those events in an ATL COM client.
I have been able to duplicate a phone example from Adam Nathan's book
".NET and COM" where "WithEvents" was used in a VB6 Client.
While the VB6 client works great, I get a First-chance exception
0xE0434F4D (generic COM exception) when I attempt to start my C#
FireEventThread from the COM client, and I never hit a breakpoint
at the start of the COM Sink Invoke method.
So... I know the events are being generated, but they are being
lost somewhere in the CLR managed app. I have included all the
relevant code sections in my experiment below. Is there a code
example that anyone could refer me to that uses ATL COM to sink
C# events, not just the simple VB6 client?

Any help would be greatly appreciated!
Dan Carter


//-------------------------------------------------------------------------
// C# PhoneTest event source
using System;
using System.Runtime.InteropServices;
using System.Threading;

// Source interface with "event handlers" for COM objects to implement
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPhoneEvents
{
void Ring();
}

// Delegate for the event
public delegate void RingEventHandler();

[ComSourceInterfaces(typeof(IPhoneEvents))]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Phone
{
public event RingEventHandler Ring;
public Thread fireMyEventThread;

public void BeginMyFireEventThread()
{
fireMyEventThread = new Thread(new ThreadStart(this.onRing));
fireMyEventThread.Start();
}

public void onRing()
{
int ii = 0;
while (ii < 3)
{
Ring();
Thread.Sleep(1000);
ii++;
}
}
}

//-------------------------------------------------------------------------
Simple VB6 Client that sinks the events as expected:
This works great... I get three pop up msgBoxes

Private WithEvents myPhone As Phone.Phone

Private Sub Form_Load()
Set myPhone = CreateObject("Phone")
End Sub

Private Sub myPhone_Ring()
MsgBox "Ring!"
End Sub

Private Sub Start_Click()
myPhone.BeginMyFireEventThread
End Sub


//-------------------------------------------------------------------------
// COM ATL EVENT SINK CLASS (CPhoneTestSink.h)
// NOTE: CPhoneTestSink.cpp has only the standard Invoke method implemented.

using namespace Phone;

class ATL_NO_VTABLE CPhoneTestSink :
public CComObjectRootEx<CComMultiThreadModel>,
public IDispatch
{
public:

BEGIN_COM_MAP(CPhoneTestSink)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_IID(DIID_IPhoneEvents, IDispatch)
END_COM_MAP()

STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
STDMETHOD(GetTypeInfo)(UINT itinfo,
LCID lcid,
ITypeInfo** pptinfo);
STDMETHOD(GetIDsOfNames)(REFIID riid,
LPOLESTR* rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgdispid);
STDMETHOD(Invoke)(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr);
};


//-------------------------------------------------------------------------
// COM ATL CLIENT SIDE

HRESULT hr;
CComPtr<_Phone> m_pIPhone;
DWORD dwPhoneCookie;
CComPtr<IUnknown> pPhoneUnknown;
IUnknown *pUnkPhoneDispatchSink;
CComObject<CPhoneTestSink> *m_pPhoneEvents;

pPhoneUnknown = NULL;
dwPhoneCookie = NULL;
pUnkPhoneDispatchSink = NULL;
m_pPhoneEvents = NULL;

hr = m_pIPhone.CoCreateInstance(CLSID_Phone, NULL);

// hr is S_OK!

m_pIPhone->QueryInterface(IID_IUnknown,(void **)&m_pPhoneUnknown);

CComObject<CPhoneTestSink>::CreateInstance(&m_pPhoneEvents);
m_pPhoneEvents->QueryInterface(IID_IUnknown,
(void**)&m_pUnkPhoneDispatchSink);

if (m_pUnkPhoneDispatchSink)
{
hr = AtlAdvise(m_pPhoneUnknown,
m_pUnkPhoneDispatchSink,
DIID_IPhoneEvents,
&m_dwPhoneCookie);

// again, hr is S_OK! so AtlAdvise seems happy

}

m_pIPhone->BeginMyFireEventThread();

// I get an exception when I exit this thread

**If you made it this far, thank you!!**
--
dbcarter
dbcarter
2005-08-04 17:40:18 UTC
Permalink
For those of you experiencing the same types of Connection Point problems..
here is how I got the example below to work:

The AtlAdvise will NOT work.. no matter what I tried... and I tried just
about everything!

hr = AtlAdvise(m_pPhoneUnknown,
m_pUnkPhoneDispatchSink,
DIID_IPhoneEvents,
&m_dwPhoneCookie);

Instead, get the Connection point directly...

LPCONNECTIONPOINTCONTAINER pCPC;
LPCONNECTIONPOINT pCP;

hr = m_pIPhone->QueryInterface(IID_IConnectionPointContainer,
(LPVOID*)&pCPC);
hr = pCPC->FindConnectionPoint(DIID_IPhoneEvents, &pCP);
hr = pCP->Advise(m_pPhoneSinkUnk, &m_dwPhoneCookie);

best of luck..
thanks for all the help from the interop community... not
Post by dbcarter
Hi All,
I have been trying for quite some time to generate events in
a managed C# assembly and Sink those events in an ATL COM client.
I have been able to duplicate a phone example from Adam Nathan's book
".NET and COM" where "WithEvents" was used in a VB6 Client.
While the VB6 client works great, I get a First-chance exception
0xE0434F4D (generic COM exception) when I attempt to start my C#
FireEventThread from the COM client, and I never hit a breakpoint
at the start of the COM Sink Invoke method.
So... I know the events are being generated, but they are being
lost somewhere in the CLR managed app. I have included all the
relevant code sections in my experiment below. Is there a code
example that anyone could refer me to that uses ATL COM to sink
C# events, not just the simple VB6 client?
Any help would be greatly appreciated!
Dan Carter
//-------------------------------------------------------------------------
// C# PhoneTest event source
using System;
using System.Runtime.InteropServices;
using System.Threading;
// Source interface with "event handlers" for COM objects to implement
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPhoneEvents
{
void Ring();
}
// Delegate for the event
public delegate void RingEventHandler();
[ComSourceInterfaces(typeof(IPhoneEvents))]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Phone
{
public event RingEventHandler Ring;
public Thread fireMyEventThread;
public void BeginMyFireEventThread()
{
fireMyEventThread = new Thread(new ThreadStart(this.onRing));
fireMyEventThread.Start();
}
public void onRing()
{
int ii = 0;
while (ii < 3)
{
Ring();
Thread.Sleep(1000);
ii++;
}
}
}
//-------------------------------------------------------------------------
This works great... I get three pop up msgBoxes
Private WithEvents myPhone As Phone.Phone
Private Sub Form_Load()
Set myPhone = CreateObject("Phone")
End Sub
Private Sub myPhone_Ring()
MsgBox "Ring!"
End Sub
Private Sub Start_Click()
myPhone.BeginMyFireEventThread
End Sub
//-------------------------------------------------------------------------
// COM ATL EVENT SINK CLASS (CPhoneTestSink.h)
// NOTE: CPhoneTestSink.cpp has only the standard Invoke method implemented.
using namespace Phone;
public CComObjectRootEx<CComMultiThreadModel>,
public IDispatch
{
BEGIN_COM_MAP(CPhoneTestSink)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_IID(DIID_IPhoneEvents, IDispatch)
END_COM_MAP()
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
STDMETHOD(GetTypeInfo)(UINT itinfo,
LCID lcid,
ITypeInfo** pptinfo);
STDMETHOD(GetIDsOfNames)(REFIID riid,
LPOLESTR* rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgdispid);
STDMETHOD(Invoke)(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr);
};
//-------------------------------------------------------------------------
// COM ATL CLIENT SIDE
HRESULT hr;
CComPtr<_Phone> m_pIPhone;
DWORD dwPhoneCookie;
CComPtr<IUnknown> pPhoneUnknown;
IUnknown *pUnkPhoneDispatchSink;
CComObject<CPhoneTestSink> *m_pPhoneEvents;
pPhoneUnknown = NULL;
dwPhoneCookie = NULL;
pUnkPhoneDispatchSink = NULL;
m_pPhoneEvents = NULL;
hr = m_pIPhone.CoCreateInstance(CLSID_Phone, NULL);
// hr is S_OK!
m_pIPhone->QueryInterface(IID_IUnknown,(void **)&m_pPhoneUnknown);
CComObject<CPhoneTestSink>::CreateInstance(&m_pPhoneEvents);
m_pPhoneEvents->QueryInterface(IID_IUnknown,
(void**)&m_pUnkPhoneDispatchSink);
if (m_pUnkPhoneDispatchSink)
{
hr = AtlAdvise(m_pPhoneUnknown,
m_pUnkPhoneDispatchSink,
DIID_IPhoneEvents,
&m_dwPhoneCookie);
// again, hr is S_OK! so AtlAdvise seems happy
}
m_pIPhone->BeginMyFireEventThread();
// I get an exception when I exit this thread
**If you made it this far, thank you!!**
--
dbcarter
knaresh
2010-07-15 05:29:29 UTC
Permalink
Hi carter,

I am experiencing the same problem what you have experienced sinking the .net events in the ATL COM.I was going through the Adam Nathan ".Net and COM" for the solution.but i didn't succeeded. VB6 client is working fine . But i have problems with ATL COM , seems my breakpoint never hit the COM sink event method.
I was seeing your sample,seems you got the solution to the COM Sink problem.

I have some queries regarding this dane,you mentioned ATLAdvise method will not work and try with connection points directly. But my point is, what are LPCONNECTIONPOINTCONTAINER and LPCONNECTIONPOINT supposed to be?Are they natively supported in vc++?

Can you help me with the full COM Code

From http://www.developmentnow.com/g/21_2005_7_0_0_556605/Catching-C-generated-events-with-an-ATL-COM-Sink.ht

Posted via DevelopmentNow.com Group
http://www.developmentnow.com/g/

Loading...