Bombas de mensagens e AppDomains
Pergunta
I têm uma aplicação de um C # (FFx 3,5) que carrega os DLLs como plug-ins. Esses plug-ins são carregados em AppDomains separados (para os lotes de boas razões, e essa arquitetura não pode mudar). Isto é tudo muito bem.
Agora tenho um requisito para mostrar um diálogo de um desses plug-ins. Tenha em mente que eu não pode devolver o Formulário de diálogo para a aplicação principal e apresentá-lo lá (a infra-estrutura atual não suporta-lo).
Falha 1
Na minha DLL Eu criei um formulário e chamou Show. O esboço de diálogo apareceu, mas não pintar e ele não responde a eventos do mouse. Eu assumi que este é becasue a DLL está em um AppDomain separado e a bomba de mensagem para o aplicativo de alguma forma é incapaz de distribuir mensagens para a nova forma.
Falha 2
Na minha DLL Eu criei um formulário e chamou ShowDialog, que por todos os direitos devem criar uma bomba de mensagem interna para o diálogo .. O diálogo é exibida e respondeu a cliques (hooray), mas parece que o aplicativo principal não está processando ou despachar mensagens do Windows porque ele sai pintura e já não responde a eventos do mouse. Por alguma razão, agora parece que bomba de mensagem do aplicativo principal não está despachando.
A falha 3
Na minha DLL Eu criei um formulário e chamou Application.Run. Isso certamente vai criar uma bomba mensagem completa segundo. Eu obter o mesmo comportamento como falha. 2 - se comporta de diálogo, mas o aplicativo de chamada não
Quaisquer pensamentos sobre o que exatamente está acontecendo aqui e como eu poderia ir sobre apresentação de uma janela de DLL do outro AppDomain e ambos têm o chamador eo receptor ainda respondem e pintar corretamente?
Solução
Tente usar BeginInvoke principal do formulário de appdomain1 com um delegado que exibe a forma de appdomain2. Assim, em Pseudocódigo:
Appdomain1:
AppDomain2.DoSomething(myMainForm);
AppDomain2:
DoSomething(Form parent)
{
Form foolishForm = new Form();
parent.BeginInvoke(new Action( delegate { foolishForm.Show(); } ));
}
O código não pode ser perfeito, mas demonstra o conceito.
A propósito, se você está tendo problemas para passar as formas ao redor por causa de comunicação remota, você pode:
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;
}
}
que conterá objeto que você jogue com ele.
Outras dicas
Nós temos uma aplicação muito semelhante arquitetado que carrega a DLL arquivos e plugins. Cada arquivo DLL é carregada em um domínio de aplicação, que é criado em um segmento separado. Nós temos um controle de terceiros de uma forma que não iria aparecer a menos que chamamos System.Windows.Forms.Application.DoEvents()
regularmente.
código Pseudo:
<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>
Este resolvido todos os nossos problemas GUI.
Uma coisa que eu usei antes está a implementar um DomainManager . É possível personalizar os vários aplicativo de segurança de domínio / ligação / de lidar contexto complexo ou frango de ovo digite problemas com relação a bombear seus dados onde quer;)
Eu ususally feito isso de um native.exe, bootstrapping o CLR através das interfaces COM (código psudo mas a ordem e método nomes estão corretos;):
CorBindToRuntimeEx()
SetHostControl()
GetCLRControl()
SetAppDomainManagerType("yourdomainmanger","info")
// Domain manager set before starting runtime
Start()
HostControl -- GetDomainManagerForDefaultDomain()
DomainManager -- Run()
O seu gerenciador de domínio pode ser qualquer CLR biblioteca de classes, assim que seu não é que muito mais nativa C.
Uma nota lateral, se você estivesse em WPF ; Eu realmente gosto de usar o método "Microsoft.DwayneNeed.Controls". Onde você pode ter tópicos disperate com a sua própria bomba Dispatcher no mesma controle de UI (não necessitando de recorrer a inteiramente nova janela () 's).
A única coisa sobre o uso dessa abordagem, é que mesmo que o segmento interface do usuário principal está bloqueada / ocupado (alguns operação pesada, a digitalização do sistema de arquivos, etc ...), esses outros tópicos podem pintar / atualizar seu UIElement do sem qualquer soluço .