【问题标题】:Determine from which location an application was being started确定应用程序从哪个位置启动
【发布时间】:2017-09-07 07:28:18
【问题描述】:

是否有可能确定 c# 应用程序是如何启动的?

就我而言,我想检查此应用程序 (wpf) 是否由位于特定文件夹中的快捷方式启动。

所以,有两种方法可以打开我的应用程序

  • 使用直接快捷方式
  • 启动另一个类似于更新管理器的应用程序以使我的应用程序保持最新。检查后,它使用 Process.Start() 启动我的应用程序

我想确保应用程序只能通过更新管理器启动。

【问题讨论】:

  • 对我来说听起来像 XY problem
  • 要求它接受一个只有 UpdateManager 知道的键的参数。
  • 你解决了这个问题吗?

标签: c# .net wpf process shortcut


【解决方案1】:

您可以使用的一个技巧是检查父进程的 PID,然后获取父进程的一些进程信息。

如果父进程的名称类似于“explorer.exe”,那么应用程序是从快捷方式启动的,或者直接通过在资源管理器上双击它来启动。

否则,它是从另一个应用程序启动的:它可能是您的更新程序应用程序,也可能是与您的更新程序应用程序同名的另一个应用程序...

这意味着您必须重新考虑您希望在多大程度上实现这样的解决方案,以及您希望安全控制有多深。您可以将更新程序中的参数传递给您的主应用程序,或者通过令牌交换实现一些进程间通信......不可能建立一个 100% 安全的系统。

正如上面有人评论的那样,这似乎是一个 XY 问题......或者可能不是。也许这只是一个安全问题。建议您修改您对该软件的具体目标。

如果您需要在 .NET 中检索进程信息的示例代码(通过使用 System.Management),请尝试下面列出的代码。您所要做的就是将它放在一个名为“Updater”的控制台应用程序项目中,并在代码中正确设置主应用程序的路径。

如果您通过在不同情况下启动和关闭 YourApplication.exe 来稍微玩一下这个示例,那么您应该能够看到如下输出:

Parent process 'Updater.exe' [PID=5472]
Parent process 'explorer.exe' [PID=12052]

以下代码在 VS2017 .Net 4.6.1 上测试

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;

class Program
{
    static void Main(string[] args)
    {
        Process.Start(new ProcessStartInfo()
        {
            FileName = "YourApplication.exe" // path to your application
        });

        while (Console.ReadKey(true).Key != ConsoleKey.Escape)
        {
            Process process = Process.GetProcessesByName("YourApplication").FirstOrDefault();  // your application's process name
            if (process == null)
            {
                Console.WriteLine($"Process is not running...");
                continue;
            }
            ProcessManager pm = ProcessManager.FromLocalMachine();
            var processProperties = pm.GetProcessProperties(process.Id);
            int parentProcessId = Convert.ToInt32(processProperties[EProcessProperty.ParentProcessId]);

            try
            {
                var parentProcessProperties = pm.GetProcessProperties(parentProcessId);
                string parentProcessName = parentProcessProperties[EProcessProperty.Name].ToString();
                Console.WriteLine($"Parent process '{parentProcessName ?? "Unknown"}' [PID={parentProcessId}]");
                Console.WriteLine("---------------------------------");
            }
            catch { Console.WriteLine("Parent process information not found."); }
        }
    }
}

public class ProcessConnection
{
    internal ManagementScope ManagementScope { get; }

    internal ProcessConnection(string machineName, string user = null, string password = null, string domain = null)
    {
        ManagementScope = new ManagementScope
        {
            Path = new ManagementPath(@"\\" + machineName + @"\root\CIMV2"),
            Options = new ConnectionOptions
            {
                Impersonation = ImpersonationLevel.Impersonate,
                Authentication = AuthenticationLevel.Default,
                EnablePrivileges = true,
                Username = user == null ? null : (string.IsNullOrWhiteSpace(domain) ? user : $"{domain}\\{user}"),
                Password = user == null ? null : password,
            },
        };
        ManagementScope.Connect();
    }
}

public class ProcessManager
{
    public static ProcessManager FromLocalMachine() => new ProcessManager()
    {
        Machine = Environment.MachineName,
    };

    public static ProcessManager FromRemoteMachine(string machine, string user = null, string password = null, string domain = null) => new ProcessManager()
    {
        Machine = machine,
        User = user,
        Password = password,
        Domain = domain,
    };

    private ProcessManager() { }

    public string Machine { get; private set; }
    public string User { get; private set; }
    public string Password { get; private set; }
    public string Domain { get; private set; }

    private ProcessConnection Connection { get; set; }
    private ManagementScope ManagementScope => Connection == null ? (Connection = new ProcessConnection(Machine, User, Password, Domain)).ManagementScope : Connection.ManagementScope;

    public EProcessStartStatus StartProcess(string processPath)
    {
        ManagementClass mc = new ManagementClass($"\\\\{Machine}\\root\\CIMV2", "Win32_Process", null);
        ManagementBaseObject process = mc.GetMethodParameters("Create");
        process["CommandLine"] = processPath;
        ManagementBaseObject createCode = mc.InvokeMethod("Create", process, null);
        string createCodeStr = createCode["ReturnValue"].ToString();
        return (EProcessStartStatus)Convert.ToInt32(createCodeStr);
    }

    public bool KillProcess(string processName)
    {
        try
        {
            SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
            foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
            return true;
        }
        catch { return false; }
    }

    public bool KillProcess(int processId)
    {
        try
        {
            SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
            foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
            return true;
        }
        catch { return false; }
    }

    public void SetProcessPriority(string processName, EProcessPriority priority)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
        ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(ManagementScope, query);
        foreach (ManagementObject managementObject in managementObjectSearcher.Get())
        {
            ManagementBaseObject methodParams = managementObject.GetMethodParameters("SetPriority");
            methodParams["Priority"] = priority;
            managementObject.InvokeMethod("SetPriority", methodParams, null);
        }
    }

    public string GetProcessOwner(string processName)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
        foreach (ManagementObject mo in searcher.Get())
        {
            ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwner");
            ManagementBaseObject owner = mo.InvokeMethod("GetOwner", null, null);
            return owner["User"].ToString();
        }
        return null;
    }

    public string GetProcessOwnerSID(string processName)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
        foreach (ManagementObject mo in searcher.Get())
        {
            ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwnerSid");
            ManagementBaseObject OwnerSid = mo.InvokeMethod("GetOwnerSid", null, null);
            return OwnerSid["Sid"].ToString();
        }
        return null;
    }

    public IList<int> GetRunningProcesses()
    {
        IList<int> processes = new List<int>();
        SelectQuery query = new SelectQuery("SELECT * FROM Win32_Process");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
        foreach (ManagementObject mo in searcher.Get()) processes.Add(int.Parse(mo["ProcessId"].ToString()));
        return processes;
    }

    public IDictionary<EProcessProperty, object> GetProcessProperties(int processId)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);

        Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
        foreach (ManagementObject mo in searcher.Get())
        {
            foreach (PropertyData pd in mo.Properties)
            {
                if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
                else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
            }
        }
        return properties;
    }

    public IDictionary<EProcessProperty, object> GetProcessProperties(string processName)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);

        Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
        foreach (ManagementObject mo in searcher.Get())
        {
            foreach (PropertyData pd in mo.Properties)
            {
                if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
                else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
            }
        }
        return properties;
    }

    public IList<int> GetProcessessFromExecutablePath(string executablePath)
    {
        SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ExecutablePath = '{executablePath.Replace("\\", "\\\\")}'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
        return searcher.Get().Cast<ManagementObject>().Select(mo => Convert.ToInt32(mo["ProcessId"])).ToList();
    }

}

public enum EProcessPriority : uint
{
    IDLE = 0x40,
    BELOW_NORMAL = 0x4000,
    NORMAL = 0x20,
    ABOVE_NORMAL = 0x8000,
    HIGH_PRIORITY = 0x80,
    REALTIME = 0x100
}

public enum EProcessStartStatus
{
    Success = 0,
    AccessDenied = 2,
    NoPermissions = 3,
    Unknown = 8,
    FileNotFound = 9,
    Invalid = 21,
}

public enum EProcessProperty
{
    Caption,
    CommandLine,
    CreationClassName,
    CreationDate,
    CSCreationClassName,
    CSName,
    Description,
    ExecutablePath,
    ExecutionState,
    Handle,
    HandleCount,
    InstallDate,
    KernelModeTime,
    MaximumWorkingSetSize,
    MinimumWorkingSetSize,
    Name,
    OSCreationClassName,
    OSName,
    OtherOperationCount,
    OtherTransferCount,
    PageFaults,
    PageFileUsage,
    ParentProcessId,
    PeakPageFileUsage,
    PeakVirtualSize,
    PeakWorkingSetSize,
    Priority,
    PrivatePageCount,
    ProcessId,
    QuotaNonPagedPoolUsage,
    QuotaPagedPoolUsage,
    QuotaPeakNonPagedPoolUsage,
    QuotaPeakPagedPoolUsage,
    ReadOperationCount,
    ReadTransferCount,
    SessionId,
    Status,
    TerminationDate,
    ThreadCount,
    UserModeTime,
    VirtualSize,
    WindowsVersion,
    WorkingSetSize,
    WriteOperationCount,
    WriteTransferCount,
}

【讨论】:

    【解决方案2】:

    如果只有两种方式启动您的应用,则第二种方法应将参数(GUID?)传递给 Process.Start() - 由您的更新程序应用生成。

    或许可以设计某种算法,让应用仅使用令牌启动。

    【讨论】:

      【解决方案3】:

      据我所知,这是不可能的,但您可以使用一个技巧。首先更改您的 WPF 应用程序的输入方法以获取命令行参数,并且(例如)使用 -u 参数来区分应用程序的启动位置。然后在-u 之后,您可以传递HWND 或与您的更新程序匹配的进程ID。当然,您必须检查该应用程序是否正在运行以及它是否是您的更新程序。

      例子:

      // updated process start
      ProcessStartInfo psi = new ProcessStartInfo("your/WPF/application.exe");
      psi.Arguments = "-u " + Process.GetCurrentProcess().Id;
      // fill up rest of the properties you need 
      Process.Start(psi);
      
      // wpf application's entry point
      void Main(string[] args)
      {
          string updaterProcessIdstr = string.Empty;
          for (int i = 0; i < args.Length; i++)
          {
              if(args[i] == "-u")
              {
                  updaterProcessIdstr = args[i + 1];
                  i++;
              }
          }
          int pid = int.Parse(updaterProcessIdstr);
          Process updaterProcess = Process.GetProcessById(pid);
          // do some validation here
          // send something to stdin and read from stdout 
          // to determine if it was started from that updater.
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-02
        • 1970-01-01
        • 1970-01-01
        • 2011-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多