Discussion:
Events in Managed COM
(too old to reply)
Ken Ross
2010-05-19 18:10:51 UTC
Permalink
Raw Message
We've created a COM component in C# which needs to be able to raise
events to a managed code consumer of the COM component (Silverlight 4 in
this case). We can call methods on the COM component just fine but when
we try to register the event handler it throws and gives an error
indicating it can't find the event we're specifying.

As an asside, it would be GREAT to be able to test this outside of SL
with a console app or unit test, but when we try to reference the
managed COM component from a non-Silverlight managed client, the IDE
barks and tells us to just add a reference to the assembly [instead of
using COM].

Here's the code we're using to defne the event on the COM component
side:

namespace DeviceCom
{
public delegate void DeviceEventHandler(object sender,
DeviceEventArgs e);

public class DeviceEventArgs : EventArgs
{
public string Data { get; set; }

public DeviceEventArgs() { }

public DeviceEventArgs(string data)
{
Data = data;
}
}
}


The event Interface looks like this:

namespace DeviceCom
{
[Guid("7E1E5F7D-3303-4A15-8025-CB8458AF1949"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IDeviceComEvents
{
event DeviceEventHandler LeftLineDataReceived;
}
}


The COM object that raises the event (and implements the above
interface):

namespace DeviceCom
{
[Guid("38814898-A470-42DE-AD21-9AB29B5A536E"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IDeviceComEvents))]
public class DeviceComManager : DeviceCom.IDeviceComManager
{
public DeviceComManager() { }

public void InitializeDevices()
{
DeviceInformation deviceInfo = new DeviceInformation("Left
Line Pin",
"COM3,9600,N,8,1",
"/HORIZON",
false, 1, 1, true, CommunicationStyles.Horizon,
DeviceManager.CashDrawerType.None);

List<DeviceInformation> deviceList = new
List<DeviceInformation>(); deviceList.Add(deviceInfo);

DeviceManager.InitializeDevices(deviceList);
DeviceManager.LeftLineDataReceived +=new
DeviceManager.LeftLineDataReceivedEventHandler(DeviceManager_
LeftLineDataReceived);

}

public string HelloWorld()
{
return "Hello World";
}

private void DeviceManager_LeftLineDataReceived(object sender,
DeviceArgs e) {
LeftLineDataReceived(this, new
DeviceEventArgs(e.DataReceived));
}

public event DeviceEventHandler LeftLineDataReceived;
}
}


And here's the line that throws when we try to handle the event on the
Silverlight side:

public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
Go();
}

private void Go()
{
dynamic device =
AutomationFactory.CreateObject("DeviceCom.DeviceComManager");
device.InitializeDevices();

AutomationEvent hzDeviceEvent =
AutomationFactory.GetEvent(device, "LeftLineDataReceived");

//****>> This next line throws!
hzDeviceEvent.EventRaised += (sender, e) =>
{
MessageBox.Show((string)e.Arguments[0]);
};

string hw = device.HelloWorld();
if (hw != null)
{
MessageBox.Show(hw);
}
}

void hzDeviceEvent_EventRaised(object sender,
AutomationEventArgs e) {
MessageBox.Show((string)e.Arguments[0]);
}

}


Lastly, here is the exception that the above event registration throws:

System.Exception was unhandled by user code
Message=Failed to add event handler. Possible reasons include: the
object does not support this or any events, or something failed while
adding the event. StackTrace:
at MS.Internal.Error.MarshalXresultAsException(UInt32 hr,
COMExceptionBehavior comExceptionBehavior) at
MS.Internal.XcpImports.CheckHResult(UInt32 hr) at
MS.Internal.ComAutomation.ComAutomationNative.ConnectEvent(IntPtr
nativePeer, String eventName, RaiseComAutomationEventDelegate
raiseComAutomationEventDelegate) at
MS.Internal.ComAutomation.ComAutomationObject.ConnectEvent(String
name) at
System.Runtime.InteropServices.Automation.AutomationEvent.UpdateCo
nnection() at
System.Runtime.InteropServices.Automation.AutomationEvent.add_Even
tRaised(EventHandler`1 value) at
SilverlightApplication1.MainPage.Go() at
SilverlightApplication1.MainPage.Button_Click(Object sender,
RoutedEventArgs e) at
System.Windows.Controls.Primitives.ButtonBase.OnClick() at
System.Windows.Controls.Button.OnClick() at
System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(
MouseButtonEventArgs e) at
System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl,
EventArgs e) at MS.Internal.JoltHelper.FireEvent(IntPtr
unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex,
String eventName)
TDC
2010-05-20 20:00:03 UTC
Permalink
Raw Message
On your aside, you must have tried to add a ref to the tlb exported
from your .NET based COM component from Visual Studio. The tlb
exported from .NET contains a flag that states it came from .NET. If
you are trying to test your .NET COM object from a real COM client,
try a simple VBScript or VB6 program.



On May 19, 2:10 pm, Ken Ross <***@horizonsoftware.com> wrote:
> We've created a COM component in C# which needs to be able to raise
> events to a managed code consumer of the COM component (Silverlight 4 in
> this case). We can call methods on the COM component just fine but when
> we try to register the event handler it throws and gives an error
> indicating it can't find the event we're specifying.
>
> As an asside, it would be GREAT to be able to test this outside of SL
> with a console app or unit test, but when we try to reference the
> managed COM component from a non-Silverlight managed client, the IDE
> barks and tells us to just add a reference to the assembly [instead of
> using COM].
>
> Here's the code we're using to defne the event on the COM component
> side:
>
> namespace DeviceCom
> {
>     public delegate void DeviceEventHandler(object sender,
>     DeviceEventArgs e);
>
>     public class DeviceEventArgs : EventArgs
>     {
>         public string Data { get; set; }
>
>         public DeviceEventArgs() { }
>
>         public DeviceEventArgs(string data)
>         {
>             Data = data;
>         }
>     }
>
> }
>
> The event Interface looks like this:
>
> namespace DeviceCom
> {
>     [Guid("7E1E5F7D-3303-4A15-8025-CB8458AF1949"),
>     InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
>     public interface IDeviceComEvents
>     {
>         event DeviceEventHandler LeftLineDataReceived;
>     }
>
> }
>
> The COM object that raises the event (and implements the above
> interface):
>
> namespace DeviceCom
> {
>     [Guid("38814898-A470-42DE-AD21-9AB29B5A536E"),
>     ClassInterface(ClassInterfaceType.None),
>     ComSourceInterfaces(typeof(IDeviceComEvents))]
>     public class DeviceComManager : DeviceCom.IDeviceComManager
>     {
>         public DeviceComManager() { }
>
>         public void InitializeDevices()
>         {
>             DeviceInformation deviceInfo = new DeviceInformation("Left
>             Line Pin",
>                 "COM3,9600,N,8,1",
>                 "/HORIZON",
>                 false, 1, 1, true, CommunicationStyles.Horizon,
>                 DeviceManager.CashDrawerType.None);
>
>             List<DeviceInformation> deviceList = new
>             List<DeviceInformation>(); deviceList.Add(deviceInfo);
>
>             DeviceManager.InitializeDevices(deviceList);
>             DeviceManager.LeftLineDataReceived +=new
>             DeviceManager.LeftLineDataReceivedEventHandler(DeviceManager_
>             LeftLineDataReceived);
>
>         }
>
>         public string HelloWorld()
>         {
>             return "Hello World";
>         }
>
>         private void DeviceManager_LeftLineDataReceived(object sender,
>         DeviceArgs e) {
>             LeftLineDataReceived(this, new
>             DeviceEventArgs(e.DataReceived));
>         }
>
>         public event DeviceEventHandler LeftLineDataReceived;
>     }
>
> }
>
> And here's the line that throws when we try to handle the event on the
> Silverlight side:
>
>     public partial class MainPage : UserControl
>     {
>         public MainPage()
>         {
>             InitializeComponent();
>         }
>
>         private void Button_Click(object sender, RoutedEventArgs e)
>         {
>             Go();
>         }
>
>         private void Go()
>         {
>             dynamic device =
>             AutomationFactory.CreateObject("DeviceCom.DeviceComManager");
>             device.InitializeDevices();
>
>             AutomationEvent hzDeviceEvent =
>             AutomationFactory.GetEvent(device, "LeftLineDataReceived");
>
> //****>> This next line throws!
>             hzDeviceEvent.EventRaised += (sender, e) =>
>             {
>                 MessageBox.Show((string)e.Arguments[0]);
>             };
>
>             string hw = device.HelloWorld();
>             if (hw != null)
>             {
>                 MessageBox.Show(hw);
>             }
>         }
>
>         void hzDeviceEvent_EventRaised(object sender,
>         AutomationEventArgs e) {
>             MessageBox.Show((string)e.Arguments[0]);
>         }
>
>     }
>
> Lastly, here is the exception that the above event registration throws:
>
> System.Exception was unhandled by user code
>   Message=Failed to add event handler. Possible reasons include: the
>   object does not support this or any events, or something failed while
>   adding the event. StackTrace:
>        at MS.Internal.Error.MarshalXresultAsException(UInt32 hr,
>        COMExceptionBehavior comExceptionBehavior) at
>        MS.Internal.XcpImports.CheckHResult(UInt32 hr) at
>        MS.Internal.ComAutomation.ComAutomationNative.ConnectEvent(IntPtr
>        nativePeer, String eventName, RaiseComAutomationEventDelegate
>        raiseComAutomationEventDelegate) at
>        MS.Internal.ComAutomation.ComAutomationObject.ConnectEvent(String
>        name) at
>        System.Runtime.InteropServices.Automation.AutomationEvent.UpdateCo
>        nnection() at
>        System.Runtime.InteropServices.Automation.AutomationEvent.add_Even
>        tRaised(EventHandler`1 value) at
>        SilverlightApplication1.MainPage.Go() at
>        SilverlightApplication1.MainPage.Button_Click(Object sender,
>        RoutedEventArgs e) at
>        System.Windows.Controls.Primitives.ButtonBase.OnClick() at
>        System.Windows.Controls.Button.OnClick() at
>        System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(
>        MouseButtonEventArgs e) at
>        System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl,
>        EventArgs e) at MS.Internal.JoltHelper.FireEvent(IntPtr
>        unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex,
>        String eventName)
Craig Berntson
2010-05-24 15:35:22 UTC
Permalink
Raw Message
Look at the Forms Interop Toolkit. MS has one for VB.NET. There is a
community created one for C#.

--

----
Craig Berntson
Microsoft MVP

"Ken Ross" <***@horizonsoftware.com> wrote in message
news:***@207.46.248.16...
> We've created a COM component in C# which needs to be able to raise
> events to a managed code consumer of the COM component (Silverlight 4 in
> this case). We can call methods on the COM component just fine but when
> we try to register the event handler it throws and gives an error
> indicating it can't find the event we're specifying.
>
> As an asside, it would be GREAT to be able to test this outside of SL
> with a console app or unit test, but when we try to reference the
> managed COM component from a non-Silverlight managed client, the IDE
> barks and tells us to just add a reference to the assembly [instead of
> using COM].
>
> Here's the code we're using to defne the event on the COM component
> side:
>
> namespace DeviceCom
> {
> public delegate void DeviceEventHandler(object sender,
> DeviceEventArgs e);
>
> public class DeviceEventArgs : EventArgs
> {
> public string Data { get; set; }
>
> public DeviceEventArgs() { }
>
> public DeviceEventArgs(string data)
> {
> Data = data;
> }
> }
> }
>
>
> The event Interface looks like this:
>
> namespace DeviceCom
> {
> [Guid("7E1E5F7D-3303-4A15-8025-CB8458AF1949"),
> InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
> public interface IDeviceComEvents
> {
> event DeviceEventHandler LeftLineDataReceived;
> }
> }
>
>
> The COM object that raises the event (and implements the above
> interface):
>
> namespace DeviceCom
> {
> [Guid("38814898-A470-42DE-AD21-9AB29B5A536E"),
> ClassInterface(ClassInterfaceType.None),
> ComSourceInterfaces(typeof(IDeviceComEvents))]
> public class DeviceComManager : DeviceCom.IDeviceComManager
> {
> public DeviceComManager() { }
>
> public void InitializeDevices()
> {
> DeviceInformation deviceInfo = new DeviceInformation("Left
> Line Pin",
> "COM3,9600,N,8,1",
> "/HORIZON",
> false, 1, 1, true, CommunicationStyles.Horizon,
> DeviceManager.CashDrawerType.None);
>
> List<DeviceInformation> deviceList = new
> List<DeviceInformation>(); deviceList.Add(deviceInfo);
>
> DeviceManager.InitializeDevices(deviceList);
> DeviceManager.LeftLineDataReceived +=new
> DeviceManager.LeftLineDataReceivedEventHandler(DeviceManager_
> LeftLineDataReceived);
>
> }
>
> public string HelloWorld()
> {
> return "Hello World";
> }
>
> private void DeviceManager_LeftLineDataReceived(object sender,
> DeviceArgs e) {
> LeftLineDataReceived(this, new
> DeviceEventArgs(e.DataReceived));
> }
>
> public event DeviceEventHandler LeftLineDataReceived;
> }
> }
>
>
> And here's the line that throws when we try to handle the event on the
> Silverlight side:
>
> public partial class MainPage : UserControl
> {
> public MainPage()
> {
> InitializeComponent();
> }
>
> private void Button_Click(object sender, RoutedEventArgs e)
> {
> Go();
> }
>
> private void Go()
> {
> dynamic device =
> AutomationFactory.CreateObject("DeviceCom.DeviceComManager");
> device.InitializeDevices();
>
> AutomationEvent hzDeviceEvent =
> AutomationFactory.GetEvent(device, "LeftLineDataReceived");
>
> //****>> This next line throws!
> hzDeviceEvent.EventRaised += (sender, e) =>
> {
> MessageBox.Show((string)e.Arguments[0]);
> };
>
> string hw = device.HelloWorld();
> if (hw != null)
> {
> MessageBox.Show(hw);
> }
> }
>
> void hzDeviceEvent_EventRaised(object sender,
> AutomationEventArgs e) {
> MessageBox.Show((string)e.Arguments[0]);
> }
>
> }
>
>
> Lastly, here is the exception that the above event registration throws:
>
> System.Exception was unhandled by user code
> Message=Failed to add event handler. Possible reasons include: the
> object does not support this or any events, or something failed while
> adding the event. StackTrace:
> at MS.Internal.Error.MarshalXresultAsException(UInt32 hr,
> COMExceptionBehavior comExceptionBehavior) at
> MS.Internal.XcpImports.CheckHResult(UInt32 hr) at
> MS.Internal.ComAutomation.ComAutomationNative.ConnectEvent(IntPtr
> nativePeer, String eventName, RaiseComAutomationEventDelegate
> raiseComAutomationEventDelegate) at
> MS.Internal.ComAutomation.ComAutomationObject.ConnectEvent(String
> name) at
> System.Runtime.InteropServices.Automation.AutomationEvent.UpdateCo
> nnection() at
> System.Runtime.InteropServices.Automation.AutomationEvent.add_Even
> tRaised(EventHandler`1 value) at
> SilverlightApplication1.MainPage.Go() at
> SilverlightApplication1.MainPage.Button_Click(Object sender,
> RoutedEventArgs e) at
> System.Windows.Controls.Primitives.ButtonBase.OnClick() at
> System.Windows.Controls.Button.OnClick() at
> System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(
> MouseButtonEventArgs e) at
> System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl,
> EventArgs e) at MS.Internal.JoltHelper.FireEvent(IntPtr
> unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex,
> String eventName)
Loading...