Question

Consider next situation. I have injected my managed dll into the process using EasyHook. EasyHook injects dll using separate AppDomain. Now I need a way to get notifications about creation of new AppDomain in the current process. So the question is there a way do get notifications when a new AppDomain was created in the process?

Was it helpful?

Solution

There is no event or easy way to do it, there is a COM interrupt that allows you to get a list of app domains loaded but any events etc are all hidden from us on private interfaces.

There is two ways you could do this but both require you to actively seek the information i.e. there is no event to register too.

  1. Using Performance Counters.
  2. Using mscoree COM interrupt.

Both there options can complement each other but it depends what level of information you need.

Using Performance Counters

CLR has numerous performance counters available but the one we care about resides in the category ".Net CLR Loading" and it is the counter called "Total Appdomains".

Using the System.Diagnostics namespace you can get the number of app domains per instance/process running in you machine.

Like the code below:

PerformanceCounter toPopulate = new PerformanceCounter(".Net CLR Loading", "Total Appdomains", "ConsoleApplication2.vshost", true);

Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());

(please note the example needs the application instance name if you create your own app make sure to change this)

You can wrap this on a loop and raise an even for your app when the number changes. (Not elegant but there is no way around it at the moment)

Using mscoree COM interrupt

Further more if you want to List all the app domains in a process you need to make use the MSCOREE.TBL library which is a COM library used by the CLRHost.

You can find the library at C:\WINDOWS\Microsoft.NET\Framework\vXXXXXX\mscoree.tlb using mscoree;

If you are using it on window 7 or above you must make sure that the embed assembly type in the reference properties is turned off as this assembly can not be embedded like that. See further information on this stack post: Interop type cannot be embedded

See the code below to see how you can return and list all app domains in a process (this will return the actual AppDomain instances for each app domain). The original stack post for this can be found here: List AppDomains in Process

public static List<AppDomain> GetAppDomains()
{
    List<AppDomain> _IList = new List<AppDomain>();
    IntPtr enumHandle = IntPtr.Zero;
    CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
    try
    {
        host.EnumDomains(out enumHandle);
        object domain = null;
        while (true)
        {
            host.NextDomain(enumHandle, out domain);
            if (domain == null) break;
            AppDomain appDomain = (AppDomain)domain;
            _IList.Add(appDomain);
        }
        return _IList;
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        return null;
    }
    finally
    {
        host.CloseEnum(enumHandle);
        Marshal.ReleaseComObject(host);
    }
}

Now that you can see how many app domains exist in a process and list them let put that to the test.

Below is a fully working example using both techniques.

using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.Linq;
using System.Printing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Xps.Packaging;
using System.Runtime.InteropServices;
using mscoree;
using System.Diagnostics;
using System.Threading;                           

namespace ConsoleApplication2
{
    class AppDomainWorker
    {
        public void DoSomeWork()
        {
            while (true)
            {
                for (int i = 0; i < 1000; i++)
                {
                    var hello = "hello world".GetHashCode();
                }
                Thread.Sleep(500);
            }
        }
    }

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            PerformanceCounter toPopulate = new PerformanceCounter(".Net CLR Loading", "Total Appdomains", "ConsoleApplication2.vshost", true);

            Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());

            for (int i = 0; i < 10; i++)
            {
                AppDomain domain = AppDomain.CreateDomain("App Domain " + i);
                domain.DoCallBack(() => new Thread(new AppDomainWorker().DoSomeWork).Start());

                Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());
            }

            Console.WriteLine("List all app domains");
            GetAppDomains().ForEach(a => {
                Console.WriteLine(a.FriendlyName);
            });

            Console.WriteLine("running, press any key to stop");

            Console.ReadKey();        
        }

        public static List<AppDomain> GetAppDomains()
        {
            List<AppDomain> _IList = new List<AppDomain>();
            IntPtr enumHandle = IntPtr.Zero;
            CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
            try
            {
                host.EnumDomains(out enumHandle);
                object domain = null;
                while (true)
                {
                    host.NextDomain(enumHandle, out domain);
                    if (domain == null) break;
                    AppDomain appDomain = (AppDomain)domain;
                    _IList.Add(appDomain);
                }
                return _IList;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
            finally
            {
                host.CloseEnum(enumHandle);
                Marshal.ReleaseComObject(host);
            }
        }
    }
}

I hope this is helpful and if you need any further help let us know.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top