c# - 枚举所有没有 mscoree 的 AppDomains

标签 c# .net pinvoke appdomain

如何在不引用 mscoree 的情况下枚举所有进程的域。是否可以?我从 2007 年的某个地方在互联网上找到了一些解决方案。但它枚举并清空了集合。

代码如下:

public static class DomainHelper
{
    public static AppDomain[] LoadedDomains
    {
        get
        {
            var loadedDomains = new List<AppDomain>();
            var runtimeHost = new CorRuntimeHost() as ICorRuntimeHost;

            try
            {
                var enumeration = IntPtr.Zero;
                runtimeHost.EnumDomains(out enumeration);

                try
                {
                    object nextDomain = null;
                    runtimeHost.NextDomain(enumeration, ref nextDomain);

                    while (nextDomain != null)
                    {
                        loadedDomains.Add((AppDomain) nextDomain);
                        nextDomain = null;
                        runtimeHost.NextDomain(enumeration, ref nextDomain);
                    }
                }
                finally
                {
                    runtimeHost.CloseEnum(enumeration);
                }
            }
            finally
            {
                Marshal.ReleaseComObject(runtimeHost);
            }

            return loadedDomains.ToArray();
        }
    }

    [ComImport]
    [Guid("CB2F6723-AB3A-11d2-9C40-00C04FA30A3E")]
    private class CorRuntimeHost // : ICorRuntimeHost
    {}

    [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICorRuntimeHost
    {
        void CloseEnum(IntPtr enumHandle);
        void CreateDomain();
        void CreateDomainEx();
        void CreateDomainSetup();
        void CreateEvidence();
        void CreateLogicalThreadState();
        void CurrentDomain();
        void DeleteLogicalThreadState();
        void EnumDomains(out IntPtr enumHandle);
        void GetConfiguration();
        void GetDefaultDomain();
        void LocksHeldByLogicalThread();
        void MapFile();
        void NextDomain(IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] ref object appDomain);
        void Start();
        void Stop();
        void SwitchInLogicalThreadState();
        void SwitchOutLogicalThreadState();
        void UnloadDomain();
    }
}

最佳答案

不引用 mscoree.tlb 是给您带来麻烦的原因,ICorRuntimeHost 被声明为错误。方法顺序完全困惑,不清楚这是怎么发生的。早在 2007 年,生活也简单得多,托管接口(interface)针对 .NET 4.0 进行了彻底的重新设计,并且 ICorRuntimeHost 已被弃用。不过它仍然有效,肯定会持续一段时间。

我将发布在 .NET 4.0 及更高版本上运行的代码。正确的方法是从 ICLRMetaHost 开始。然后获取您感兴趣的运行时实例的 ICLRRuntimeInfo 实例。请记住,.NET 4.0 支持 CLR 的进程内并行实例化,您需要找到您的代码正在使用的实例。然后,ICLRRuntimeInfo::GetInterface() 方法可以将实例返回到旧 ICorRuntimeHost 接口(interface)。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public static class CLRUtil {
    public static IEnumerable<_AppDomain> EnumAppDomains() {
        // Obtain ICLRMetaHost interface
        object objHost;
        int hr = CLRCreateInstance(ref CLSID_CLRMetaHost, ref IID_CLRMetaHost, out objHost);
        if (hr < 0) throw new COMException("Cannot create meta host", hr);
        var host = (ICLRMetaHost)objHost;

        // Obtain ICLRRuntimeInfo interface
        var vers = Environment.Version;
        var versString = string.Format("v{0}.{1}.{2}", vers.Major, vers.Minor, vers.Build);
        var objRuntime = host.GetRuntime(versString, ref IID_CLRRuntimeInfo);
        var runtime = (ICLRRuntimeInfo)objRuntime;
        bool started;
        uint flags;
        runtime.IsStarted(out started, out flags);
        if (!started) throw new COMException("CLR not started??");

        // Obtain legacy ICorRuntimeHost interface and iterate appdomains
        var V2Host = (ICorRuntimeHost)runtime.GetInterface(ref CLSID_CorRuntimeHost, ref IID_CorRuntimeHost);
        IntPtr hDomainEnum;
        V2Host.EnumDomains(out hDomainEnum);
        for (;;) {
            _AppDomain domain = null;
            V2Host.NextDomain(hDomainEnum, out domain);
            if (domain == null) break;
            yield return domain;
        }
        V2Host.CloseEnum(hDomainEnum);
    }

    private static Guid CLSID_CLRMetaHost = new Guid(0x9280188d, 0xe8e, 0x4867, 0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde);
    private static Guid IID_CLRMetaHost = new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16);
    private static Guid IID_CLRRuntimeInfo = new Guid(0xBD39D1D2, 0xBA2F, 0x486a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91);
    private static Guid CLSID_CorRuntimeHost = new Guid(0xcb2f6723, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e);
    private static Guid IID_CorRuntimeHost = new Guid(0xcb2f6722, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e);

    [DllImport("mscoree.dll")]
    private static extern int CLRCreateInstance(ref Guid clsid, ref Guid iid,
        [MarshalAs(UnmanagedType.Interface)] out object ptr);

    [ComImport, Guid("D332DB9E-B9B3-4125-8207-A14884F53216"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICLRMetaHost {
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetRuntime(string version, ref Guid iid);
        // Rest omitted
    }

    [ComImport, Guid("BD39D1D2-BA2F-486a-89B0-B4B0CB466891"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICLRRuntimeInfo {
        void GetVersionString(char[] buffer, int bufferLength);
        void GetRuntimeDirectory(char[] buffer, int bufferLength);
        bool IsLoaded(IntPtr hProcess);
        void LoadErrorString(uint id, char[] buffer, int bufferLength, int lcid);
        void LoadLibrary(string path, out IntPtr hMdodule);
        void GetProcAddress(string name, out IntPtr addr);
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetInterface(ref Guid clsid, ref Guid iid);
        bool IsLoadable();
        void SetDefaultStartupFlags(uint flags, string configFile);
        void GetDefaultStartupFlags(out uint flags, char[] configFile, int configFileLength);
        void BindAsLegacyV2Runtime();
        void IsStarted(out bool started, out uint flags);
    }

    [ComImport, Guid("CB2F6722-AB3A-11d2-9C40-00C04FA30A3E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICorRuntimeHost {
        void CreateLogicalThreadState();
        void DeleteLogicalThreadState();
        void SwitchinLogicalThreadState(IntPtr cookie);
        void SwitchoutLogicalThreadState(out IntPtr cookie);
        void LocksHeldByLogicalThread(out int count);
        void MapFile(IntPtr hFile, out IntPtr address);
        void GetConfiguration(out IntPtr config);
        void Start();
        void Stop();
        void CreateDomain(string name, object identity, out _AppDomain domain);
        void GetDefaultDomain(out _AppDomain domain);
        void EnumDomains(out IntPtr hEnum);
        void NextDomain(IntPtr hEnum, out _AppDomain domain);
        void CloseEnum(IntPtr hEnum);
        // rest omitted
    }
}

示例用法:

class Program {
    static void Main(string[] args) {
        AppDomain.CreateDomain("Example");
        foreach (var domain in CLRUtil.EnumAppDomains()) {
            Console.WriteLine("Found appdomain {0}", domain.FriendlyName);
        }
        Console.ReadLine();
    }
}

输出:

Found appdomain ConsoleApplication1.vshost.exe
Found appdomain Example

关于c# - 枚举所有没有 mscoree 的 AppDomains,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33890264/

相关文章:

c# - 多键数据结构

c# - VB.NET下的Late Binding Magic转换为C#

c# - 我什么时候可以保证一个线程上更改的值对其他线程可见?

c - 将 C dll 方法导出到 c# P/Invoke

c# - 如何在 C# 中使用 WM_Close?

c# - 如何正确处理 pinvoke/非托管代码

c# - Model和ViewModel一模一样怎么办?

c# - 从 JSON 字符串中反序列化选定的 JSON 对象

c# - 复制文件时服务器变慢

.net - Azure Graph .Net SDK 用户选择参数不区分大小写,但成员不区分大小写