Silverlight 4 COM互操作-线程和COM事件的问题 [英] Silverlight 4 COM interop - problem with threads and COM event

查看:123
本文介绍了Silverlight 4 COM互操作-线程和COM事件的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个用于演示Silverlight 4.0和OpenCL互操作的应用程序.我正在使用Silverlight的AutomationFactory与用C#4编写的 COM inproc-server 合作. Silverlight应用程序(COM cilent)从COM服务器调用Solve方法,因为求解可能需要一些时间,它应该在后台运行,因此我已经准备了带有事件的COM接口,用于将结果发送回Silverlight(SL应用程序为COM注册)事件).
现在一切正常,调用是同步的,因此SL app等待解决,然后COM服务器触发事件​​并成功将结果发送到app.

当我尝试以异步方式运行求解而不是阻止Silverlight应用程序UI时出现问题.
方法A:我一直在尝试仅在COM服务器中进行异步调用-解决工作正常,直到触发事件-在这里我遇到了异常:

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

br/> 此异常(对象与目标类型不匹配)似乎是错误的,因为事件在同步调用(单线程)上可以正常工作.

这是我的代码:

COM事件接口:(Server.IProblemEngineEvents)


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接口:(Server.IProblemEngine)


COM interface: (Server.IProblemEngine)

[Guid(...)]
[ComVisible(true)]
public interface IProblemEngine
{
    .....
    [DispId(2)]
    void Solve(String problemFileName, String datasetFileName);
}


COM服务器:(Server.ProblemEngine)


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)]
    // entry point
    public void Solve(String problemFileName, String datasetFileName)
    {
        // asynchronous call
        SolveDelegate solveDlgt = new SolveDelegate(InnerSolve);
        IAsyncResult result = solveDlgt.BeginInvoke(
            problemFileName,
            datasetFileName,
            new AsyncCallback(SendResults),
            solveDlgt);
    }

    // doing some calculations and returns results
    private SolveResults InnerSolve(String problemFileName, String datasetFileName)
    {....}

    // callback method called after solving is finished
    // this callback is still in new thread
    private void SendResults(IAsyncResult asyncResult)
    {
        ...
        if (null != this.ProblemSolvedEvent)
        {
            try
            {
                // HERE comes exception
                // System.Reflection.TargetException was caught
                //  Object does not match target type.
                this.ProblemSolvedEvent(serializedResults);
            }....
         }
    }


Silverlight应用程序(COM客户端,SolverManager.InnerSolve),调用代码:


Silverlight app (COM Client, SolverManager.InnerSolve), calling code:

public void InnerSolve()
{
    try
    {
        // ProblemEngine is dynamic COM object reference from AutomationFactory
        ProblemEngine.Solve(currentProblemName, currentDatasetFile);
    }...
}



方法B:我还尝试了SL应用程序(COM客户端)中的后台工作程序在后台线程中从COM运行整个Solve方法-这里的异常如下:



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()


进入COM的Solve方法之前会引发异常.

方法b的代码差异:
COM:


Exception is thrown before geting into COM''s Solve method.

Code differences for method b:
COM:

...
public class ProblemEngine : IProblemEngine
{
   ...
    [ComVisible(true)]
    // entry point
    public void Solve(String problemFileName, String datasetFileName)
    {
        InnerSolve();
    }

    // doing some calculations
    // sending results
    private void InnerSolve(String problemFileName, String datasetFileName)
    {
       SendResults(results);
    }

    private void SendResults(string results)
    {
        ...
        if (null != this.ProblemSolvedEvent)
        {
            try
            {
                this.ProblemSolvedEvent(results);
            }....
         }
    }


Silverlight:


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 is dynamic COM object reference from AutomationFactory
        // HERE comes exception: 
        // "System.InvalidOperationException:
        //  Invalid cross-thread access."
        ProblemEngine.Solve(currentProblemName, currentDatasetFile);
    }...
}


再次,我不知道怎么了.我发现这通常是由于从另一个线程更新silverlight UI引起的,但是我没有做任何类似的事情.

我一直在寻找解决方案几天,却一无所获.
我不知道问题是由使用COM本身的某些方面还是由某些Silverlight对线程的限制引起的.
如我之前所说,当不使用异步调用或bw时一切正常.
(COM在安装过程中已注册.)

欢迎任何帮助.


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.

推荐答案

我找到了解决方案.

查看此帖子
您需要像这样调用您的事件.

SynchronizationContext.Current.Post(o => DataReceived(sender,(int)(e.EventType)),null);
I found a solution for this.

Check out this post
You will need to call your event like this.

SynchronizationContext.Current.Post(o => DataReceived(sender, (int) (e.EventType)), null);


这篇关于Silverlight 4 COM互操作-线程和COM事件的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆