在我目前的工作中,我刚刚“赢得”了维护一个用 C# 编码的遗留库的特权。
这个dll:
- 公开使用 Uniface 制作的大型遗留系统的方法,该系统别无选择,只能调用 COM 对象。
- 充当此遗留系统与另一个系统的 API 之间的链接。
- 在某些情况下,它的 UI 使用 WinForm。
更直观地,据我了解组件:
*[Big legacy system in Uniface]*
==[COM]==> [C# Library]
==[托管 API]==> *[Big EDM Management System]*
问题是:这个 C# 库中的一个方法运行时间太长,我“应该”让它异步!
我习惯了 C#,但根本不习惯 COM。我已经完成了并发编程,但是 COM 似乎给它增加了很多复杂性,到目前为止我所有的试验都以以下两种方式结束:
- 完全没有错误消息的崩溃
- 我的 Dll 仅部分工作(仅显示其 UI 的一部分,然后关闭),但仍然没有给我任何错误
我没有关于如何在 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# 中的另一个 Window 应用程序调用时,而不是通过 COM。当我调用该函数时,遗留系统遇到了一个非常模糊的错误,并且没有提供有关崩溃的任何详细信息。
更新 2:
我的试验中的最新更新:当调用来自测试项目而不是来自Uniface 系统时,我设法使多线程工作。经过多次试验,我们倾向于认为我们的遗留系统在其当前配置中不能很好地支持多线程。但这不再是问题的重点:)
这是似乎有效的代码摘录:
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 服务中并在系统和服务之间创建接口。它应该更可持续..