Unloading a secondary AppDomain that has invoked a Dynamic Method

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi all. I’m looking for some advice on how to completely unload a newly
created (second) AppDomain that calls a dynamic method in a dynamic
assembly&module which is a wrapper for a legacy dll method. It’s basically a
plugin manager but my problem comes when I need to replace, update or delete
the legacy dll because even if I unload the secondary appdomain, a lock on
the dll file continues to exist. I believe this happens because my second app
domain is being treated as a proxy to the first. I attached some sample code
in hopes that someone could please help me out with this problem. It’s been
giving me a headache for weeks and I just can’t get it to work.

// To run it
Void foo()
{
CLocalLoader pInvoke = new CLocalLoader();
pInvoke.DynamicPInvoke("C:\\VAdminHook.dll", "VAdmin_DLLInit",
typeof(bool), new Type[]{ typeof(uint) }, new Object[]{ (uint)0 });
//……..
pInvoke.Dispose();
pInvoke = null;

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(0);
}




namespace InvokeExternal
{
/// <summary>
/// Local Loader Class
/// </summary>
public class CLocalLoader : IDisposable
{
private AppDomain m_dynamicAppDomain = null;
private CRemoteLoader m_RemoteLoader = null;

public CLocalLoader()
{
LoadUp();
}

~CLocalLoader()
{
dispose( false );
}

public void Dispose()
{
dispose( true );
}

private void dispose( bool disposing )
{
if( disposing )
{
Console.WriteLine("CLocalLoader::Unload AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

m_RemoteLoader.Dispose();
m_RemoteLoader = null;

AppDomain.Unload(m_dynamicAppDomain);
m_dynamicAppDomain = null;

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect( 0 );
}
}


public void LoadUp()
{
try
{
Console.WriteLine("CLocalLoader::LoadUp AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());
// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = "CLocalLoaderTestApp";
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;

m_dynamicAppDomain = AppDomain.CreateDomain("MySecondDomain", null,
setup);

//CreateInstanceAndUnwrap(CurrentAssemblyName,
Namespace.ClassObject);
m_RemoteLoader = (CRemoteLoader)
m_dynamicAppDomain.CreateInstanceAndUnwrap("InvokeVadminHook",
"InvokeExternal.CRemoteLoader");
}

catch (Exception pError)
{
Console.WriteLine("CLocalLoader::CallDynaMethod EXCEPTION [{0}]
AppDomain[{1}]", pError.Message, AppDomain.CurrentDomain.ToString());
}
}

public object DynamicPInvoke(string dll, string entryPoint, Type
returnType, Type [] parameterTypes, object [] parameterValues)
{
Console.WriteLine("CLocalLoader::DynamicPInvoke AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

if (m_RemoteLoader != null )

m_RemoteLoader.CallDynaMethod("InvokeExternal.CRemoteLoader.DynaAssembly",
dll, entryPoint, returnType, parameterTypes, parameterValues);

return null;
}
}




//=============================================================================
/// <summary>MBRO Class to Load and Call DynaMethod </summary>
internal class CRemoteLoader : MarshalByRefObject, IDisposable
{
~CRemoteLoader()
{
dispose( false );
}

public void Dispose()
{
dispose( true );
}

private void dispose( bool disposing )
{
if( disposing )
{
Console.WriteLine("CRemoteLoader::dispose AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect( 0 );
}
}

public void CallDynaMethod(String strAssemblyName, string dll, string
entryPoint, Type returnType, Type [] parameterTypes, object []
parameterValues)
{

try
{
Console.WriteLine("CRemoteLoader::CallDynaMethod Executing in
AppDomain[{0}]", AppDomain.CurrentDomain.ToString());

AssemblyName asmName = new AssemblyName();
asmName.Name = strAssemblyName;

AssemblyBuilder dynamicAsm =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);

//Create a temp module in the assembly
ModuleBuilder dynamicMod = dynamicAsm.DefineDynamicModule(
"tempModule");

// Dynamically construct a global PInvoke signature using the input
information
MethodBuilder dynamicMethod =
dynamicMod.DefinePInvokeMethod(entryPoint,
dll,
MethodAttributes.Static | MethodAttributes.Public |
MethodAttributes.PinvokeImpl,
CallingConventions.Standard,
typeof(System.Int32),
parameterTypes,
CallingConvention.Winapi,
CharSet.Ansi);



dynamicMethod.SetImplementationFlags(MethodImplAttributes.PreserveSig |
dynamicMethod.GetMethodImplementationFlags());

// This global method is now complete
dynamicMod.CreateGlobalFunctions();

// Get a MethodInfo for the PInvoke method
MethodInfo mi = dynamicMod.GetMethod(entryPoint);

// Invoke the static method and return an object
Object pRetObj = mi.Invoke(null, parameterValues);
}

catch (Exception pError)
{
Console.WriteLine("CRemoteLoader::CallDynaMethod EXCEPTION [{0}]
AppDomain[{1}]", pError.Message, AppDomain.CurrentDomain.ToString());
throw pError;
}
}
}





}
 
bump

Alex said:
Hi all. I’m looking for some advice on how to completely unload a newly
created (second) AppDomain that calls a dynamic method in a dynamic
assembly&module which is a wrapper for a legacy dll method. It’s basically a
plugin manager but my problem comes when I need to replace, update or delete
the legacy dll because even if I unload the secondary appdomain, a lock on
the dll file continues to exist. I believe this happens because my second app
domain is being treated as a proxy to the first. I attached some sample code
in hopes that someone could please help me out with this problem. It’s been
giving me a headache for weeks and I just can’t get it to work.

// To run it
Void foo()
{
CLocalLoader pInvoke = new CLocalLoader();
pInvoke.DynamicPInvoke("C:\\VAdminHook.dll", "VAdmin_DLLInit",
typeof(bool), new Type[]{ typeof(uint) }, new Object[]{ (uint)0 });
//……..
pInvoke.Dispose();
pInvoke = null;

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(0);
}




namespace InvokeExternal
{
/// <summary>
/// Local Loader Class
/// </summary>
public class CLocalLoader : IDisposable
{
private AppDomain m_dynamicAppDomain = null;
private CRemoteLoader m_RemoteLoader = null;

public CLocalLoader()
{
LoadUp();
}

~CLocalLoader()
{
dispose( false );
}

public void Dispose()
{
dispose( true );
}

private void dispose( bool disposing )
{
if( disposing )
{
Console.WriteLine("CLocalLoader::Unload AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

m_RemoteLoader.Dispose();
m_RemoteLoader = null;

AppDomain.Unload(m_dynamicAppDomain);
m_dynamicAppDomain = null;

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect( 0 );
}
}


public void LoadUp()
{
try
{
Console.WriteLine("CLocalLoader::LoadUp AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());
// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = "CLocalLoaderTestApp";
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;

m_dynamicAppDomain = AppDomain.CreateDomain("MySecondDomain", null,
setup);

//CreateInstanceAndUnwrap(CurrentAssemblyName,
Namespace.ClassObject);
m_RemoteLoader = (CRemoteLoader)
m_dynamicAppDomain.CreateInstanceAndUnwrap("InvokeVadminHook",
"InvokeExternal.CRemoteLoader");
}

catch (Exception pError)
{
Console.WriteLine("CLocalLoader::CallDynaMethod EXCEPTION [{0}]
AppDomain[{1}]", pError.Message, AppDomain.CurrentDomain.ToString());
}
}

public object DynamicPInvoke(string dll, string entryPoint, Type
returnType, Type [] parameterTypes, object [] parameterValues)
{
Console.WriteLine("CLocalLoader::DynamicPInvoke AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

if (m_RemoteLoader != null )

m_RemoteLoader.CallDynaMethod("InvokeExternal.CRemoteLoader.DynaAssembly",
dll, entryPoint, returnType, parameterTypes, parameterValues);

return null;
}
}




//=============================================================================
/// <summary>MBRO Class to Load and Call DynaMethod </summary>
internal class CRemoteLoader : MarshalByRefObject, IDisposable
{
~CRemoteLoader()
{
dispose( false );
}

public void Dispose()
{
dispose( true );
}

private void dispose( bool disposing )
{
if( disposing )
{
Console.WriteLine("CRemoteLoader::dispose AppDomain[{0}]",
AppDomain.CurrentDomain.ToString());

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect( 0 );
}
}

public void CallDynaMethod(String strAssemblyName, string dll, string
entryPoint, Type returnType, Type [] parameterTypes, object []
parameterValues)
{

try
{
Console.WriteLine("CRemoteLoader::CallDynaMethod Executing in
AppDomain[{0}]", AppDomain.CurrentDomain.ToString());

AssemblyName asmName = new AssemblyName();
asmName.Name = strAssemblyName;

AssemblyBuilder dynamicAsm =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);

//Create a temp module in the assembly
ModuleBuilder dynamicMod = dynamicAsm.DefineDynamicModule(
"tempModule");

// Dynamically construct a global PInvoke signature using the input
information
MethodBuilder dynamicMethod =
dynamicMod.DefinePInvokeMethod(entryPoint,
dll,
MethodAttributes.Static | MethodAttributes.Public |
MethodAttributes.PinvokeImpl,
CallingConventions.Standard,
typeof(System.Int32),
parameterTypes,
CallingConvention.Winapi,
CharSet.Ansi);



dynamicMethod.SetImplementationFlags(MethodImplAttributes.PreserveSig |
dynamicMethod.GetMethodImplementationFlags());

// This global method is now complete
dynamicMod.CreateGlobalFunctions();

// Get a MethodInfo for the PInvoke method
MethodInfo mi = dynamicMod.GetMethod(entryPoint);

// Invoke the static method and return an object
Object pRetObj = mi.Invoke(null, parameterValues);
}

catch (Exception pError)
{
Console.WriteLine("CRemoteLoader::CallDynaMethod EXCEPTION [{0}]
AppDomain[{1}]", pError.Message, AppDomain.CurrentDomain.ToString());
throw pError;
}
}
}





}
 
Back
Top