windows-development-sandbox 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/features/accounts/accounts.def.d.ts +1 -0
- package/dist/app/features/accounts/accounts.def.js +12 -3
- package/dist/app/features/accounts/accounts.run.d.ts +1 -0
- package/dist/app/features/accounts/accounts.run.js +20 -11
- package/dist/app/features/defs.d.ts +1 -0
- package/dist/app/features/settings/settings-file.d.ts +7 -0
- package/dist/app/features/settings/settings-file.js +19 -2
- package/dist/app/features/settings/settings-rows.js +9 -1
- package/dist/app/features/storage/storage.run.js +1 -1
- package/dist/bin/agent-sandbox.js +7 -1
- package/dist/bin/chunk-BQ23GBLC.js +78790 -0
- package/dist/bin/chunk-F7IMME5G.js +10432 -0
- package/dist/bin/chunk-LQHEUN2A.js +7 -0
- package/dist/bin/claude-host.js +10 -4
- package/dist/bin/claude-sbx.js +8 -2
- package/dist/bin/codex-sbx.js +8 -2
- package/dist/bin/gemini-sbx.js +8 -2
- package/dist/bin/sandbox.js +7 -2
- package/dist/bin/sbx-hide.js +8 -2
- package/dist/bin/sbx-show.js +8 -2
- package/dist/cli/commands/launch/launch.js +1 -1
- package/dist/cli/commands/launch/prepare.js +24 -7
- package/dist/cli/commands/launch/running.js +4 -0
- package/dist/cli/commands/repair/checks/contained.js +1 -1
- package/dist/cli/commands/storage/offer.js +1 -1
- package/dist/cli/menu/live.d.ts +29 -0
- package/dist/cli/menu/live.js +92 -21
- package/dist/cli/menu/menu.d.ts +2 -1
- package/dist/cli/menu/menu.js +16 -2
- package/dist/cli/menu/pages/list-page.d.ts +5 -0
- package/dist/cli/menu/pages/list-page.js +19 -0
- package/dist/cli/menu/shell.d.ts +2 -0
- package/dist/cli/menu/shell.js +1 -1
- package/dist/cli/services/accounts-service.d.ts +7 -0
- package/dist/cli/services/accounts-service.js +20 -0
- package/dist/cli/tui/app.d.ts +4 -0
- package/dist/cli/tui/app.js +5 -0
- package/dist/cli/tui/terminal.d.ts +6 -0
- package/dist/cli/tui/terminal.js +8 -1
- package/dist/cli/validate.js +8 -4
- package/dist/core/package-info.js +1 -1
- package/dist/guest/daemon/sessions.d.ts +7 -0
- package/dist/guest/daemon/sessions.js +23 -2
- package/dist/guest/entries/daemon.js +1 -0
- package/dist/guest/sessions/pty-host.d.ts +10 -0
- package/dist/guest/sessions/pty-host.js +48 -3
- package/dist/host/channel/channel.js +1 -1
- package/dist/host/install/install-record.d.ts +1 -0
- package/dist/host/install/install-record.js +2 -0
- package/dist/host/sandbox/contained-deps.d.ts +2 -1
- package/dist/host/sandbox/contained-deps.js +6 -4
- package/dist/host/sandbox/platform.d.ts +2 -0
- package/dist/host/sandbox/platform.js +19 -4
- package/dist/host/sharing/lifecycle.js +9 -1
- package/dist/host/storage/contained/contained-storage.js +13 -0
- package/dist/host/storage/contained/disk-port.d.ts +5 -0
- package/dist/host/storage/contained/helper-port.d.ts +72 -0
- package/dist/host/storage/contained/helper-port.js +162 -0
- package/dist/host/storage/contained/index.d.ts +1 -0
- package/dist/host/storage/contained/index.js +1 -0
- package/dist/host/storage/contained/state.d.ts +3 -2
- package/dist/host/storage/contained/state.js +5 -2
- package/dist/host/web/bridge.d.ts +5 -0
- package/dist/host/web/bridge.js +11 -1
- package/dist/host/web/server.d.ts +2 -0
- package/dist/host/web/server.js +11 -1
- package/dist/runtime/agent.js +9 -0
- package/dist/runtime/daemon.js +57 -3
- package/dist/runtime/db.js +9 -0
- package/dist/runtime/main.js +195 -12
- package/dist/runtime/netproxy.js +9 -0
- package/dist/runtime/view.js +195 -12
- package/dist/selftest/channel.test.js +72 -1
- package/dist/selftest/contained.test.js +1 -37
- package/dist/selftest/hcs.test.js +5 -2
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/install.test.js +11 -0
- package/dist/selftest/layout.test.js +10 -1
- package/dist/selftest/live-daemon.test.js +51 -1
- package/dist/selftest/live-terminal.test.js +112 -4
- package/dist/selftest/menu-perf.test.js +198 -12
- package/dist/selftest/menu.test.js +4 -0
- package/dist/selftest/storage-helper.test.d.ts +2 -0
- package/dist/selftest/storage-helper.test.js +493 -0
- package/dist/selftest/support/vhdx.d.ts +14 -0
- package/dist/selftest/support/vhdx.js +72 -0
- package/dist/selftest/web.test.js +14 -2
- package/dist/shared/channel/run-dir.d.ts +6 -0
- package/dist/shared/channel/run-dir.js +9 -0
- package/dist/shared/pty/index.d.ts +3 -1
- package/dist/shared/pty/index.js +3 -1
- package/dist/shared/pty/key-gate.d.ts +24 -0
- package/dist/shared/pty/key-gate.js +45 -0
- package/dist/shared/pty/mouse-modes.d.ts +27 -0
- package/dist/shared/pty/mouse-modes.js +155 -0
- package/dist/shared/pty/terminal.d.ts +0 -5
- package/dist/shared/pty/terminal.js +51 -20
- package/dist/sync/watcher.js +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/{main-Z2WYAE2Z.js → main-6XNBTJLT.js} +34 -34
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +15 -0
- package/native/csharp/StorageHelper/Client.cs +297 -0
- package/native/csharp/StorageHelper/Log.cs +177 -0
- package/native/csharp/StorageHelper/MountRecords.cs +160 -0
- package/native/csharp/StorageHelper/Operations.cs +596 -0
- package/native/csharp/StorageHelper/Pins.cs +270 -0
- package/native/csharp/StorageHelper/Privileges.cs +78 -0
- package/native/csharp/StorageHelper/Program.cs +349 -0
- package/native/csharp/StorageHelper/Protocol.cs +107 -0
- package/native/csharp/StorageHelper/RateLimiter.cs +97 -0
- package/native/csharp/StorageHelper/Rules.cs +156 -0
- package/native/csharp/StorageHelper/Server.cs +656 -0
- package/native/csharp/StorageHelper/Settings.cs +297 -0
- package/native/csharp/StorageHelper/StorageService.cs +53 -0
- package/native/csharp/StorageHelper/UserSettings.cs +206 -0
- package/native/csharp/StorageHelper/Vhdx.cs +230 -0
- package/native/csharp/StorageHelper/VirtualDisk.cs +241 -0
- package/native/csharp/StorageHelper/Volumes.cs +379 -0
- package/native/csharp/StorageHelper/Watchdog.cs +128 -0
- package/native/csharp/StorageHelper/Win32.cs +250 -0
- package/native/scripts/set-storage-helper.ps1 +203 -0
- package/package.json +1 -1
- package/sandbox/csharp/PtyHost.cs +236 -1
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
// .NET Framework csc.exe, so this is C# 5 (no string interpolation, no ?., no expression-bodied members).
|
|
4
4
|
//
|
|
5
5
|
// Usage: ptyhost.exe <port> <token> <cols> <rows> <logFile> <commandLine> [<restartCommandLine>]
|
|
6
|
+
// ptyhost.exe --end-tree <recordFile> ends what a ptyhost that was itself ended (Task Manager, a crash) left
|
|
7
|
+
// running, from the process tree it recorded (PTYHOST_TREE_FILE)
|
|
6
8
|
//
|
|
9
|
+
// PTYHOST_TREE_FILE: where the program's process tree (ProcessTree: what it started, by id and start time) is kept
|
|
10
|
+
// while it runs; deleted when ptyhost ends it itself. A file left behind means ptyhost did not get to: the session
|
|
11
|
+
// daemon then runs --end-tree on it.
|
|
7
12
|
// Wire format, both directions: [type:1][length:4, little endian][payload]
|
|
8
13
|
// client -> host 1 HELLO [cols:2][rows:2][flags:1][token utf8] flags bit 0 = control-only (no output, no sizing),
|
|
9
14
|
// bit 1 = status query (answered with STATUS, then closed)
|
|
@@ -37,6 +42,10 @@ static class PtyHost
|
|
|
37
42
|
{
|
|
38
43
|
static int Main(string[] args)
|
|
39
44
|
{
|
|
45
|
+
if (args.Length == 2 && args[0] == "--end-tree")
|
|
46
|
+
{
|
|
47
|
+
return ProcessTree.EndRecorded(args[1]);
|
|
48
|
+
}
|
|
40
49
|
if (args.Length < 6)
|
|
41
50
|
{
|
|
42
51
|
Console.Error.WriteLine("usage: ptyhost <port> <token> <cols> <rows> <logFile> <commandLine> [<restartCommandLine>]");
|
|
@@ -886,9 +895,24 @@ sealed class ProcessTree
|
|
|
886
895
|
private const uint SnapProcess = 0x00000002;
|
|
887
896
|
private const uint ProcessTerminate = 0x0001;
|
|
888
897
|
private const uint ProcessQueryLimited = 0x1000;
|
|
898
|
+
private const uint Synchronize = 0x00100000;
|
|
899
|
+
private const uint WaitTimeout = 0x102;
|
|
889
900
|
private const int FollowMs = 3000;
|
|
890
901
|
private const int MaxPath = 260;
|
|
902
|
+
private const uint MoveReplaceExisting = 0x1;
|
|
903
|
+
private const uint MoveWriteThrough = 0x8;
|
|
904
|
+
/// <summary>A record larger than this is not one ptyhost wrote (thousands of processes).</summary>
|
|
905
|
+
private const int MaxRecordBytes = 1 << 20;
|
|
906
|
+
/// <summary>--end-tree exit codes: the ptyhost that wrote the record still runs; no readable record.</summary>
|
|
907
|
+
private const int StillRunning = 3;
|
|
908
|
+
private const int Unreadable = 4;
|
|
891
909
|
private static readonly IntPtr InvalidHandle = new IntPtr(-1);
|
|
910
|
+
private static readonly Regex RecordEntry = new Regex("\\{\"pid\":(\\d{1,10}),\"start\":\"(\\d{1,20})\"\\}");
|
|
911
|
+
/// <summary>The pseudo console's own process (Windows' or conpty.dll's), started by ptyhost itself.</summary>
|
|
912
|
+
private static readonly HashSet<string> ConsoleHosts = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
913
|
+
{
|
|
914
|
+
"conhost.exe", "OpenConsole.exe",
|
|
915
|
+
};
|
|
892
916
|
private static readonly HashSet<string> Shared = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
893
917
|
{
|
|
894
918
|
"postgres.exe", "pg_ctl.exe", "mysqld.exe", "mariadbd.exe", "redis-server.exe", "mongod.exe", "sccache.exe",
|
|
@@ -937,13 +961,28 @@ sealed class ProcessTree
|
|
|
937
961
|
|
|
938
962
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
939
963
|
public static extern bool CloseHandle(IntPtr handle);
|
|
964
|
+
|
|
965
|
+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
966
|
+
public static extern bool MoveFileExW(string existing, string replacement, uint flags);
|
|
967
|
+
|
|
968
|
+
[DllImport("kernel32.dll")]
|
|
969
|
+
public static extern int GetCurrentProcessId();
|
|
970
|
+
|
|
971
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
972
|
+
public static extern uint WaitForSingleObject(IntPtr handle, uint milliseconds);
|
|
940
973
|
}
|
|
941
974
|
|
|
942
975
|
private readonly object gate = new object();
|
|
943
976
|
/// <summary>The program and what it started: process id -> start time.</summary>
|
|
944
977
|
private readonly Dictionary<int, long> known = new Dictionary<int, long>();
|
|
978
|
+
/// <summary>The program (closing the console ends it), spared by EndAll (0 in --end-tree: none).</summary>
|
|
945
979
|
private readonly int root;
|
|
946
980
|
private readonly Timer timer;
|
|
981
|
+
/// <summary>Where the tree is recorded (PTYHOST_TREE_FILE), or null.</summary>
|
|
982
|
+
private readonly string recordFile;
|
|
983
|
+
private int recorded = -1;
|
|
984
|
+
/// <summary>The last process snapshot Refresh took (Record reuses it), or null.</summary>
|
|
985
|
+
private List<ProcessEntry> lastSnapshot;
|
|
947
986
|
private bool ended;
|
|
948
987
|
|
|
949
988
|
public ProcessTree(IntPtr rootProcess)
|
|
@@ -954,9 +993,24 @@ sealed class ProcessTree
|
|
|
954
993
|
{
|
|
955
994
|
known[root] = start;
|
|
956
995
|
}
|
|
996
|
+
string file = Environment.GetEnvironmentVariable("PTYHOST_TREE_FILE");
|
|
997
|
+
recordFile = string.IsNullOrEmpty(file) ? null : file;
|
|
998
|
+
lock (gate)
|
|
999
|
+
{
|
|
1000
|
+
Record();
|
|
1001
|
+
}
|
|
957
1002
|
timer = new Timer(Follow, null, FollowMs, FollowMs);
|
|
958
1003
|
}
|
|
959
1004
|
|
|
1005
|
+
/// <summary>--end-tree: the processes of a record that still run as the same process (id and start time).</summary>
|
|
1006
|
+
private ProcessTree(Dictionary<int, long> alive)
|
|
1007
|
+
{
|
|
1008
|
+
foreach (KeyValuePair<int, long> p in alive)
|
|
1009
|
+
{
|
|
1010
|
+
known[p.Key] = p.Value;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
960
1014
|
private void Follow(object unused)
|
|
961
1015
|
{
|
|
962
1016
|
lock (gate)
|
|
@@ -964,8 +1018,158 @@ sealed class ProcessTree
|
|
|
964
1018
|
if (!ended)
|
|
965
1019
|
{
|
|
966
1020
|
Refresh();
|
|
1021
|
+
Record();
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/// <summary>
|
|
1027
|
+
/// Writes the tree to the record file when it grew: {"ptyhost":{"pid":1,"start":"2"},"processes":[{...}]}, start
|
|
1028
|
+
/// times as FILETIME strings (too large for a JSON number). Written aside and moved over the old one, so a ptyhost
|
|
1029
|
+
/// ended at any moment leaves a whole record.
|
|
1030
|
+
/// </summary>
|
|
1031
|
+
private void Record()
|
|
1032
|
+
{
|
|
1033
|
+
if (recordFile == null)
|
|
1034
|
+
{
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
// The pseudo console's process too: one whose ptyhost was ended does not always go away by itself.
|
|
1038
|
+
int self = NativeMethods.GetCurrentProcessId();
|
|
1039
|
+
long selfStart = StartTime(self);
|
|
1040
|
+
Dictionary<int, long> all = new Dictionary<int, long>(known);
|
|
1041
|
+
foreach (ProcessEntry p in lastSnapshot ?? Snapshot())
|
|
1042
|
+
{
|
|
1043
|
+
int pid = (int)p.ProcessId;
|
|
1044
|
+
if ((int)p.ParentProcessId != self || !ConsoleHosts.Contains(p.ExeFile) || all.ContainsKey(pid))
|
|
1045
|
+
{
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
long start = StartTime(pid);
|
|
1049
|
+
if (start != 0 && start >= selfStart)
|
|
1050
|
+
{
|
|
1051
|
+
all[pid] = start;
|
|
967
1052
|
}
|
|
968
1053
|
}
|
|
1054
|
+
if (all.Count == recorded)
|
|
1055
|
+
{
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
StringBuilder json = new StringBuilder();
|
|
1059
|
+
json.Append("{\"ptyhost\":").Append(Entry(self, selfStart)).Append(",\"processes\":[");
|
|
1060
|
+
bool first = true;
|
|
1061
|
+
foreach (KeyValuePair<int, long> p in all)
|
|
1062
|
+
{
|
|
1063
|
+
json.Append(first ? "" : ",").Append(Entry(p.Key, p.Value));
|
|
1064
|
+
first = false;
|
|
1065
|
+
}
|
|
1066
|
+
json.Append("]}");
|
|
1067
|
+
string temp = recordFile + ".tmp";
|
|
1068
|
+
try
|
|
1069
|
+
{
|
|
1070
|
+
File.WriteAllText(temp, json.ToString());
|
|
1071
|
+
if (NativeMethods.MoveFileExW(temp, recordFile, MoveReplaceExisting | MoveWriteThrough))
|
|
1072
|
+
{
|
|
1073
|
+
recorded = all.Count;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
catch (IOException)
|
|
1077
|
+
{
|
|
1078
|
+
// Tried again on the next round (every FollowMs).
|
|
1079
|
+
}
|
|
1080
|
+
catch (UnauthorizedAccessException)
|
|
1081
|
+
{
|
|
1082
|
+
// Same.
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
private static string Entry(int pid, long start)
|
|
1087
|
+
{
|
|
1088
|
+
return "{\"pid\":" + pid + ",\"start\":\"" + start + "\"}";
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/// <summary>The tree ended with ptyhost's own help: nothing is left for the daemon to end.</summary>
|
|
1092
|
+
private void Unrecord()
|
|
1093
|
+
{
|
|
1094
|
+
if (recordFile == null)
|
|
1095
|
+
{
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
try
|
|
1099
|
+
{
|
|
1100
|
+
File.Delete(recordFile);
|
|
1101
|
+
}
|
|
1102
|
+
catch (IOException)
|
|
1103
|
+
{
|
|
1104
|
+
// The daemon finds the processes gone (their ids and start times no longer match).
|
|
1105
|
+
}
|
|
1106
|
+
catch (UnauthorizedAccessException)
|
|
1107
|
+
{
|
|
1108
|
+
// Same.
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/// <summary>
|
|
1113
|
+
/// --end-tree: ends what a ptyhost recorded, unless that ptyhost still runs. Only processes that still run as the
|
|
1114
|
+
/// recorded process (same id and start time) count, and the processes they started since; the Shared ones
|
|
1115
|
+
/// (databases, sccache ...) are spared as always. Prints how many were ended. 0 = done, 3 = the ptyhost still
|
|
1116
|
+
/// runs, 4 = no readable record.
|
|
1117
|
+
/// </summary>
|
|
1118
|
+
public static int EndRecorded(string file)
|
|
1119
|
+
{
|
|
1120
|
+
string text;
|
|
1121
|
+
try
|
|
1122
|
+
{
|
|
1123
|
+
FileInfo info = new FileInfo(file);
|
|
1124
|
+
if (!info.Exists || info.Length > MaxRecordBytes)
|
|
1125
|
+
{
|
|
1126
|
+
return Unreadable;
|
|
1127
|
+
}
|
|
1128
|
+
text = File.ReadAllText(file);
|
|
1129
|
+
}
|
|
1130
|
+
catch (IOException)
|
|
1131
|
+
{
|
|
1132
|
+
return Unreadable;
|
|
1133
|
+
}
|
|
1134
|
+
catch (UnauthorizedAccessException)
|
|
1135
|
+
{
|
|
1136
|
+
return Unreadable;
|
|
1137
|
+
}
|
|
1138
|
+
if (!text.StartsWith("{\"ptyhost\":"))
|
|
1139
|
+
{
|
|
1140
|
+
return Unreadable;
|
|
1141
|
+
}
|
|
1142
|
+
MatchCollection entries = RecordEntry.Matches(text);
|
|
1143
|
+
if (entries.Count == 0)
|
|
1144
|
+
{
|
|
1145
|
+
return Unreadable;
|
|
1146
|
+
}
|
|
1147
|
+
Dictionary<int, long> alive = new Dictionary<int, long>();
|
|
1148
|
+
for (int i = 0; i < entries.Count; i++)
|
|
1149
|
+
{
|
|
1150
|
+
int pid;
|
|
1151
|
+
long start;
|
|
1152
|
+
if (!int.TryParse(entries[i].Groups[1].Value, out pid) ||
|
|
1153
|
+
!long.TryParse(entries[i].Groups[2].Value, out start))
|
|
1154
|
+
{
|
|
1155
|
+
return Unreadable;
|
|
1156
|
+
}
|
|
1157
|
+
bool same = pid != 0 && start != 0 && Running(pid, start);
|
|
1158
|
+
if (i == 0)
|
|
1159
|
+
{
|
|
1160
|
+
if (same)
|
|
1161
|
+
{
|
|
1162
|
+
return StillRunning;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
else if (same)
|
|
1166
|
+
{
|
|
1167
|
+
alive[pid] = start;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
int ended = new ProcessTree(alive).EndAll();
|
|
1171
|
+
Console.Out.WriteLine("ended " + ended + " process(es)");
|
|
1172
|
+
return 0;
|
|
969
1173
|
}
|
|
970
1174
|
|
|
971
1175
|
/// <summary>Adds every process whose parent is known (and that started after it), until nothing new is found.</summary>
|
|
@@ -976,6 +1180,7 @@ sealed class ProcessTree
|
|
|
976
1180
|
return;
|
|
977
1181
|
}
|
|
978
1182
|
List<ProcessEntry> all = Snapshot();
|
|
1183
|
+
lastSnapshot = all;
|
|
979
1184
|
bool added = true;
|
|
980
1185
|
while (added)
|
|
981
1186
|
{
|
|
@@ -1012,7 +1217,10 @@ sealed class ProcessTree
|
|
|
1012
1217
|
}
|
|
1013
1218
|
Refresh();
|
|
1014
1219
|
ended = true;
|
|
1015
|
-
timer
|
|
1220
|
+
if (timer != null)
|
|
1221
|
+
{
|
|
1222
|
+
timer.Dispose();
|
|
1223
|
+
}
|
|
1016
1224
|
int count = 0;
|
|
1017
1225
|
foreach (KeyValuePair<int, long> p in known)
|
|
1018
1226
|
{
|
|
@@ -1021,6 +1229,7 @@ sealed class ProcessTree
|
|
|
1021
1229
|
count++;
|
|
1022
1230
|
}
|
|
1023
1231
|
}
|
|
1232
|
+
Unrecord();
|
|
1024
1233
|
return count;
|
|
1025
1234
|
}
|
|
1026
1235
|
}
|
|
@@ -1073,6 +1282,32 @@ sealed class ProcessTree
|
|
|
1073
1282
|
}
|
|
1074
1283
|
}
|
|
1075
1284
|
|
|
1285
|
+
/// <summary>
|
|
1286
|
+
/// True while process pid is the one that started at `start` and has not ended (an ended process someone still
|
|
1287
|
+
/// holds a handle to keeps its id and start time).
|
|
1288
|
+
/// </summary>
|
|
1289
|
+
private static bool Running(int pid, long start)
|
|
1290
|
+
{
|
|
1291
|
+
IntPtr process = NativeMethods.OpenProcess(ProcessQueryLimited | Synchronize, false, pid);
|
|
1292
|
+
if (process == IntPtr.Zero)
|
|
1293
|
+
{
|
|
1294
|
+
return false;
|
|
1295
|
+
}
|
|
1296
|
+
try
|
|
1297
|
+
{
|
|
1298
|
+
long creation;
|
|
1299
|
+
long exit;
|
|
1300
|
+
long kernel;
|
|
1301
|
+
long user;
|
|
1302
|
+
return NativeMethods.GetProcessTimes(process, out creation, out exit, out kernel, out user) &&
|
|
1303
|
+
creation == start && NativeMethods.WaitForSingleObject(process, 0) == WaitTimeout;
|
|
1304
|
+
}
|
|
1305
|
+
finally
|
|
1306
|
+
{
|
|
1307
|
+
NativeMethods.CloseHandle(process);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1076
1311
|
private static bool Terminate(int pid)
|
|
1077
1312
|
{
|
|
1078
1313
|
IntPtr process = NativeMethods.OpenProcess(ProcessTerminate, false, pid);
|