tags:

views:

1012

answers:

5

I have a a C# (FFx 3.5) application that loads DLLs as plug-ins. These plug-ins are loaded in separate AppDomains (for lots of good reasons, and this architecture cannot change). This is all well and good.

I now have a requirement to show a Dialog from one of those plug-ins. Bear in mind that I cannot return the dialog Form to the main application and have it displayed there (the current infrastructure doesn't support it).

Failure 1

In my DLL I created a Form and called Show. The dialog outline showed up but did not paint and it doesn't respond to mouse events. I assumed that this is becasue the DLL is in a separate AppDomain and the message pump for the app is somehow unable to dispatch messages to the new Form.

Failure 2

In my DLL I created a Form and called ShowDialog, which by all rights should create an internal message pump for the dialog.. The dialog is displayed and responded to clicks (hooray), but it appears that the primary app no longer is processing or dispatching windows messages because it quits painting and no longer responds to mouse events. For some reason now it seems that the main app's message pump is not dispatching.

Failure 3

In my DLL I created a Form and called Application.Run. This will certainly create a complete second message pump. I get the same behavior as Failure 2 - the Dialog behaves, but the calling app does not.

Any thoughts on what exactly is going on here and how I might go about showing a dialog from the other AppDomain's DLL and have both the caller and the callee still respond and paint properly?

+2  A: 

Try using appdomain1's main form's BeginInvoke with a delegate that displays the form from appdomain2. So in Pseudocode:

Appdomain1:
    AppDomain2.DoSomething(myMainForm);

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

The code may not be perfect, but it demonstrates the concept.

By the way, if you are having problems passing forms around because of remoting you can:

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

That will contain object you throw at it.

Jonathan C Dickinson
+1: Thanks for the suggestions. I like the concept of the container. We may keep that in mind as we move forward.
ctacke
A: 

I realize this is 3 months old, and hopefully you have a soluion. We have a very similarly architected application that loads DLLs a plugins. Each DLL is loaded in a separate appdomain, which is created on a separate thread. We have a third party control in a form that would not appear unless we call System.Windows.Forms.Application.DoEvents() regularly.

Pseudo code:

This soved all of our GUI issues.

Seth

I don't see your pseudocode...
Lucero
+1  A: 

One thing that I've used before is implmenting a DomainManager. It's possiable to customize the various AppDomain security/binding/context's to handle complex or chicken-egg type problems with respect to pumping your data where you want ;)

I've ususally done this from a native.exe, bootstrapping the CLR through the COM interfaces (psudo code but the order and method names are correct ;)

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

Your domain manager can be any CLR class library, so their's not that much more native C.

A side note, if you were in WPF; I really like using the "Microsoft.DwayneNeed.Controls" method. Where you may have disperate threads with their own Dispatcher pump in the same UI control (not needing to resort to entirely new Window()'s).

The unique thing about using the this approach, is that even if the primary UI thread is blocked/busy (some heavy operation, scanning the filesystem etc...), these other threads may paint/update their UIElement's w/o any hiccup.

RandomNickName42
http://stackoverflow.com/users/100864/giulio-vian answered another question with a link to a book which also document's how to do this;http://stackoverflow.com/questions/171541/how-do-i-obtain-a-list-of-the-application-domains-my-application-has-created
RandomNickName42
A: 

I have a problem which is also related to AppDomain's and Windows messages.

A web page to be hosted in Internet Explorer that would contains a .Net WinForms UserControl derived

control - HelloWorldCtl. This control is inside a C# written assembly - HelloWorldControl.dll. The

control uses code from another assembly that is written in C++/CLR - HelloWorldLibCPP.dll.

HelloWorldCtl loads HelloWorldLibCPP.dll and calls code that would create a Win32 native window and

places that window in HelloWorldCtl's area.

Navigate to the web page, HelloWorldCtl loads, I can see it as well as the native window in the center

of HelloWorldCtl's area.

Both the C# control and the native window have some message handlers and the messages are all working

fine and reaching both the C# control's window and the native window; mouse clicks, re-paints and so

on... However, some of the message handles of the native window need to call methods on the C# control

which is the parent of the native window. This is done using an interface that the C# control

implements and which the native window holds a reference to its handle by storing the handle in a

GCHandle (from System::Runtime::InteropServices.) I used the gcroot<> template for the GCHandle.

The failure is happening at this point when code in the native window (although compiled as managed code with /clr) is trying to use the GCHandle to call any method on the C# control.

The exception that is thrown is :

"Cannot pass a GCHandle across AppDomains"

I put some debugging code to display the Id and FriendName of the CurrentDomain in both the C# and the native window and I found out that these AppDomains are not the same.

During the creation of the native window, the CurrentDomain is the same as that of the C# control, but when the native window receives messages and those messages are handled, the CurrentDomain is different from the C# control's.

Can this situation be changed? Is it possible to have both the native window messages hanlder run in the same AppDomain as that of the C# control?

Any other suggestions perhaps?

Thanks, Roger

enter code here
Roger
Yes, I suggest asking this as it's own question, not as an asnwer to mine (which it clearly isn't)
ctacke
A: 

ctacke, you're right. I will re-post as a new thread.

Roger
This is also not an answer. I suggest you read the FAQ (linked at the top of the page); this is a question-and-answer site, not a standard forum or discussion board.
Michael Myers