Events raised in .net code is does not seem to occur in COM code when deployed with Side by side manifests
After a long time (and several failed attempts) It turned out I could make this work by making one tiny change:
Make the VB6 code compile to P-Code instead of native code.
I'm pretty sure this somehow affects how marshalling between threads is handles, but I've been unable to find any information confirming that theory.
At least it works...
Or Not! (24. October 2013)
It turned out that in real life compiling to P-Code was not enough. In another implementation of this pattern we ended up with the event just disappearing into nowhere, with no exceptions (we thought) and no traces. So more investigation was due:
1. The real issue
Wrapping the event triggering in a try-catch clause revealed that there was in fact an exception being thrown, it just never surfaced anywhere
if (OnHappened != null)
{
try
{
OnHappened(theMessage));
}
catch (Exception e)
{
Messagebox.Show(e.GetType().Name + " : " + e.message)
}
}
The exception was a TargetException (the object does not match the target type)
. Some research revealed that this was most probably a threading issue (as I had suspected earlier.)
2. The solution
Most of the stuff written about this seemed to solve it by using an Invoke method. It turned out that most other people trying to solve this was building winforms application, and thus had a handy Ìnvoke(Delegate)
method available on all forms and controls.
As Winforms also does quite a bit of COM interop behind the scenes (according to now forgotten articles on the google result list) The invoke method is used to ensure that a method call is executed on the thread that created the given component and thus ensure that it happens on the message-pumped UI thread.
I figured this could be relevant for my case aswell, so I cheated.
I made my interop class inherit from the winforms control
public class InteropConnection : Control, IInteropConnection
Now I wrapped my call in the Invoke method
if (OnHappened != null)
{
try
{
Invoke(OnHappened, theMessage);
}
catch (Exception e)
{
Messagebox.Show(e.GetType().Name + " : " + e.message)
}
}
Now I got an exception because the Control had no WindowHandle assigned.
As it turned out the Control class has a handy CreateHandle()
method that can be called and solves this particular issue. (I do not know what possible consequences this has, as the documentation does not recommend calling this method directly.
Now all seems to be working all the time, though I would not be surprised if something new jumps up and bites me now...
I have run into the same issue. COM can marshal the event/call to the correct thread but it needs to have a proxy-stub. These are added to the registry if you use the /tlb
option with regasm, and the equivalent in the manifest file are the elements typelib
and comInterfaceExternalProxyStub
. The VB6 executable can be compiled to a native binary.
For more info see my SO topic: Regfree COM event fails from other thread