让我的COM组件调用异步(Make my COM assembly call asynchronou

2019-08-17 11:33发布

我只是“赚”的特权保持传统图书馆在我目前的工作在C#编码。

此DLL:

  • 自曝与UNIFACE犯了一个大的遗留系统,有没有选择,只能调用COM对象的方法。
  • 作为与其他系统的API这个遗留系统之间的联系。
  • 使用的WinForm其在某些情况下,UI。

更直观,据我所知的组件:

*[Big legacy system in Uniface]* == [COM] ==> [C# Library] == [托管API] ==> *[Big EDM Management System]*

现在的问题是:一是在这个C#库的方法耗时过长运行和我“应该”让异步!

我已经习惯了C#,但不是在所有的COM。 我已经做了并发编程,但COM似乎很多复杂的东西添加到它和我所有的试验迄今结束或者:

  • 没有错误消息崩溃所有
  • 我的DLL只有部分工作(只显示其用户界面的一部分,然后关闭),仍然没有给我任何的错误可言

我出的有关如何在COM DLL中处理线程的想法和资源,我将不胜感激任何提示或帮助。

到目前为止,该代码最大的一部分,我已经改变了,使我的方法异步:

// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
  errMsg = "";
  try {
    Action<string> asyncOp = AsyncComparedSearch;
    asyncOp.BeginInvoke(application, null, null);
  } catch (ex) {
    // ...
  }
  return 0;
}

private int AsyncComparedSearch(string application) {
  // my actual method doing the work, that was the called method before
}

任何提示或有用的资源将不胜感激。 谢谢。

更新1:

遵循下面的答案和线索(尤其是有关SynchronizationContext ,并以帮助这个例子 ),我能重构我的代码,并使它的工作,但只在C#中的另一个窗口的应用程序不是通过COM调用时,和。 当我打电话的功能和不提供有关飞机坠毁的任何细节遗留系统遇到相当令人费解的错误。

更新2:

最新更新我的试验:我设法让多线程工作时,呼叫从一个测试项目从UNIFACE系统进行,而不是 。 多次试验之后,我们倾向于认为,我们的遗留系统并不支持以及在其目前的配置多线程。 但是,这不是问题的点更多:)

这里,似乎工作的代码的exerpt:

string application;
SynchronizationContext context;

// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
    this.application = application;
    context = WindowsFormsSynchronizationContext.Current;
    Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs));
    t.Start();
    errMsg = "";
    return 0;
}

private void AsyncComparedSearch() {
    // ANY WORK THAT AS NOTHING TO DO WITH UI
    context.Send(new SendOrPostCallback(
        delegate(object state)
        {
            // METHODS THAT MANAGE UI SOMEHOW
        }
    ), null);
}

现在我们正在考虑不是修改该COM组件,封装一样在Windows服务这个库并创建系统和服务之间的接口,其他的解决方案。 它应该是更加可持续的..

Answer 1:

这是很难告诉不知道更多的细节,但这里有几个问题。

您可以执行经由另一个线程委托BeginInvoke ,但你不等待它。 你try\catch的同时,仍执行远程调用它已经通过了块不会赶上什么。 相反,你应该把try\catch里面块AsyncComparedSearch

当你不等待远程方法的执行结束( EndInvoke或通过回调),我不知道你是怎么处理COM调用的结果。 我想,然后你从内更新GUI AsyncComparedSearch 。 如果是这样,这是错误的,因为它是在另一个线程运行,你永远不应该从任何地方,但GUI线程更新界面 - 这将有崩溃或其他意外的行为,最有可能的结果。 因此,你需要同步的GUI更新工作GUI线程。 在的WinForms,你需要使用Control.BeginInvoke (不Delegate.BeginInvoke混淆)或其他方式(如的SynchronizationContext )同步代码GUI线程。 我用类似这样:

private delegate void ExecuteActionHandler(Action action);

public static void ExecuteOnUiThread(this Form form, Action action)
{
  if (form.InvokeRequired) { // we are not on UI thread
    // Invoke or BeginInvoke, depending on what you need
    form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
  }
  else { // we are on UI thread so just execute the action
    action();
  }
}

然后,我这样称呼它从任何线程:

theForm.ExecuteOnUiThread( () => theForm.SomeMethodWhichUpdatesControls() );

此外,阅读这个答案的一些注意事项。



文章来源: Make my COM assembly call asynchronous