在流程中创建新的appdomain时通知

时间:2014-04-24 08:00:32

标签: c# .net

考虑下一个情况。我已经使用EasyHook将我的托管dll注入到进程中。 EasyHook使用单独的AppDomain注入dll。现在我需要一种方法来获取有关在当前进程中创建新AppDomain的通知。 所以问题是在进程中创建新的AppDomain时有没有办法收到通知?

1 个答案:

答案 0 :(得分:3)

没有事件或简单的方法,有一个COM中断,允许您获取加载的应用程序域列表,但任何事件等都隐藏在私人接口上。

有两种方法可以做到这一点,但两者都要求您主动寻找信息,即没有事件要注册。

  1. 使用性能计数器。
  2. 使用mscoree COM中断。
  3. 这两个选项可以相互补充,但它取决于您需要的信息级别。

    使用效果计数器

    CLR有许多可用的性能计数器,但我们关心的那个属于“.Net CLR Loading”类别,它是一个名为“Total Appdomains”的计数器。

    使用System.Diagnostics命名空间,您可以获得在您的计算机上运行的每个实例/进程的应用程序域数。

    与下面的代码一样:

    PerformanceCounter toPopulate = new PerformanceCounter(".Net CLR Loading", "Total Appdomains", "ConsoleApplication2.vshost", true);
    
    Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());
    

    (请注意,如果您创建自己的应用程序,示例需要应用程序实例名称,请确保更改此内容)

    您可以将其换行循环,并在数字更改时为您的应用提高偶数。 (虽然不优雅,但目前无法绕过它)

    使用mscoree COM中断

    此外,如果您想要列出流程中的所有应用程序域,则需要使用MSCOREE.TBL库,这是CLRHost使用的COM库。

    您可以在C:\ WINDOWS \ Microsoft.NET \ Framework \ vXXXXXX \ mscoree.tlb找到该库 使用mscoree;

    如果在窗口7或更高版本上使用它,则必须确保参考属性中的嵌入装配类型已关闭,因为此装配不能像这样嵌入。 请参阅此堆栈帖子的更多信息:Interop type cannot be embedded

    请参阅下面的代码,了解如何返回并列出流程中的所有应用域(这将返回每个应用域的实际AppDomain实例)。 可以在此处找到原始堆栈帖子: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);
        }
    }
    

    既然您可以看到流程中存在多少个应用域并列出它们,请将其放入测试中。

    以下是使用这两种技术的完整工作示例。

    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);
                }
            }
        }
    }
    

    我希望这有用,如果您需要任何进一步的帮助,请告诉我们。