Message Pumps und AppDomains

Ich habe eine C # (FFx 3.5) -Anwendung, die DLLs als Plug-Ins lädt. Diese Plug-Ins werden in separaten AppDomains geladen (aus vielen guten Gründen, und diese Architektur kann sich nicht ändern). Das ist alles gut und gut.

Ich habe jetzt die Anforderung, einen Dialog von einem dieser Plug-Ins anzuzeigen. Beachten Sie, dass ich das Dialogformular nicht an die Hauptanwendung zurückgeben kann und es dort anzeigen kann (die aktuelle Infrastruktur unterstützt es nicht).

Ausfall 1

In meiner DLL habe ich ein Formular erstellt und Show aufgerufen. Die Dialogskizze wurde angezeigt, aber nicht gezeichnet und reactjs nicht auf Mausereignisse. Ich nahm an, dass dies der Fall ist, da sich die DLL in einer separaten AppDomain befindet und die Message-Pumpe für die App irgendwie nicht in der Lage ist, Nachrichten an das neue Formular weiterzuleiten.

Ausfall 2

In meiner DLL habe ich ein Formular erstellt und ShowDialog aufgerufen, das ausnahmslos eine interne Nachrichtenpumpe für den Dialog erstellen sollte. Der Dialog wird angezeigt und auf Klicks (hooray) reactjs, aber es scheint, dass die primäre App nicht mehr verarbeitet oder Senden von Fensternachrichten, da das Zeichnen beendet wird und auf Mausereignisse nicht mehr reactjs wird. Aus irgendeinem Grund scheint es jetzt, dass die Nachrichtenpumpe der Haupt-App nicht abschickt.

Ausfall 3

In meiner DLL habe ich ein Formular erstellt und Application.Run aufgerufen. Dies wird sicherlich eine komplette zweite Nachrichtenpumpe erzeugen. Ich bekomme dasselbe Verhalten wie Fehler 2 – der Dialog verhält sich, die aufrufende App jedoch nicht.

Irgendwelche Gedanken, was genau hier vor sich geht und wie ich ein Dialogfeld aus der DLL der anderen AppDomain anzeigen kann und sowohl der Anrufer als auch der Aufgerufene immer noch reagieren und richtig malen können?

Versuchen Sie, BeginInvoke des Hauptformulars von appdomain1 mit einem Delegaten zu verwenden, der das Formular aus appdomain2 anzeigt. Also im Pseudocode:

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

Der Code ist möglicherweise nicht perfekt, aber er demonstriert das Konzept.

Übrigens: Wenn Sie Probleme beim Weiterleiten von Formularen haben, können Sie:

 public class Container : 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 container) { return container.Value; } } 

Das wird Objekte enthalten, die Sie darauf casting.

Wir haben eine sehr ähnliche Architektur, die DLL-Dateien und Plugins lädt. Jede DLL-Datei wird in eine separate Anwendungsdomäne geladen, die in einem separaten Thread erstellt wird. Wir haben ein Steuerelement eines Drittanbieters in einer Form, die nicht angezeigt wird, wenn wir regelmäßig System.Windows.Forms.Application.DoEvents() aufrufen.

Pseudocode:

       

Dies triggerse alle unsere GUI-Probleme.

Eine Sache, die ich zuvor verwendet habe, ist die Implementierung eines DomainManagers . Es ist möglich, die verschiedenen Anwendungsdomänen- Sicherheits- / Bindungs- / Kontext-Einstellungen so anzupassen, dass komplexe Probleme oder Hühnereierprobleme in Bezug auf das Pumpen Ihrer Daten an die gewünschte Stelle behandelt werden.

Normalerweise habe ich dies von einer native.exe aus gemacht, die CLR über die COM-Schnittstellen bootstrapping (Psudo-Code, aber die Reihenfolge und Methodennamen sind korrekt;):

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

Ihr Domain-Manager kann eine beliebige CLR- classnbibliothek sein, daher ist deren C-class nicht so viel nativer.

Eine Randnotiz, wenn Sie in WPF waren ; Ich mag die Methode “Microsoft.DwayneNeed.Controls” sehr gerne. Möglicherweise haben Sie disperate Threads mit einer eigenen Dispatcher-Pumpe in derselben UI-Steuerung (ohne auf komplett neue Window ()) zurückgreifen zu müssen.

Das Einzigartige an diesem Ansatz ist, dass, selbst wenn der primäre UI-Thread blockiert / beschäftigt ist (einige schwere Operationen, das Scannen des Dateisystems usw.), diese anderen Threads ihre UIElement-Dateien möglicherweise ohne Hickup malen / aktualisieren.