Discussion:
Events in Managed COM
(too old to reply)
Ken Ross
2010-05-19 18:10:51 UTC
Permalink
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
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.
Post by Ken Ross
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
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;
        }
    }
}
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
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
    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]);
        }
    }
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
       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
Look at the Forms Interop Toolkit. MS has one for VB.NET. There is a
community created one for C#.
--
----
Craig Berntson
Microsoft MVP
Post by Ken Ross
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
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;
}
}
}
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
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
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]);
}
}
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
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...