确定应用程序从哪个位置启动

Determine from which location an application was being started

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

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

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

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

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

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

据我所知,这不可能以您希望的方式实现,但您可以使用一个技巧。首先更改您的 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.
}

您可以使用的一个技巧是检查父进程的 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,
}