问题
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
回答1:
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.
回答2:
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.
回答3:
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]
来源:https://stackoverflow.com/questions/1767439/passing-data-across-appdomains-with-marshalbyrefobject