Hello Matthew,

I've implemented the proof-of-concept program, which creates AppDomain
and loads assemblies there, but I'm not sure if it works around the
problem you've described. Probably it would be good to set up some
security policy for the newly-created AppDomain, so that the loaded
assembly couldn't do any harm (AFAIR, static constructors are called
when assembly is being loaded). Also, in MSDN there is a clause that
it may take quite a time to Unload the AppDomain. An alternative way
is to call Abort on all threads of this domain which is a bit harsh.
I'm not sure which way to go, please tell your opinion if you find
some way to be the preferable one.

Program source is attached, it just prints the names of referenced
assemblies.
I'm also going to do some speedup by using Hashtable, so don't take
the current ArrayList implementation into account.

It would be great if somebody commented upon that code (style/bad
practices/etc.), so that I could change it now.

MM> AppDomains allow you load/unload assemblies at will.  The .NET runtime
MM> tends to exhibit some odd/unpredictable behaviour as you load assemblies 
MM> with the same name, especially if they don't have strong names.  You can 
MM> end up with types no longer resolving as expected.  By loading 
MM> assemblies in the separate AppDomain, you side-step all of these issues.

-- 
Best regards,
 Ivan                            mailto:[EMAIL PROTECTED]
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Runtime.Remoting;

public class GetRefs {
    public static void Main(string[] p_args) {
        if (p_args.Length != 1) {
            Console.WriteLine("usage: refs <dll>");
            return;
        }

        string[] referenced = GetAllReferencedModules(p_args[0]);
        Console.WriteLine("Referenced:");
        Console.WriteLine(string.Join("\n", referenced));
    }

    private static string[] GetAllReferencedModules(string module) {
        string fullPathToModule = Path.GetFullPath(module);
        string moduleDirectory = Path.GetDirectoryName(fullPathToModule);
        AppDomain temporaryDomain = AppDomain.CreateDomain("temporaryDomain");

        ArrayList referenceList = new ArrayList();
        try {
            ReferencesResolver referencesResolver =
                ((ReferencesResolver) temporaryDomain.CreateInstanceFrom("refs.exe",
                    typeof(ReferencesResolver).FullName).Unwrap());

            referenceList.Add(fullPathToModule);

            for (int currentModule = 0; currentModule < referenceList.Count; 
currentModule++) {
                
referencesResolver.AppendReferencedModulesLocatedInGivenDirectory(moduleDirectory,
                    (string) referenceList[currentModule], ref referenceList);
            }
        } finally {
            AppDomain.Unload(temporaryDomain);
        }

        return (string[]) referenceList.ToArray(typeof(string));
    }

}

public class ReferencesResolver : MarshalByRefObject {
    public void AppendReferencedModulesLocatedInGivenDirectory(string moduleDirectory, 
string moduleName,
                                                                ref ArrayList 
referenceList) {
        Assembly module = Assembly.LoadFrom(moduleName);
        AssemblyName[] referencedAssemblies = module.GetReferencedAssemblies();

        foreach (AssemblyName referencedAssemblyName in referencedAssemblies) {
            string fullPathToReferencedAssembly = string.Format(@"{0}\{1}.dll", 
moduleDirectory, referencedAssemblyName.Name);
            // we only add referenced assemblies which are located in given directory
            if (File.Exists(fullPathToReferencedAssembly) && 
!referenceList.Contains(fullPathToReferencedAssembly))
                referenceList.Add(fullPathToReferencedAssembly);
        }
    }
}

Reply via email to