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

3
有没有可能确定C#应用程序是如何启动的?
在我的情况下,我想检查这个应用程序(WPF)是否是通过位于特定文件夹中的快捷方式启动的。
因此,有两种方法可以打开我的应用程序:
- 使用直接快捷方式。 - 启动另一个应用程序(类似于更新管理器),以使我的应用程序保持最新状态。检查后,使用Process.Start()启动我的应用程序。
我希望确保只能使用更新管理器启动该应用程序。

3
我觉得这听起来像是一个 XY 问题 - Uwe Keim
3
要求它接受一个参数,这个参数是只有你的UpdateManager知道的某个键。 - Fildor
你解决这个问题了吗? - sɐunıɔןɐqɐp
3个回答

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,
}

1
据我所知,以你想要的方式是不可能的,但有一个技巧可以使用。首先将你的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.
}

1
如果您的应用程序只有两种启动方式,第二种方法应该向Process.Start()传递一个参数(GUID?)-由您的更新程序生成。也许可以设计一种算法,使应用程序仅通过令牌启动。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接