C# com and c++ event sink

dotnet framework

    Next

  • 1. C# control needs to notify C++ application
    I'm writing a C# control that needs to be able to notify the parent application of certain events. If the application were also using the .NET platform I'd just use a delegate. Unfortunately the application is writen in unmanaged C++. Is there some way for me to send a message or execute a callback from the control that the application can process?
  • 2. how to pass Form handle to unmanaged code
    How can I pass a Windows Form handle to unmanaged DLL that expects HWND? Even if I have a wrapper calss between managed C# and unmanaged C++, IntPtr does not by default cast to HWND. Should I force it? Can somebody give an example? Gregory
  • 3. Opening a word document in rich textbox control in VB.Net
    Hi I am working on a windows application develoed using .Net framework 1.1 in VB.Net.I have a requirement where I need to open a word document in a rich textbox control. I open a new word document ( WordApp = New Word.ApplicationClass) and extract the handle of this document (hWndChild = <Word Process>.MainWindowHandle.ToInt32()). Then I extract the handle of rich textbox ( hWndParent = <RichTextBox>.Handle.ToInt32()) and use the SetParent method to establish a parent child relationship between the two. The code I am using is as under SetParent(hWndChild, hWndParent) <DllImport("user32.dll", EntryPoint:="SetParent", _ SetLastError:=True, CharSet:=CharSet.Unicode, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function SetParent(ByVal hWndChid As Int32, ByVal hWndParent As Int32) As Int32 End Function My problem is when the word window opens is the rich textbox it is minimized. I want to open the window in maximized state. I have tried <WordApp.Documents.Open(<Path>)>.Windows.Application.WindowState = 1 but this does not seem to work. Also I want that the word window should not be closed or minimized explicitly so I want to hide the tite bar of word window. Please help me in resolving these issues. Regards GAUTAM KASHYAP
  • 4. Communication between windows services in .Net and C++ or .Net
    Hi, Is there an example or an 'How To' how the communication between windows services in .Net and C++ or .Net works. In a C++ ATL Service I could expose a COM interface and add methods accessible by any application. Thanks

C# com and c++ event sink

Postby Abhishek » Wed, 06 Dec 2006 21:50:06 GMT

Hi All,

    I am trying to create a C# Com object and call it from unmanaged Cpp. I
have created a call library. I was able to create the interfaces for the
functions & event and call them from cpp code

//in c#

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Diagnostics;
// Outgoing Event Interface which the Sink implements. We'll
// use a dispinterface here so that it remains friendly to
// scripting clients
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITornadoWatchEvents
{
void OnTornadoWarning(int nWindSpeed);
}/* end interface ITornadoWatchEvents */
// Explicit incoming interface containing the methods
// being exposed to COM aware clients
public interface IWeatherNotify {
int WindSpeed { get; set; }
}/* end interface IWeatherNotify */
// Delegate representing the OnTornadoWarning method of the outgoing event 
interface
public delegate void TornadoWarningDelegate(int nWindSpeed);
[ComSourceInterfaces("ITornadoWatchEvents"),
ClassInterface(ClassInterfaceType.None)]
public class WeatherNotify : IWeatherNotify
{
// Indicates Windspeed in Miles Per Hour
private int m_nWindSpeed = 20;
// Define an event associated with the TornadoWarningDelegate
public event TornadoWarningDelegate OnTornadoWarning;
// Constructor
public WeatherNotify() {
}

public int WindSpeed
{
get {
// Return the current Wind speed
return m_nWindSpeed;
}

set {
// Set the WindSpeed to the new value
m_nWindSpeed = value;
// Check if the Wind Speed warrants an event notification
if(value >= 300) {
try {
// Check if the delegate instance for the event exists
if(null != OnTornadoWarning) {
// Twister on the loose. Run for cover !!!.
// Fire the event to all the unmanaged sink handlers
// that have registered for this event.
OnTornadoWarning(m_nWindSpeed);
OnTornadoWarning.Target.GetType().InvokeMember( "OnTornadoWarning", 
BindingFlags.InvokeMethod, null, OnTornadoWarning.Target, new object [] 
{m_nWindSpeed} );
} /* end if */
}/* end try */

catch(Exception ex) {
Trace.WriteLine(ex.Message);
}/* end catch */
}/* end if */
}/* end set */
}/* End WindSpeed Property Accessors */
}/* end class WeatherNotify */



//in cpp
#import "WeatherNotify.tlb"
WeatherNotify::IWeatherNotify *WeatherInterface;
WeatherNotify::ITornadoWatchEvents *WeatherEvents;
WeatherNotify::_TornadoWarningDelegate *WeatherDelegate;


 //calling the function
 WeatherNotify::IWeatherNotifyPtr p2(_uuidof(WeatherNotify::WeatherNotify));
 WeatherInterface = p2;
 WeatherNotify::ITornadoWatchEventsPtr 
q(_uuidof(WeatherNotify::WeatherNotify));
 WeatherEvents = q;
 WeatherNotify::_TornadoWarningDelegatePtr 
r(_uuidof(WeatherNotify::WeatherNotify));
 WeatherDelegate = r;
 WeatherInterface->WindSpeed = 500;


Till this point it is working perfectly and i was able to call the function
without and issue.

Now i need to write the event handling code in the cpp section so that when 
the event is generated it will fire the code. How do i do this? Is there any 
other method of doing this?
Any example would be hugely helpful. Thanks a lot in advance.

Regards
Abhishek 



Similar Threads:

1.Problem with Event sink (ATL C++) when the event source is a C# object

Hello everybody,

I need to send from a C# object events, that have to be caught
in my C++ code. I have followed the instructions from the MSDN article
"Raising Events Handled by a COM Sink", but I have a problem
when I call AtlAdvise in the C++ client: the method FindConnectionPoint
will fail with error CONNECT_E_NOCONNECTION (0x80040200).

So I suppose there is a problem with the connetion point map. I found
in another posting that the event instance name has to be the same as the
interface method, which I did, but with no result.

How can I solve my problem? Stupid ideea: is there any way to define 
(correct)
manually the message map for the C# object, like it was possible in C++?

Many thanks for your help,
Cristian





2.Problem with Event sink (ATL C++) when the event source is a C# ob

Sorry, I forgot to mention that I am an MSDN subscriber, so I would
be pleased to see some "Microsoft" answers.

Regards,
Cristian Marinescu


"Cristian Marinescu" wrote:

> 
> Hello everybody,
> 
> I need to send from a C# object events, that have to be caught
> in my C++ code. I have followed the instructions from the MSDN article
> "Raising Events Handled by a COM Sink", but I have a problem
> when I call AtlAdvise in the C++ client: the method FindConnectionPoint
> will fail with error CONNECT_E_NOCONNECTION (0x80040200).
> 
> So I suppose there is a problem with the connetion point map. I found
> in another posting that the event instance name has to be the same as the
> interface method, which I did, but with no result.
> 
> How can I solve my problem? Stupid ideea: is there any way to define 
> (correct)
> manually the message map for the C# object, like it was possible in C++?
> 
> Many thanks for your help,
> Cristian
> 
> 
> 
> 
> 
> 

3.Catching C# generated events with an ATL COM Sink

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

4.C# Remoted Event Source, COM Event Sink

Hi All,

I'm having trouble figuring this out. I have a C# object, which is
exposed to COM, and fires events. I also have a COM object that can
create the C# object, call DispEventAdvise to be the sink for these
events. This all works fine. Now I want to change it so that instead of
the COM object CoCreating the C# object, I have a C# server which
remotes the object. The COM object uses Activator::GetObject() to get
the remoted object, and then I want to call DispEventAdvise() to set
the COM object as an event sink for the remoted object. I can't get it
to work. DispEventAdvise returns hr = 0x8013150B. I'm assuming that
this should be possible, and help would be greatly appreciated.

My C# object...

using System;
using System.Runtime.InteropServices;

namespace EventSource
{
	public delegate void OnCompleteDelegate();

	// Define event sink interface to be implemented by the COM sink
	[GuidAttribute("7D6A6BB0-C136-4a22-9F84-ABC8603B3D6F") ]
	[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
	public interface IEventTestEvents
	{
		[DispId(0)] void OnComplete();
	}

	[GuidAttribute("88A158C1-896C-467a-B3CC-9F2068093AE2") ]
	[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IEventTest
	{
		void FireCompleteEvent();
	}

	// Connects the event sink interface to a class
	[ComSourceInterfaces(typeof(IEventTestEvents))]
	[ClassInterface(ClassInterfaceType.None)]
	public class EventTest : MarshalByRefObject, IEventTest
	{
		// URL information for remoting this object
		public const String RemotingProtocol = "tcp://";
		public const String RemotingPort = "1234";
		public const String RemotingURI = "EventTestUri";
		public const String RemotingLocal = RemotingProtocol + "localhost" +
":" + RemotingPort + "/" + RemotingURI;
		public const String RemotingRemote = RemotingProtocol + "{0}" + ":" +
RemotingPort + "/" + RemotingURI;

		public event OnCompleteDelegate OnComplete;

		public EventTest()
		{
		}

		public void FireCompleteEvent()
		{
			OnComplete();
		}
	}
}


The code in my COM object where I try to call DispEventAdvise...

EventSource::EventTest* et =
static_cast<EventSource::EventTest*>(System::Activator::GetObject(__typeof(EventSource::EventTest),
EventSource::EventTest::RemotingLocal));
	System::IntPtr iUnknown =
System::Runtime::InteropServices::Marshal::GetIUnknownForObject(et);
	IUnknown* pUnk = (IUnknown*)(void*)iUnknown;
	HRESULT hr = DispEventAdvise(pUnk, &DIID_IEventTestEvents);

Thanks for any help,

Tim.

5.Is this a CCW interop bug: C++ event sink for C# delegate

Hi all,

In the process of investigating interop between .NET and COM, I have
discovered a problem that I am as of yet unable to solve.  Basically,
I am trying to use a .NET delegate as an outbound interface.  I am
able to get the functionality I would expect, but I am also observing
an interface leak.  My .NET COM object is constructed thus:

using System;
using System.Runtime.InteropServices;

namespace CCWTestObject
{
	[ComVisible(false)]
	public delegate void TestEventDelegate(string strMsg);

	[Guid("8138740E-7A5E-4cfe-BE77-328B8EAFEE77")]
	[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
	[ComVisible(true)]
	public interface IComInterfaceEvents
	{
		[DispId(1)]
		void TestEvent(string strMsg);
	}

	[Guid("3967980E-C065-42ca-92C1-46EAE21795C8")]
	[InterfaceType(ComInterfaceType.InterfaceIsDual)]
	public interface _ICOMInterface
	{
		[DispId(1)]
		void FireTestEvent();
	}

	[Guid("6269664E-A0AA-4f1c-936B-6E362679136C")]
	[ClassInterface(ClassInterfaceType.None)]
	[ComSourceInterfaces(typeof(IComInterfaceEvents))]
	[ProgId("CCWTestObject.ICOMInterface")]
	public class ICOMInterface : _ICOMInterface
	{
		public event TestEventDelegate TestEvent;

		public ICOMInterface() {}

		public void FireTestEvent()
		{
			TestEvent("Event fired.");
		}
	};
}

I import the typelib produced from this with #import
"CCWTestObject.tlb" named_guids.

My client is a simple C++ console app.  I'm using ATL to reduce the
complexity.  For the sink event object, I have:

#define TESTEVENT_ID 1

#define DISPID_TESTEVENT 0x00000001

static _ATL_FUNC_INFO OnTestEventInfo = {CC_STDCALL,VT_EMPTY,1,
{VT_BSTR} };

class CTestDotNetEventSink :
	IDispEventImpl<TESTEVENT_ID,CTestDotNetEventSink,
		&CCWTestObject::DIID_IComInterfaceEvents,
		&CCWTestObject::LIBID_CCWTestObject,
		1,0>
{
public:
	BEGIN_SINK_MAP(CTestDotNetEventSink)
		SINK_ENTRY_INFO(TESTEVENT_ID,
			CCWTestObject::DIID_IComInterfaceEvents,
			DISPID_TESTEVENT, OnTestEvent, &OnTestEventInfo)
	END_SINK_MAP()

	CTestDotNetEventSink(CCWTestObject::_ICOMInterface* spDotNetObject)
	{
		m_spDotNetObject = spDotNetObject;
		m_spDotNetObject->AddRef();

		HRESULT hr = DispEventAdvise((IUnknown*)m_spDotNetObject);
		if (FAILED(hr))
		{
			ATLTRACE("Error in Advise.\n");
		}
	}

	~CTestDotNetEventSink(void)
	{
		m_spDotNetObject->Release();
		HRESULT hr = DispEventUnadvise((IUnknown*)m_spDotNetObject);

		if (FAILED(hr))
		{
			ATLTRACE("Error in Unadvise.\n");
		}
	}

	void __stdcall OnTestEvent(BSTR strMsg)
	{
		ATLTRACE(strMsg);
		ATLTRACE("\n");
		SysFreeString(strMsg);
	}

private:
	CCWTestObject::_ICOMInterface* m_spDotNetObject;
};

my main looks like:

int _tmain(int argc, _TCHAR* argv[])
{
	CoInitialize(NULL);

	CCWTestObject::_ICOMInterfacePtr
		spDotNetObject(__uuidof(CCWTestObject::ICOMInterface));

	if (spDotNetObject)
	{
		CTestDotNetEventSink* pTestEvent =
			new
CTestDotNetEventSink((CCWTestObject::_ICOMInterface*)spDotNetObject);

		//spDotNetObject->FireTestEvent();

		delete pTestEvent;
	}

	spDotNetObject = NULL;

	CoUninitialize();

	return 0;
}

Note that I have the call to the FireTestEvent method commented out.
Running this in debug mode with _ATL_DEBUG_INTERFACES defined and
stepping over the line

HRESULT hr = DispEventAdvise((IUnknown*)m_spDotNetObject);

in the CTestDotNetEventSink constructor, I see the following:

QIThunk - 1         	AddRef  :	Object = 0x009d3be0	Refcount = 1
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	AddRef  :	Object = 0x009d3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 2         	AddRef  :	Object = 0x009d3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 2         	AddRef  :	Object = 0x009d3be0	Refcount = 3
IDispEventImpl - IUnknown
QIThunk - 2         	Release :	Object = 0x009d3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 2         	Release :	Object = 0x009d3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 1         	Release :	Object = 0x009d3be0	Refcount = 0
IDispEventImpl - IComInterfaceEvents

When the event sink is destroyed, invoking the DispEventUnadvise,
nothing happens.  When the program exits, I see the following:

ATL: QIThunk - 2         	LEAK    :	Object = 0x009c3be0	Refcount = 1
MaxRefCount = 3	IDispEventImpl - IUnknown
First-chance exception at 0x79e8db38 in CCWTestClient.exe: 0xC0000005:
Access violation reading location 0xfeeefef6.

with the FireThestEvent method uncommented I see:

QIThunk - 1         	AddRef  :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	AddRef  :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 2         	AddRef  :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 2         	AddRef  :	Object = 0x009c3be0	Refcount = 3
IDispEventImpl - IUnknown
QIThunk - 2         	Release :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 2         	Release :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 1         	Release :	Object = 0x009c3be0	Refcount = 0
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	AddRef  :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 3         	AddRef  :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	Release :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 3         	Release :	Object = 0x009c3be0	Refcount = 0
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	AddRef  :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - IUnknown
QIThunk - 4         	AddRef  :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IComInterfaceEvents
QIThunk - 2         	Release :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IUnknown
QIThunk - 4         	AddRef  :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - IComInterfaceEvents
Event fired.
QIThunk - 4         	Release :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - IComInterfaceEvents
ATL: QIThunk - 2         	LEAK    :	Object = 0x009c3be0	Refcount = 1
MaxRefCount = 3	IDispEventImpl - IUnknown
ATL: QIThunk - 4         	LEAK    :	Object = 0x009c3be0	Refcount = 1
MaxRefCount = 2	IDispEventImpl - IComInterfaceEvents
First-chance exception at 0x79e8db38 in CCWTestClient.exe: 0xC0000005:
Access violation reading location 0xfeeefef6.
First-chance exception at 0x79e8db38 in CCWTestClient.exe: 0xC0000005:
Access violation reading location 0xfeeefef6.

Using a standard ATL-based COM server I see (with FireTestEvent method
enabled):

QIThunk - 1         	AddRef  :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - _ICOMInterfaceEvents
QIThunk - 1         	AddRef  :	Object = 0x009c3be0	Refcount = 2
IDispEventImpl - _ICOMInterfaceEvents
Event fired.
QIThunk - 1         	Release :	Object = 0x009c3be0	Refcount = 1
IDispEventImpl - _ICOMInterfaceEvents
QIThunk - 1         	Release :	Object = 0x009c3be0	Refcount = 0
IDispEventImpl - _ICOMInterfaceEvents

I have downloaded a couple of other code examples from the web and
analyzed them as well; they too exhibit this behavior.  So the
question is:  could there be something hinky with my system, or is
this a CCW interop bug?  Or am I missing something here like a
difference in threading models etc.

Other data points of possible interest:

(1) My machine is a pretty "well-used" dev machine -- vs6, 2003, and
2005 installed.
(2) In addition, v1, v1.1, v2, AND v3 of .NET are installed!!
(3) I have run this code on a "v1.1 only" virtual machine with the
same result.

If the code looks okay, I'd appreciate some feedback and/or
independent verification.  Or, obviously, clue me in to my
ignorance! ;-)

Thanks in advance,

Steve

6. ATL Event Sink using C# DLL Event Source

7. C++ Sink Event in C#

8. 80070002 error when interoperating with COM event sink



Return to dotnet framework

 

Who is online

Users browsing this forum: No registered users and 35 guest