/ src / common / ManagedCommon / RunnerHelper.cs
RunnerHelper.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using System;
 6  using System.Diagnostics;
 7  using System.Reflection;
 8  using System.Threading.Tasks;
 9  
10  using Microsoft.PowerToys.Telemetry;
11  using Microsoft.PowerToys.Telemetry.Events;
12  
13  namespace ManagedCommon
14  {
15      public static class RunnerHelper
16      {
17          public static void WaitForPowerToysRunner(int powerToysPID, Action act, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "")
18          {
19              var stackTrace = new StackTrace();
20              var assembly = Assembly.GetCallingAssembly().GetName();
21              PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{memberName}]WaitForPowerToysRunner waiting for Event powerToysPID={powerToysPID}" });
22              Task.Run(() =>
23              {
24                  const uint INFINITE = 0xFFFFFFFF;
25                  const uint WAIT_OBJECT_0 = 0x00000000;
26                  const uint SYNCHRONIZE = 0x00100000;
27  
28                  IntPtr powerToysProcHandle = NativeMethods.OpenProcess(SYNCHRONIZE, false, powerToysPID);
29                  if (NativeMethods.WaitForSingleObject(powerToysProcHandle, INFINITE) == WAIT_OBJECT_0)
30                  {
31                      PowerToysTelemetry.Log.WriteEvent(new DebugEvent() { Message = $"[{assembly}][{memberName}]WaitForPowerToysRunner Event Notified powerToysPID={powerToysPID}" });
32                      act.Invoke();
33                  }
34              });
35          }
36  
37          private static readonly string PowerToysRunnerProcessName = "PowerToys.exe";
38  
39          // In case we don't have a permission to open user's processes with a SYNCHRONIZE access right, e.g. LocalSystem processes, we could use GetExitCodeProcess to check the process' exit code periodically.
40          public static void WaitForPowerToysRunnerExitFallback(Action act)
41          {
42              int[] processIds = new int[1024];
43              uint bytesCopied;
44  
45              NativeMethods.EnumProcesses(processIds, (uint)processIds.Length * sizeof(uint), out bytesCopied);
46  
47              const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
48              var handleAccess = PROCESS_QUERY_LIMITED_INFORMATION;
49  
50              IntPtr runnerHandle = IntPtr.Zero;
51              foreach (var processId in processIds)
52              {
53                  IntPtr hProcess = NativeMethods.OpenProcess(handleAccess, false, processId);
54                  System.Text.StringBuilder name = new System.Text.StringBuilder(1024);
55                  uint length = 1024;
56                  if (hProcess == IntPtr.Zero || !NativeMethods.QueryFullProcessImageName(hProcess, 0, name, ref length))
57                  {
58                      continue;
59                  }
60  
61                  if (System.IO.Path.GetFileName(name.ToString()) == PowerToysRunnerProcessName)
62                  {
63                      runnerHandle = hProcess;
64                      break;
65                  }
66              }
67  
68              if (runnerHandle == IntPtr.Zero)
69              {
70                  Logger.LogError("Couldn't determine PowerToys.exe pid");
71                  return;
72              }
73  
74              Task.Run(() =>
75              {
76                  const int STILL_ACTIVE = 0x103;
77                  uint exit_status;
78                  do
79                  {
80                      System.Threading.Thread.Sleep(1000);
81                      NativeMethods.GetExitCodeProcess(runnerHandle, out exit_status);
82                  }
83                  while (exit_status == STILL_ACTIVE);
84  
85                  NativeMethods.CloseHandle(runnerHandle);
86  
87                  act.Invoke();
88              });
89          }
90      }
91  }