次の状況を検討します。EasyHook を使用して、マネージ dll をプロセスに挿入しました。EasyHook は、個別の AppDomain を使用して dll を挿入します。ここで、現在のプロセスで新しい AppDomain の作成に関する通知を受け取る方法が必要です。プロセスで新しい AppDomain が作成されたときに通知を受け取る方法はありますか?
1 に答える
イベントやそれを行う簡単な方法はありません。ロードされたアプリ ドメインのリストを取得できる COM 割り込みがありますが、イベントなどはすべてプライベート インターフェイスで非表示になります。
これを行うには 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 割り込みの使用
さらに、プロセス内のすべてのアプリ ドメインを一覧表示する場合は、CLRHost によって使用される COM ライブラリである MSCOREE.TBL ライブラリを使用する必要があります。
ライブラリは、mscoree を使用して C:\WINDOWS\Microsoft.NET\Framework\vXXXXXX\mscoree.tlb にあります。
ウィンドウ 7 以降で使用している場合は、このアセンブリをそのように埋め込むことができないため、参照プロパティの埋め込みアセンブリ タイプがオフになっていることを確認する必要があります。このスタック投稿の詳細を参照してください:相互運用タイプを埋め込むことはできません
プロセス内のすべてのアプリ ドメインを取得して一覧表示する方法については、以下のコードを参照してください (これにより、各アプリ ドメインの実際の 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);
}
}
}
}
これがお役に立てば幸いです。さらにサポートが必要な場合はお知らせください。