// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; using System.Linq; using System.Text; using Wox.Plugin.Common.Win32; namespace Microsoft.Plugin.WindowWalker.Components { /// /// Represents the process data of an open window. This class is used in the process cache and for the process object of the open window /// public class WindowProcess { /// /// Maximum size of a file name /// private const int MaximumFileNameLength = 1000; /// /// An indicator if the window belongs to an 'Universal Windows Platform (UWP)' process /// private readonly bool _isUwpApp; /// /// Gets the id of the process /// public uint ProcessID { get; private set; } /// /// Gets the id of the thread /// public uint ThreadID { get; private set; } /// /// Gets the name of the process /// public string Name { get; private set; } /// /// Gets a value indicating whether the window belongs to an 'Universal Windows Platform (UWP)' process /// public bool IsUwpApp { get { return _isUwpApp; } } /// /// Gets a value indicating whether this is the shell process or not /// The shell process (like explorer.exe) hosts parts of the user interface (like taskbar, start menu, ...) /// public bool IsShellProcess { get { IntPtr hShellWindow = NativeMethods.GetShellWindow(); return GetProcessIDFromWindowHandle(hShellWindow) == ProcessID; } } /// /// Gets a value indicating whether the process exists on the machine /// public bool DoesExist { get { try { var p = Process.GetProcessById((int)ProcessID); p.Dispose(); return true; } catch (InvalidOperationException) { // Thrown when process not exist. return false; } catch (ArgumentException) { // Thrown when process not exist. return false; } } } /// /// Gets a value indicating whether full access to the process is denied or not /// public bool IsFullAccessDenied { get; private set; } /// /// Initializes a new instance of the class. /// /// New process id. /// New thread id. /// New process name. public WindowProcess(uint pid, uint tid, string name) { UpdateProcessInfo(pid, tid, name); _isUwpApp = Name.ToUpperInvariant().Equals("APPLICATIONFRAMEHOST.EXE", StringComparison.Ordinal); } /// /// Updates the process information of the instance. /// /// New process id. /// New thread id. /// New process name. public void UpdateProcessInfo(uint pid, uint tid, string name) { // TODO: Add verification as to wether the process id and thread id is valid ProcessID = pid; ThreadID = tid; Name = name; // Process can be elevated only if process id is not 0 (Dummy value on error) IsFullAccessDenied = (pid != 0) ? TestProcessAccessUsingAllAccessFlag(pid) : false; } /// /// Gets the process ID for the window handle /// /// The handle to the window /// The process ID public static uint GetProcessIDFromWindowHandle(IntPtr hwnd) { _ = NativeMethods.GetWindowThreadProcessId(hwnd, out uint processId); return processId; } /// /// Gets the thread ID for the window handle /// /// The handle to the window /// The thread ID public static uint GetThreadIDFromWindowHandle(IntPtr hwnd) { uint threadId = NativeMethods.GetWindowThreadProcessId(hwnd, out _); return threadId; } /// /// Gets the process name for the process ID /// /// The id of the process/param> /// A string representing the process name or an empty string if the function fails public static string GetProcessNameFromProcessID(uint pid) { IntPtr processHandle = NativeMethods.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, true, (int)pid); StringBuilder processName = new StringBuilder(MaximumFileNameLength); if (NativeMethods.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0) { _ = Win32Helpers.CloseHandleIfNotNull(processHandle); return processName.ToString().Split('\\').Reverse().ToArray()[0]; } else { _ = Win32Helpers.CloseHandleIfNotNull(processHandle); return string.Empty; } } /// /// Gets a boolean value indicating whether the access to a process using the AllAccess flag is denied or not. /// /// The process ID of the process /// True if denied and false if not. private static bool TestProcessAccessUsingAllAccessFlag(uint pid) { IntPtr processHandle = NativeMethods.OpenProcess(ProcessAccessFlags.AllAccess, true, (int)pid); if (Win32Helpers.GetLastError() == 5) { // Error 5 = ERROR_ACCESS_DENIED _ = Win32Helpers.CloseHandleIfNotNull(processHandle); return true; } else { _ = Win32Helpers.CloseHandleIfNotNull(processHandle); return false; } } } }