【问题标题】:Notify when new appdomain created in the process在进程中创建新的 appdomain 时通知
【发布时间】:2014-04-24 08:00:31
【问题描述】:

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

【问题讨论】:

  • 您需要更多帮助吗?
  • 我选择了两害相权取其轻。创建了一个计时器并定期检查应用程序域。但如果有一个可以订阅的事件会更好。
  • 是的,有一个接口有一个由 CLR 主机使用的事件,但不能使用它。有人需要提出功能请求。

标签: c# .net easyhook


【解决方案1】:

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

您有两种方法可以做到这一点,但都需要您积极寻找信息,即也没有要注册的活动。

  1. 使用性能计数器。
  2. 使用 mscoree COM 中断。

这两个选项可以相互补充,但这取决于您需要什么级别的信息。

使用性能计数器

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

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

【讨论】:

  • 非常感谢。我使用了您描述的第二种方法。
  • 不用担心,我很高兴它有帮助
猜你喜欢
  • 1970-01-01
  • 2021-06-17
  • 2012-01-28
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多