消息泵和AppDomains

时间:2009-01-13 14:45:03

标签: c# appdomain

我有一个C#(FFx 3.5)应用程序,它将DLL作为插件加载。这些插件加载在单独的AppDomain中(出于很多原因,这种架构无法更改)。这一切都很好。

我现在要求显示其中一个插件的Dialog。请记住,我无法将对话框表单返回到主应用程序并将其显示在那里(当前基础结构不支持它)。

失败1

在我的DLL中,我创建了一个名为Show的表单。对话框轮廓显示但没有绘制,它不响应鼠标事件。我认为这是因为DLL在一个单独的AppDomain中,并且应用程序的消息泵无论如何都无法将消息发送到新表单。

失败2

在我的DLL中,我创建了一个Form并调用了ShowDialog,所有权利都应该为对话框创建一个内部消息泵。对话框显示并响应点击(万岁),但似乎主应用程序不再正在处理或调度Windows消息,因为它退出绘画并且不再响应鼠标事件。由于某些原因,现在似乎主应用程序的消息泵没有调度。

失败3

在我的DLL中,我创建了一个Form并调用了Application.Run。这肯定会创建一个完整的第二个消息泵。我得到了与失败2相同的行为 - 对话行为,但调用应用没有。

有关这里究竟发生了什么以及如何从其他AppDomain的DLL显示对话框并让调用者和被调用者仍然响应并正确绘制的任何想法?

3 个答案:

答案 0 :(得分:4)

尝试使用appdomain1的主窗体的BeginInvoke和一个显示appdomain2表单的委托。所以在伪代码中:

Appdomain1:
    AppDomain2.DoSomething(myMainForm);

AppDomain2:
    DoSomething(Form parent)
    {
        Form foolishForm = new Form();
        parent.BeginInvoke(new Action( delegate { foolishForm.Show(); } ));
    }

代码可能并不完美,但它证明了这一概念。

顺便说一下,如果因为远程操作而传递表格时遇到问题,您可以:

public class Container<T> : MarshalByRefObject
{
    private T _value;
    public T Value { get { return _value; } set { _value = value; } }

    public Container() { }
    public Container(T value) { Value = value; }

    public static implicit operator T(Container<T> container)
    {
        return container.Value;
    }
}

那将包含你扔的对象。

答案 1 :(得分:1)

我们有一个非常类似的架构应用程序,可以加载DLL文件和插件。每个DLL文件都加载在一个单独的application domain中,该文件是在一个单独的线程上创建的。除非我们定期致电System.Windows.Forms.Application.DoEvents(),否则我们会以不会出现的形式提供第三方控件。

伪代码:

<In new thread>
  <Application domain created. Start called inside new application domain.>
  <Start loads new DLL file, calls init function in DLL file>
  <Start loops, calling DoEvents until the DLL file exits>
  <Application domain unloaded>
<Thread exits>

这解决了我们所有的GUI问题。

答案 2 :(得分:1)

我之前使用的一件事是实现DomainManager。可以自定义各种application domain安全性/绑定/上下文来处理复杂或鸡蛋类型问题,以便将数据抽取到您想要的位置;)

我通常使用native.exe完成此操作,通过COM接口引导CLR(psudo代码,但顺序和方法名称正确;):

CorBindToRuntimeEx()
SetHostControl()
GetCLRControl()
SetAppDomainManagerType("yourdomainmanger","info")
// Domain manager set before starting runtime
Start()
HostControl -- GetDomainManagerForDefaultDomain()
DomainManager -- Run()

您的域管理员可以是任何CLR类库,因此他们的本地C不是那么多。

旁注,如果你在WPF;我真的很喜欢使用“Microsoft.DwayneNeed.Controls”方法。你可能在相同的 UI控件中使用自己的Dispatcher泵来分离线程(不需要求助于全新的Window())。

使用这种方法的独特之处在于,即使主UI线程被阻塞/忙碌(一些繁重的操作,扫描文件系统等等),这些其他线程也可以在没有任何打嗝的情况下绘制/更新其UIElement