【发布时间】:2011-03-04 07:21:12
【问题描述】:
背景:我和我的同事正在维护我们继承的一个百万行的遗留应用程序。它的前端是用 VB6 编写的,由于我们将几乎所有的资源都用于将其转换为 C#,因此我们正在为我们的特定问题寻找快速而肮脏的解决方案。
应用程序以插件方式运行。有多达 20 个独立的 ActiveX 控件可以在网格样式布局中一次加载。问题是 ActiveX 控件在它们自己的 UI 线程上进行所有处理,并且由于其中很多都阻塞了等待网络访问,因此 UI 变得非常糟糕。当我们的托管 C# 应用程序加载这些控件时,它会变得无响应,因为有多少控件正在吞噬 UI 资源而无所事事。最重要的是,控件很脆弱,只要稍有挑衅就会崩溃。当它们托管在主 C# 应用程序中时,会造成严重的不稳定。
到目前为止,我和我的同事想到的最好的方法是为每个 ActiveX 控件启动一个进程。这个过程,我们称之为代理,是另一个 winforms 应用程序。它使用命名管道与宿主进程通信。宿主进程创建一个窗口,加载我们选择的 ActiveX 控件(通过一些反射和 AxHost 魔术),并通过命名管道告诉主进程它的窗口句柄是什么。主进程使用 SetParent 和 SetWindowPos 的组合将代理应用程序移动到自身中以模拟插件。大小更新通过命名管道发送。
在 ActiveX 应用程序执行某种冗长的过程并且我们在其工作时单击主窗口之前,这已经足够好用了。主窗口有一段时间是响应式的,但最终由于子窗口等待其 UI 线程而变得无响应。我们如何才能让子窗口保持在自己的完整线程上,同时仍然获得 SetParent 的好处?
(如果有什么不清楚的地方请告诉我!)
【问题讨论】:
-
这听起来确实是摆脱高抬腿的好时机,只需将其实现为原生 Win32 托管应用程序,您就可以很好地控制所有这些问题,
-
@ChrisBecke:“你可以很好地控制所有这些问题” - 不,你没有。这些规则是一成不变的,你无法改变它们。 (好吧,您可以向 Microsoft 提交设计更改请求,并要求他们为您重写窗口子系统。)您跨线程调用
SetParent,附加这些线程的输入队列。这与编程语言或运行时环境无关。
标签: c# winforms multithreading winapi activex