【问题标题】:Enumerate all AppDomains without mscoree枚举所有没有 mscoree 的 AppDomain
【发布时间】:2015-11-24 09:47:49
【问题描述】:

如何在不引用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();
    }
}

【问题讨论】:

    标签: c# .net pinvoke appdomain


    【解决方案1】:

    不引用 mscoree.tlb 会让您陷入麻烦,ICorRuntimeHost 被声明为错误。方法顺序完全混乱,不清楚是怎么回事。早在 2007 年,生活也变得简单多了,托管接口针对 .NET 4.0 进行了彻底的重新设计,并且不推荐使用 ICorRuntimeHost。但它仍然有效,肯定会持续一段时间。

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-11
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多