4

I'm having a little trouble passing some data between two .NET appdomains and I'm hoping someone on here can help me.

Basically what I have is a main application (Main) which loads assembly A and B into it's main domain, then when I run a plugin(C) Main calls a create domain method on B which creates a new domain and loads C and a instance of B into it, so that C can only access B and not the others.

B contains a pointer to the IDispatch of Main but only it seems to get it after it is loaded into the new domain with C. What I am trying to do is send a copy of the pointer from the new domain instance of B and send it to A which is still running in the default domain.

Just for the record I control A,B and C but not Main

Sorry if this is a bit hard to understand I tried my best to explain it.

Code:

In A:

public class Tunnel : MarshalByRefObject
{
    public void SetPointer(int dispID)
    {
        IntPtr pointer = new IntPtr(dispID);
    }
}

In B:

//Call by Main after loading plug in but after A.dll is loaded.
public void CreateDomain()
{
  AppDomain maindomain= AppDomain.CurrentDomain;
  tunnel = (Tunnel)maindomain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                      typeof(Tunnel).FullName);

   AppDomain domain = base.CreateDomain(friendlyName, securityInfo, appDomainInfo);
   //Load assembly C (plug in) in domain.
   // C uses B so it loads a new instance of B into the domain also at the same time.

  // If I do this here it creates new instance of A but I need to use the one in
  // the main domain.
  //tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                    typeof(Tunnel).FullName);
  tunnel.SetPointer(//Send data from B loaded in new domain.)

}

So at the end it looks something like this:

Default Domain:

  • Main.dll
  • A.dll
  • B.dll

Plug in Domain:

  • B.dll
  • C.dll
Nathan W
  • 54,475
  • 27
  • 99
  • 146
  • IDispatch? What role is COM playing in your case? – Lucero Nov 19 '09 at 23:54
  • Yeah, it is a bit hard to understand. Could you post some code and clarify what fails, eg. do you get some exception somewhere or is something null when it shouldn't be? – EMP Nov 19 '09 at 23:55
  • @Lucero B is a wrapper around a COM object. – Nathan W Nov 20 '09 at 00:29
  • Quote: "If I do this here it creates new instance of A". That makes it definitely sound like A is a class. Where previously you said it was an assembly. You'll need to distinguish this to have any hope of getting an answer. – Hans Passant Nov 20 '09 at 02:10
  • Yes, there seems to be some confusion between assemblies and domains. An AppDomain can only have one instance of an assembly loaded. But if the assembly is not strongly named then it's possible to have two identical assemblies and of course their types will be treated as different (ie. type Tunnel in C:\Temp\A.dll and type Tunnel in C:\Dev\A.dll are different). So when you say "C uses B so it loads a new instance of B into the domain" do you mean it loads a different COPY of B, from a different location on disk? What actually fails to work int he above code? – EMP Nov 20 '09 at 03:18
  • Sorry for the confusion everyone, I have never really got into this AppDomain stuff until now. If I have two domains is it possible to have the same assembly loaded in both domains as different instances? or is that wrong? – Nathan W Nov 20 '09 at 03:27
  • I'm not sure what you mean by an "instance" of an assembly. – EMP Nov 20 '09 at 03:32
  • I'm really sorry for this, say I have two domains 1 and 2, 1 is loaded with assembly A.dll and a domain 2 is loaded with a plugin that uses A.dll, A.dll also gets loaded into domain 2 by the plugin. If I change a property in the version that domain 2 has will it be reflected in domain 1 version? – Nathan W Nov 20 '09 at 03:54
  • There are no properties on assemblies. You can pass a MarshalByRef object from one domain to another, which would automatically load the object's assembly into the remote domain. If you set a property on that object instance then yes, it will be reflected in the remote domain. – EMP Nov 20 '09 at 04:28

3 Answers3

8

In your code above you are calling

AppDomain.CurrentDomain.CreateInstanceAndUnwrap(...)

This is simply a round-about way of creating an object in the current domain, same as if you just called the constructor. You need to call that method on a remote domain, ie.

AppDomain domain = AppDomain.Create(...)
Tunnel tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(...)

If you then call tunnel.SetPointer(...) that will run on the remote object.

EMP
  • 59,148
  • 53
  • 164
  • 220
0

So I guess that:

class B : MarshallByRef

with that you need only create the object in the domain from class A:

AppDomain domain = ...
B inst = (B) domain.CreateInstanceAndUnwrap(typeof(B).Assembly.FullName, typeof(B).FullName);
inst.DoPlugin("C");

The DoPlugin() method will dynamically load type "C" and call whatever methods are appropriate.

csharptest.net
  • 62,602
  • 11
  • 71
  • 89
0

You may have to copy across search paths and evidence when creating "Child" domains (especially for running under unit test libraries):

var dom = AppDomain.CreateDomain("NewDomain",
    AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.BaseDirectory,
    AppDomain.CurrentDomain.RelativeSearchPath, false);
try
{
    var tunnel = (MyMarshallByRef)dom.CreateInstanceAndUnwrap(
        typeof(MyMarshallByRef).Assembly.FullName,
        typeof(MyMarshallByRef).FullName);

    tunnel.DoStuff("data");
}
finally
{
    AppDomain.Unload(dom);
}

Also note that any arguments the the DoStuff method, and any types it returns must be marked [Serializable]

Iain Ballard
  • 4,433
  • 34
  • 39
  • Why do "seach paths and evidence" have to be copied? By `MyMarshallByRef` type, do you mean `Tunnel`? I didn't see a `DoStuff()` method defined, so what is that? – Suncat2000 Aug 31 '23 at 06:21
  • 1: Internal .Net requirements. 2: Yes. 3: Whatever calls you want to cross the domain boundary. Note that this answer is nearly 10 years old now, and might not apply to latest versions of dotnet. – Iain Ballard Aug 31 '23 at 08:32