我从哪个过程开始?

时间:2015-08-24 09:12:04

标签: c#

我希望通过调用Process.Start()来获取刚刚开始的流程主窗口的句柄。

当进程尚未运行时,这很容易,因为Process.Start()的结果不为空:

var process = Process.Start(fileName);
if (process != null) 
{
   var handle = process.MainWindowHandle;
}

但是,如果进程已在运行,则结果为null。在这种情况下,是否有任何方式(托管或其他方式)告知请求的路由位置以及哪个进程消耗了启动请求?

1 个答案:

答案 0 :(得分:2)

对我而言,这似乎是XY-problem

在开始自己的流程之前,我会检查是否已经从您指定的fileName运行了流程。如果是,则使用您找到的流程的句柄,否则启动您自己的流程。

如果您的fileName是exe或bat或其他类型的可执行文件,则以下方法应该有效。如果它作为文档或文档之类的东西,我非常确定这种方法无需进一步调整就无法工作。

基本上,代码看起来像这样(伪代码!):

//see below for method definition
List<Process> runningProcesses = ProcessUtil.GetProcessesForExecutable(fileName);

Process process;
if(runningProcesses.Count == 0)
{
    process = Process.Start(fileName);
} else
{
    process = runningProcesses[0];
    // maybe some more code to handle more than one running process
}

var handle = process.MainWindowHandle;

剩下的就是ProcessUtil.GetProcessesForExecutable的实施。

通过名称resp获取进程有三种可能性。按可执行文件名称,但其中两个有重大缺点:

  1. Process.GetProcessesByName(string)
    这里的缺点是,进程名称可能与可执行文件名称不同。因此,您可能无法通过为此方法提供文件名来找到正在运行的进程。
  2. Process.GetProcesses()迭代整个数组或一些LINQ-select
    在可执行名称与进程名称方面是安全的,但在我的测试中每次执行700-800ms相当慢。
  3. 最后一种可能性是使用P / Invoke。为什么P / Invoke?事实证明,在我的测试中,这是最快的,每次执行5-6ms 我在使用P / Invoke的项目中实现了一次,受到pinvoke.net的启发:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.InteropServices;
    
    namespace Util
    {
        /// <summary>
        /// Utility methods for processes
        /// </summary>
        public static class ProcessUtil
        {
            //Code is inspired by http://www.pinvoke.net/default.aspx/kernel32.createtoolhelp32snapshot
    
            [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
            static extern IntPtr CreateToolhelp32Snapshot([In]UInt32 dwFlags, [In]UInt32 th32ProcessID);
            [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool Process32First([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
            [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool Process32Next([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
            [DllImport("kernel32", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool CloseHandle([In] IntPtr hObject);
    
            //inner enum used only internally
            [Flags]
            private enum SnapshotFlags : uint
            {
                HeapList = 0x00000001,
                Process = 0x00000002,
                Thread = 0x00000004,
                Module = 0x00000008,
                Module32 = 0x00000010,
                Inherit = 0x80000000,
                All = 0x0000001F,
                NoHeaps = 0x40000000
            }
            //inner struct used only internally
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            private struct PROCESSENTRY32
            {
                const int MAX_PATH = 260;
                internal UInt32 dwSize;
                internal UInt32 cntUsage;
                internal UInt32 th32ProcessID;
                internal IntPtr th32DefaultHeapID;
                internal UInt32 th32ModuleID;
                internal UInt32 cntThreads;
                internal UInt32 th32ParentProcessID;
                internal Int32 pcPriClassBase;
                internal UInt32 dwFlags;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
                internal string szExeFile;
            }
    
            /// <summary>
            /// Returns a list with running processes for a given executable path.
            /// </summary>
            /// <param name="exec">full path to the executable</param>
            /// <returns>a list containing all processes currently run by the given executable</returns>
            public static List<Process> GetProcessesForExecutable(string exec)
            {            
                List<Process> toReturn = new List<Process>();
                IntPtr handleToSnapShot = IntPtr.Zero;
                FileInfo fi = new FileInfo(exec);
    
                if (!fi.Exists)
                {               
                    return toReturn;
                }
    
                try
                {
                    PROCESSENTRY32 procEntry = new PROCESSENTRY32();
                    procEntry.dwSize = (UInt32)Marshal.SizeOf(typeof(PROCESSENTRY32));
                    handleToSnapShot = CreateToolhelp32Snapshot((uint)SnapshotFlags.Process, 0);
    
                    if (Process32First(handleToSnapShot, ref procEntry))
                    {
                        do
                        {
                            if (fi.Name.Equals(procEntry.szExeFile))
                            {
                                Process p = Process.GetProcessById((int)procEntry.th32ProcessID);
                                if (p.MainModule.FileName.Equals(fi.FullName))
                                    toReturn.Add(p);
                            }
                        } while (Process32Next(handleToSnapShot, ref procEntry));
                    }
                }
                catch (Exception ex)
                {
                    //some error handling would be neccessary here
                }
                finally
                {
                    CloseHandle(handleToSnapShot);
                }
                return toReturn;
            }
        }
    }