Ken Ross
2010-05-19 18:10:51 UTC
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)
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)