我希望通过调用Process.Start()
来获取刚刚开始的流程主窗口的句柄。
当进程尚未运行时,这很容易,因为Process.Start()
的结果不为空:
var process = Process.Start(fileName);
if (process != null)
{
var handle = process.MainWindowHandle;
}
但是,如果进程已在运行,则结果为null。在这种情况下,是否有任何方式(托管或其他方式)告知请求的路由位置以及哪个进程消耗了启动请求?
答案 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获取进程有三种可能性。按可执行文件名称,但其中两个有重大缺点:
Process.GetProcessesByName(string)
Process.GetProcesses()
迭代整个数组或一些LINQ-select 最后一种可能性是使用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;
}
}
}