考虑下一个情况。我已经使用EasyHook将我的托管dll注入到进程中。 EasyHook使用单独的AppDomain注入dll。现在我需要一种方法来获取有关在当前进程中创建新AppDomain的通知。 所以问题是在进程中创建新的AppDomain时有没有办法收到通知?
答案 0 :(得分:3)
没有事件或简单的方法,有一个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);
}
}
}
}
我希望这有用,如果您需要任何进一步的帮助,请告诉我们。