C# 消息泵和应用程序域

C# 消息泵和应用程序域,c#,appdomain,C#,Appdomain,我有一个C#(FFx 3.5)应用程序,它将DLL作为插件加载。这些插件加载在单独的AppDomain中(出于许多好的原因,这种体系结构无法更改)。这一切都很好 我现在需要显示这些插件之一的对话框。请记住,我不能将对话框表单返回到主应用程序并在那里显示它(当前的基础结构不支持它) 失败1 在我的DLL中,我创建了一个名为Show的表单。对话框轮廓出现了,但没有绘制,并且它对鼠标事件没有响应。我假设这是因为DLL位于单独的AppDomain中,并且应用程序的消息泵不知何故无法将消息发送到新表单 失

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

我现在需要显示这些插件之一的对话框。请记住,我不能将对话框表单返回到主应用程序并在那里显示它(当前的基础结构不支持它)

失败1

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

失败2

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

失败3

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


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

尝试使用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;
    }
}
公共类容器:MarshallByRefObject
{
私人T_值;
公共T值{get{return{U Value;}集合{U Value=Value;}}
公共容器(){}
公共容器(T值){value=value;}
公共静态隐式运算符T(容器)
{
返回容器。值;
}
}

它将包含您向它抛出的对象。

我们有一个结构非常相似的应用程序,它加载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问题。

我以前使用过的一件事是实现一个。可以自定义各种安全性/绑定/上下文,以处理复杂的或鸡蛋类型的问题,从而将数据传输到您想要的地方;)

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

您的域管理器可以是任何类库,因此它们的本地C语言就没有那么多了

一张便条,如果你在的话;我非常喜欢使用“Microsoft.dwayneed.Controls”方法。在同一个UI控件中,您可能有具有自己的Dispatcher泵的Dispatcher线程(不需要求助于全新的Window())


使用这种方法的独特之处在于,即使主UI线程被阻塞/繁忙(一些繁重的操作、扫描文件系统等),这些其他线程也可以绘制/更新其UI元素,而不会出现任何问题。

+1:感谢您的建议。我喜欢容器的概念。我们可以在前进的过程中牢记这一点。通过一本书的链接回答了另一个问题,该书还记录了如何做到这一点;
CorBindToRuntimeEx()
SetHostControl()
GetCLRControl()
SetAppDomainManagerType("yourdomainmanger","info")
// Domain manager set before starting runtime
Start()
HostControl -- GetDomainManagerForDefaultDomain()
DomainManager -- Run()