我需要检查程序(xyz.exe)是否在运行,但只针对当前用户。使用的任何方法都不能需要提升的权限,并且必须快速运行(因此WMI不可用)。
Process.GetProcessesByName("xyz")
返回所有已登录用户的"xyz"结果...但我只关心当前用户。
有什么想法吗?
SessionId
来过滤流程列表: public static bool IsProcessRunningSameSession(string processName)
{
var currentSessionID = Process.GetCurrentProcess().SessionId;
return Process.GetProcessesByName(processName).Where(p => p.SessionId == currentSessionID).Any();
}
我在这里找到了答案: http://dotbay.blogspot.com/2009/06/finding-owner-of-process-in-c.html
如果那个博客不再存在,我会复制/粘贴它。
////
// 'WindowsIdentity' Extension Method Demo:
// Enumerate all running processes with their associated Windows Identity
////
foreach (var p in Process.GetProcesses())
{
string processName;
try
{
processName = p.WindowsIdentity().Name;
}
catch (Exception ex)
{
processName = ex.Message; // Probably "Access is denied"
}
Console.WriteLine(p.ProcessName + " (" + processName + ")");
}
//-----------------------------------------------------------------------
// <copyright file="ProcessExtensions.cs" company="DockOfTheBay">
// http://www.dotbay.be
// </copyright>
// <summary>Defines the ProcessExtensions class.</summary>
//-----------------------------------------------------------------------
namespace DockOfTheBay
{
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
/// <summary>
/// Extension Methods for the System.Diagnostics.Process Class.
/// </summary>
public static class ProcessExtensions
{
/// <summary>
/// Required to query an access token.
/// </summary>
private static uint TOKEN_QUERY = 0x0008;
/// <summary>
/// Returns the WindowsIdentity associated to a Process
/// </summary>
/// <param name="process">The Windows Process.</param>
/// <returns>The WindowsIdentity of the Process.</returns>
/// <remarks>Be prepared for 'Access Denied' Exceptions</remarks>
public static WindowsIdentity WindowsIdentity(this Process process)
{
IntPtr ph = IntPtr.Zero;
WindowsIdentity wi = null;
try
{
OpenProcessToken(process.Handle, TOKEN_QUERY, out ph);
wi = new WindowsIdentity(ph);
}
catch (Exception)
{
throw;
}
finally
{
if (ph != IntPtr.Zero)
{
CloseHandle(ph);
}
}
return wi;
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
}
}
if(processName.Contains(Environment.UserName)){...}
- ltwallyEnvironment.UserName
,可以使用 WindowsIdentity.GetCurrent().Name
。 - Todd A. Stedel这是完整的程序。它是一个命令行C#应用程序。它很丑,没有注释。但它能工作。你输入一个EXE的名称(包括路径),它会检查它是否已经在运行,如果没有,就启动它。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace SingleRun
{
class Program
{
static void Main(string[] args)
{
string path = "";
var prog = "";
if (args.Length == 0) {
MessageBox.Show("Please include a program to start.\n\nExample: \nSingleRun.exe \"C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe\"", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
System.Environment.Exit(1);
}else{
path = args[0];
if (!File.Exists(path)) {
MessageBox.Show("\"" + path + "\" does not exist.\nPlease check the location.\nAnything with spaces in it needs to be inside double-quotes.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
System.Environment.Exit(1);
}else{
var splits = path.Split('\\');
prog = splits[splits.Length - 1];
foreach (var p in Process.GetProcessesByName(prog.Replace(".exe",""))) {
string processOwner;
try {
processOwner = p.WindowsIdentity().Name;
}
catch (Exception ex) {
processOwner = ex.Message; // Probably "Access is denied"
}
if (processOwner.Contains(Environment.UserName)) {
MessageBox.Show("Program already running with PID " + p.Id, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
System.Environment.Exit(1);
}
}
Process newProcess = Process.Start(path);
Console.WriteLine("Launching " + prog + " with PID: " + newProcess.Id);
}
}
}
}
/// <summary>
/// Extension Methods for the System.Diagnostics.Process Class.
/// </summary>
public static class ProcessExtensions {
/// <summary>
/// Required to query an access token.
/// </summary>
private static uint TOKEN_QUERY = 0x0008;
/// <summary>
/// Returns the WindowsIdentity associated to a Process
/// </summary>
/// <param name="process">The Windows Process.</param>
/// <returns>The WindowsIdentity of the Process.</returns>
/// <remarks>Be prepared for 'Access Denied' Exceptions</remarks>
public static WindowsIdentity WindowsIdentity(this Process process) {
IntPtr ph = IntPtr.Zero;
WindowsIdentity wi = null;
try {
OpenProcessToken(process.Handle, TOKEN_QUERY, out ph);
wi = new WindowsIdentity(ph);
}
catch (Exception) {
throw;
}
finally {
if (ph != IntPtr.Zero) {
CloseHandle(ph);
}
}
return wi;
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
}
}
以上代码运行良好。但是如果您只想知道当前用户是否看到了打开的应用程序:如果进程不是来自当前用户,则在尝试获取句柄时已经出现异常。 因此,您可以使用此扩展更简单地完成此操作:
public static bool ProcessAccessibleForCurrentUser(this Process process)
{
try
{
var ptr = process.Handle;
return true;
}
catch
{
return false;
}
}
Process.GetProcessesByName
的想法的地方。但它并没有提供任何过滤用户列表的方法。这正是我正在寻找的。也许我很蠢,但是考虑到我正在寻找超出该链接所包含内容的东西,因此此线程不是重复的。 - ltwallysameAsthisSession
相关的部分匹配当前会话。当前会话是当前用户的会话,因此所有与当前会话匹配的会话ID都应该是正在为当前用户运行的会话。(如果您的代码基于此处的另一篇帖子,请在问题中提供链接以供参考。) - Ken White