Как определить основной процесс программы? [Дубликат]

Другой общий случай, когда можно получить это исключение, включает в себя насмешливые классы во время модульного тестирования. Независимо от используемой насмешливой структуры, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом высмеиваются. В частности, все свойства HttpContext, на которые ссылается тестируемый код, должны быть изделены.

См. « Исключение NullReferenceException при проверке пользовательского AuthorizationAttribute » для несколько подробного примера.

72
задан abatishchev 25 January 2009 в 00:34
поделиться

6 ответов

Этот код обеспечивает хороший интерфейс для поиска объекта родительского процесса и учитывает возможность нескольких процессов с тем же именем:

Использование:

Console.WriteLine("ParentPid: " + Process.GetProcessById(6972).Parent().Id);

Код:

public static class ProcessExtensions {
    private static string FindIndexedProcessName(int pid) {
        var processName = Process.GetProcessById(pid).ProcessName;
        var processesByName = Process.GetProcessesByName(processName);
        string processIndexdName = null;

        for (var index = 0; index < processesByName.Length; index++) {
            processIndexdName = index == 0 ? processName : processName + "#" + index;
            var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
            if ((int) processId.NextValue() == pid) {
                return processIndexdName;
            }
        }

        return processIndexdName;
    }

    private static Process FindPidFromIndexedProcessName(string indexedProcessName) {
        var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
        return Process.GetProcessById((int) parentId.NextValue());
    }

    public static Process Parent(this Process process) {
        return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
    }
}
48
ответ дан strager 31 August 2018 в 10:36
поделиться
  • 1
    Где определяется метод float.As? – Mark Byers 21 April 2010 в 12:16
  • 2
    Это некоторые удивительно плохо названные методы. – Mark 19 November 2010 в 20:09
  • 3
    В моем тестировании это намного медленнее решения Саймона Моуриера. Кроме того, он, к сожалению, делает какой-то механизм «довести процесс до фронта». Я не знаю, почему. Кто-нибудь еще испытал это? Тест, который я запускаю для этого, - это загрузочный загрузочный файл EXE, созданный Visual Studio, который запускает установщик Windows MSIEXEC.exe. – Tyler Collier 26 March 2011 в 01:39
  • 4
    К сожалению, это не работает, когда имя категории счетчика производительности локализовано (например, на неанглийском языке Windows). – LukeSw 5 June 2012 в 11:01
  • 5
    Я бы предложил версию Саймона, если нет на то причин, потому что разница в производительности значительна. – David Burton 12 June 2012 в 17:14

Если вы принимаете P / Invoke, есть лучший способ, который более документирован, чем NtQueryInformationProcess: PROCESSENTRY32 (CreateToolhelp32Snapshot, Process32First, Process32Next). Это показано в этом сообщении .

Обратите внимание на тонкие детали и обратите внимание, что родительский PID не обязательно является идентификатором создателя, на самом деле это может быть совершенно не связанным, о чем сообщают комментарии сообщества в ] PROCESSENTRY32 .

3
ответ дан Community 31 August 2018 в 10:36
поделиться

Вот моя попытка в управляемом решении.

Он проверяет счетчики производительности для всех процессов и возвращает словарь дочернего PID родительскому PID. Затем вы можете проверить словарь с вашим текущим идентификатором PID, чтобы увидеть своего родителя, дедушку и т. Д.

Это слишком много информации о том, сколько информации оно получает. Невозможно оптимизировать.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace PidExamples
{
    class ParentPid
    {
        static void Main(string[] args)
        {
            var childPidToParentPid = GetAllProcessParentPids();
            int currentProcessId = Process.GetCurrentProcess().Id;

            Console.WriteLine("Current Process ID: " + currentProcessId);
            Console.WriteLine("Parent Process ID: " + childPidToParentPid[currentProcessId]);
        }

        public static Dictionary<int, int> GetAllProcessParentPids()
        {
            var childPidToParentPid = new Dictionary<int, int>();

            var processCounters = new SortedDictionary<string, PerformanceCounter[]>();
            var category = new PerformanceCounterCategory("Process");

            // As the base system always has more than one process running, 
            // don't special case a single instance return.
            var instanceNames = category.GetInstanceNames();
            foreach(string t in instanceNames)
            {
                try
                {
                    processCounters[t] = category.GetCounters(t);
                }
                catch (InvalidOperationException)
                {
                    // Transient processes may no longer exist between 
                    // GetInstanceNames and when the counters are queried.
                }
            }

            foreach (var kvp in processCounters)
            {
                int childPid = -1;
                int parentPid = -1;

                foreach (var counter in kvp.Value)
                {
                    if ("ID Process".CompareTo(counter.CounterName) == 0)
                    {
                        childPid = (int)(counter.NextValue());
                    }
                    else if ("Creating Process ID".CompareTo(counter.CounterName) == 0)
                    {
                        parentPid = (int)(counter.NextValue());
                    }
                }

                if (childPid != -1 && parentPid != -1)
                {
                    childPidToParentPid[childPid] = parentPid;
                }
            }

            return childPidToParentPid;
        }
    }
}    

В других новостях я узнал, сколько счетчиков производительности на моей машине: 13401. Святая корова.

4
ответ дан Jeremy Murray 31 August 2018 в 10:36
поделиться
  • 1
    Этот метод работает, но, кажется, очень медленный. Это заняло более 10 секунд на моей машине. – Karsten 16 May 2017 в 12:32

Если вы когда-либо выкапывали BCL, вы обнаружите, что способы поиска родительского процесса сознательно избегают, возьмите это, например:

https://referencesource.microsoft.com /#System/services/monitoring/system/diagnosticts/ProcessManager.cs,327

Как вы можете видеть в исходном коде, он содержит комплексные структуры и импортированные собственные методы, которые абсолютно достаточны для справиться с работой. Однако, даже если вы обращаетесь к ним через рефлексию (это возможно), вы не найдете метода для этого. Я не могу ответить, почему, но это явление вызывает несколько повторений таких вопросов, как ваша. например:

Как я могу получить PID родительского процесса моего приложения

Поскольку нет ответа вместе с некоторым кодом с помощью CreateToolhelp32Snapshot в этом потоке я бы добавил - часть определений структуры и имен, которые я ворую из исходного источника MS:)

  • Код
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Linq;
    using System;
    
    public static class Toolhelp32 {
        public const uint Inherit = 0x80000000;
        public const uint SnapModule32 = 0x00000010;
        public const uint SnapAll = SnapHeapList|SnapModule|SnapProcess|SnapThread;
        public const uint SnapHeapList = 0x00000001;
        public const uint SnapProcess = 0x00000002;
        public const uint SnapThread = 0x00000004;
        public const uint SnapModule = 0x00000008;
    
        [DllImport("kernel32.dll")]
        static extern bool CloseHandle(IntPtr handle);
        [DllImport("kernel32.dll")]
        static extern IntPtr CreateToolhelp32Snapshot(uint flags, int processId);
    
        public static IEnumerable<T> TakeSnapshot<T>(uint flags, int id) where T : IEntry, new() {
            using(var snap = new Snapshot(flags, id))
                for(IEntry entry = new T { }; entry.TryMoveNext(snap, out entry);)
                    yield return (T)entry;
        }
    
        public interface IEntry {
            bool TryMoveNext(Toolhelp32.Snapshot snap, out IEntry entry);
        }
    
        public struct Snapshot:IDisposable {
            void IDisposable.Dispose() {
                Toolhelp32.CloseHandle(m_handle);
            }
            public Snapshot(uint flags, int processId) {
                m_handle=Toolhelp32.CreateToolhelp32Snapshot(flags, processId);
            }
            IntPtr m_handle;
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct WinProcessEntry:Toolhelp32.IEntry {
        [DllImport("kernel32.dll")]
        public static extern bool Process32Next(Toolhelp32.Snapshot snap, ref WinProcessEntry entry);
    
        public bool TryMoveNext(Toolhelp32.Snapshot snap, out Toolhelp32.IEntry entry) {
            var x = new WinProcessEntry { dwSize=Marshal.SizeOf(typeof(WinProcessEntry)) };
            var b = Process32Next(snap, ref x);
            entry=x;
            return b;
        }
    
        public int dwSize;
        public int cntUsage;
        public int th32ProcessID;
        public IntPtr th32DefaultHeapID;
        public int th32ModuleID;
        public int cntThreads;
        public int th32ParentProcessID;
        public int pcPriClassBase;
        public int dwFlags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public String fileName;
        //byte fileName[260];
        //public const int sizeofFileName = 260;
    }
    
    public static class Extensions {
        public static Process Parent(this Process p) {
            var entries = Toolhelp32.TakeSnapshot<WinProcessEntry>(Toolhelp32.SnapAll, 0);
            var parentid = entries.First(x => x.th32ProcessID==p.Id).th32ParentProcessID;
            return Process.GetProcessById(parentid);
        }
    }
    

И мы можем использовать его как:

  • Тест
    public class TestClass {
        public static void TestMethod() {
            var p = Process.GetCurrentProcess().Parent();
            Console.WriteLine("{0}", p.Id);
        }
    }
    

Для альтернативного окончания ..

Согласно документации, существует пара итерационных методов для каждого типа записей, таких как Process32First и Process32Next, для итерации процессов; но я обнаружил, что методы «xxxxFirst» не нужны, и тогда я подумал, почему бы не поместить метод итерации с соответствующим типом записи? Было бы проще реализовать и понять (я думаю, так ..).

Так же, как Toolhelp32, суффикс с помощью help , я считаю, что статический вспомогательный класс является правильным, так что мы можем иметь ясные квалифицированные имена, такие как Toolhelp32.Snapshot или Toolhelp32.IEntry хотя это было бы неуместно здесь.

Как только родительский процесс будет получен, если вы хотите получить подробную информацию, вы можете легко расширить его, например, итерации по своим модулям, а затем добавить :

  • Код - WinModuleEntry
    [StructLayout(LayoutKind.Sequential)]
    public struct WinModuleEntry:Toolhelp32.IEntry { // MODULEENTRY32
        [DllImport("kernel32.dll")]
        public static extern bool Module32Next(Toolhelp32.Snapshot snap, ref WinModuleEntry entry);
    
        public bool TryMoveNext(Toolhelp32.Snapshot snap, out Toolhelp32.IEntry entry) {
            var x = new WinModuleEntry { dwSize=Marshal.SizeOf(typeof(WinModuleEntry)) };
            var b = Module32Next(snap, ref x);
            entry=x;
            return b;
        }
    
        public int dwSize;
        public int th32ModuleID;
        public int th32ProcessID;
        public int GlblcntUsage;
        public int ProccntUsage;
        public IntPtr modBaseAddr;
        public int modBaseSize;
        public IntPtr hModule;
        //byte moduleName[256];
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string moduleName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string fileName;
        //byte fileName[260];
        //public const int sizeofModuleName = 256;
        //public const int sizeofFileName = 260;
    }
    
    и некоторый тест ..
    public class TestClass {
        public static void TestMethod() {
            var p = Process.GetCurrentProcess().Parent();
            Console.WriteLine("{0}", p.Id);
    
            var formatter = new CustomFormatter { };
            foreach(var x in Toolhelp32.TakeSnapshot<WinModuleEntry>(Toolhelp32.SnapModule, p.Id)) {
                Console.WriteLine(String.Format(formatter, "{0}", x));
            }
        }
    }
    
    public class CustomFormatter:IFormatProvider, ICustomFormatter {
        String ICustomFormatter.Format(String format, object arg, IFormatProvider formatProvider) {
            var type = arg.GetType();
            var fields = type.GetFields();
            var q = fields.Select(x => String.Format("{0}:{1}", x.Name, x.GetValue(arg)));
            return String.Format("{{{0}}}", String.Join(", ", q.ToArray()));
        }
    
        object IFormatProvider.GetFormat(Type formatType) {
            return typeof(ICustomFormatter)!=formatType ? null : this;
        }
    }
    

Если вам нужен пример кода ..

1
ответ дан Ken Kin 31 August 2018 в 10:36
поделиться

Таким образом:

public static Process GetParent(this Process process)
{
  try
  {
    using (var query = new ManagementObjectSearcher(
      "SELECT * " +
      "FROM Win32_Process " +
      "WHERE ProcessId=" + process.Id))
    {
      return query
        .Get()
        .OfType<ManagementObject>()
        .Select(p => Process.GetProcessById((int)(uint)p["ParentProcessId"]))
        .FirstOrDefault();
    }
  }
  catch
  {
    return null;
  }
}
5
ответ дан Péter Major 31 August 2018 в 10:36
поделиться
  • 1
    Работает, но WMI может быть супер-медленным (секунды). Pinvoke - это путь. – Alastair Maw 23 March 2018 в 18:23

Вот решение. Он использует p / invoke, но, похоже, работает хорошо, 32 или 64 процессора:

    /// <summary>
    /// A utility class to determine a process parent.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct ParentProcessUtilities
    {
        // These members must match PROCESS_BASIC_INFORMATION
        internal IntPtr Reserved1;
        internal IntPtr PebBaseAddress;
        internal IntPtr Reserved2_0;
        internal IntPtr Reserved2_1;
        internal IntPtr UniqueProcessId;
        internal IntPtr InheritedFromUniqueProcessId;

        [DllImport("ntdll.dll")]
        private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);

        /// <summary>
        /// Gets the parent process of the current process.
        /// </summary>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess()
        {
            return GetParentProcess(Process.GetCurrentProcess().Handle);
        }

        /// <summary>
        /// Gets the parent process of specified process.
        /// </summary>
        /// <param name="id">The process id.</param>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess(int id)
        {
            Process process = Process.GetProcessById(id);
            return GetParentProcess(process.Handle);
        }

        /// <summary>
        /// Gets the parent process of a specified process.
        /// </summary>
        /// <param name="handle">The process handle.</param>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess(IntPtr handle)
        {
            ParentProcessUtilities pbi = new ParentProcessUtilities();
            int returnLength;
            int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
            if (status != 0)
                throw new Win32Exception(status);

            try
            {
                return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
            }
            catch (ArgumentException)
            {
                // not found
                return null;
            }
        }
    }
118
ответ дан Simon Mourier 31 August 2018 в 10:36
поделиться
  • 1
    На самом деле это управляется, но не переносится на другую ОС, чем Windows, вы правы. Однако понятие родительского процесса также не переносится, поскольку оно не относится к самой платформе .NET Framework, поэтому я не думаю, что это большая проблема. – Simon Mourier 28 July 2010 в 08:57
  • 2
    Большой! Никаких медленных перфомансов. Я действительно ненавижу «не управляемый». Комментарии. Как запросить персидский счетчик более управляемым, а затем использовать P / Invoke. – Jabe 27 August 2011 в 23:51
  • 3
    К сожалению, эта функция только внутренняя. MSDN говорит, что это «[NtQueryInformationProcess может быть изменен или недоступен в будущих версиях Windows. Приложения должны использовать альтернативные функции, перечисленные в этом разделе.] & Quot; [Д0] msdn.microsoft.com/en-us/library/windows/desktop/… – justin.m.chase 18 January 2012 в 00:04
  • 4
    @ justin.m.chase - Он существует уже почти 20 лет, поэтому я сомневаюсь, что он будет удален завтра, и нет никаких дополнительных функций NT, которые дают родительский процесс моим знаниям, но да, конечно, используйте на свой страх и риск , – Simon Mourier 18 January 2012 в 00:19
  • 5
    У меня была система, которая использовала счетчики производительности для получения родительского идентификатора. К сожалению, когда цикл 300+ процессов и создание счетчиков производительности просто для получения родительского идентификатора, производительность была ужасной. Я предпочел бы избежать прямых вызовов Win32 API, но разница заключалась в остановке службы за 1 секунду, а не в минутах, используя версию PerformanceCounter. В результате на сервере, на котором запущено множество сервисов, это основная версия, которая, вероятно, будет подходящей по соображениям производительности. – David Burton 12 June 2012 в 17:13
Другие вопросы по тегам:

Похожие вопросы: