3

我有一个将 DLL 作为插件加载的 C# (FFx 3.5) 应用程序。这些插件加载在单独的 AppDomain 中(有很多很好的理由,而且这种架构不能改变)。这一切都很好。

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

失败1

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

失败2

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

失败 3

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

关于这里到底发生了什么以及我如何从另一个 AppDomain 的 DLL 中显示一个对话框并让调用者和被调用者仍然响应并正确绘制的任何想法?

4

3 回答 3

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;
    }
}

这将包含你扔给它的对象。

于 2009-01-14T08:49:03.683 回答
1

我们有一个非常相似的架构应用程序来加载 DLL 文件和插件。每个 DLL 文件都加载到单独的应用程序域中,该应用程序域是在单独的线程上创建的。我们有一个第三方控件,除非我们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 问题。

于 2009-04-19T12:29:05.027 回答
1

我之前使用过的一件事是实现DomainManager。可以自定义各种应用程序域安全/绑定/上下文,以处理复杂或鸡蛋类型的问题,将您的数据泵送到您想要的地方;)

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

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 而不会出现任何问题。

于 2009-05-29T06:23:15.217 回答