I'm developing an application for demonstrating Silverlight 4.0 and OpenCL interop. I'm using Silverlight's AutomationFactory to cooperate with
COM inproc-server written in C# 4.
Silverlight app (COM cilent) calls Solve method from COM server, as solving can take some time, it should run in background, for that reason i've prepared COM interface with event for sending results back to silverlight (SL app registers for COM event).
For now everything works fine, call is synchronous, so SL app waits until solving is done, then COM server fires event and successfully sends results to app.
Problem occurs when I try to run solving asynchronously, not to block Silverlight app UI.
Method A: I've been trying asynchronous call only in COM server - solving works fine untill firing event - here I'm getting exception:
System.Reflection.TargetException was caught
Message=Object does not match target type.
Source=mscorlib
StackTrace:
at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at Server.IProblemEngineEvents.ProblemSolvedEvent(String performanceResults)
at Server.ProblemEngine.SendResults(IAsyncResult asyncResult) in ProblemEngine.cs:line 468
This exception (Object does not match target type) seems to be wrong, because event works fine on synchronous call (single thread).
Here is my code:
COM events interface: (Server.IProblemEngineEvents)
[Guid(...),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IProblemEngineEvents
{
[DispId(1)]
void ProblemSolvedEvent(String performanceResults);
}
COM interface: (Server.IProblemEngine)
[Guid(...)]
[ComVisible(true)]
public interface IProblemEngine
{
.....
[DispId(2)]
void Solve(String problemFileName, String datasetFileName);
}
COM Server: (Server.ProblemEngine)
[Guid(...),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IProblemEngineEvents))]
[ComVisible(true)]
public class ProblemEngine : IProblemEngine
{
private delegate SolveResults SolveDelegate(String problemFileName, String datasetFileName);
public event ProblemSolvedDelegate ProblemSolvedEvent;
[ComVisible(true)]
public void Solve(String problemFileName, String datasetFileName)
{
SolveDelegate solveDlgt = new SolveDelegate(InnerSolve);
IAsyncResult result = solveDlgt.BeginInvoke(
problemFileName,
datasetFileName,
new AsyncCallback(SendResults),
solveDlgt);
}
private SolveResults InnerSolve(String problemFileName, String datasetFileName)
{....}
private void SendResults(IAsyncResult asyncResult)
{
...
if (null != this.ProblemSolvedEvent)
{
try
{
this.ProblemSolvedEvent(serializedResults);
}....
}
}
Silverlight app (COM Client, SolverManager.InnerSolve), calling code:
public void InnerSolve()
{
try
{
ProblemEngine.Solve(currentProblemName, currentDatasetFile);
}...
}
Method B: I've also tried background worker in SL app (COM client) to run whole Solve method from COM in background thread - here the exception is as follows:
System.InvalidOperationException was caught
Message=Invalid cross-thread access.
StackTrace:
at MS.Internal.Error.MarshalXresultAsException(UInt32 hr, COMExceptionBehavior comExceptionBehavior)
at MS.Internal.ComAutomation.ComAutomationNative.CheckInvokeHResult(UInt32 hr, String memberName, String exceptionSource, String exceptionDescription, String exceptionHelpFile, UInt32 exceptionHelpContext)
at MS.Internal.ComAutomation.ComAutomationNative.Invoke(Boolean tryInvoke, String memberName, ComAutomationInvokeType invokeType, ComAutomationInteropValue[] rgParams, IntPtr nativePeer, ComAutomationInteropValue& returnValue)
at MS.Internal.ComAutomation.ComAutomationObject.InvokeImpl(Boolean tryInvoke, String name, ComAutomationInvokeType invokeType, Object& returnValue, Object[] args)
at MS.Internal.ComAutomation.ComAutomationObject.Invoke(String name, ComAutomationInvokeType invokeType, Object[] args)
at System.Runtime.InteropServices.Automation.AutomationMetaObjectProvider.TryInvokeMember(InvokeMemberBinder binder, Object[] args, Object& result)
at System.Runtime.InteropServices.Automation.AutomationMetaObjectProviderBase.<.cctor>b__4(Object obj, InvokeMemberBinder binder, Object[] args)
at CallSite.Target(Closure , CallSite , Object , String , String )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2](CallSite site, T0 arg0, T1 arg1, T2 arg2)
at SolverManager.InnerSolve()
Exception is thrown before geting into COM's Solve method.
Code differences for method b:
COM:
...
public class ProblemEngine : IProblemEngine
{
...
[ComVisible(true)]
public void Solve(String problemFileName, String datasetFileName)
{
InnerSolve();
}
private void InnerSolve(String problemFileName, String datasetFileName)
{
SendResults(results);
}
private void SendResults(string results)
{
...
if (null != this.ProblemSolvedEvent)
{
try
{
this.ProblemSolvedEvent(results);
}....
}
}
Silverlight:
public void Init()
{
bw = new System.ComponentModel.BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new System.ComponentModel.DoWorkEventHandler(DoWorkCallback);
bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(RunWorkerCompletedCallback);
bw.RunWorkerAsync();
}
private void DoWorkCallback(object sender, System.ComponentModel.DoWorkEventArgs e)
{
...
InnerSolve();
...
}
public void InnerSolve()
{
try
{
ProblemEngine.Solve(currentProblemName, currentDatasetFile);
}...
}
Again I have no idea what's wrong. What i found is that it is often caused by updating silverlight UI from another thread, but i'm not doing anything like that.
I've been searching solution for few days and found nothing.
I don't know if problem is caused by some aspects of using COM itself or rather some Silverlight's restrictions with threads.
As i said before, everything works fine when not using asynchronous calls or bw.
(COM is registered during installation.)
Any help will be welcome.