-
Notifications
You must be signed in to change notification settings - Fork 466
Expand file tree
/
Copy pathProcessHelper.cs
More file actions
175 lines (151 loc) · 6.36 KB
/
ProcessHelper.cs
File metadata and controls
175 lines (151 loc) · 6.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
namespace GVFS.Common
{
public static class ProcessHelper
{
private static string currentProcessVersion = null;
public static ProcessResult Run(string programName, string args, bool redirectOutput = true)
{
ProcessStartInfo processInfo = new ProcessStartInfo(programName);
processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = redirectOutput;
processInfo.RedirectStandardError = redirectOutput;
processInfo.WindowStyle = ProcessWindowStyle.Hidden;
// CreateNoWindow=false avoids allocating a hidden conhost.exe per child
// process. When redirectOutput is true, I/O goes through pipes so no
// console is needed. When redirectOutput is false, the child inherits the
// parent's console handles — this works when the parent has a console
// (e.g., GVFS.Hooks invoked from a terminal), but output is silently lost
// when the parent has no console (e.g., service context). This is
// acceptable because CreateNoWindow=true would only send that output to
// an invisible hidden console instead.
processInfo.CreateNoWindow = false;
processInfo.Arguments = args;
return Run(processInfo);
}
public static string GetCurrentProcessLocation()
{
// Environment.ProcessPath can be null in NativeAOT or certain hosting scenarios.
string processPath = Environment.ProcessPath;
if (!string.IsNullOrEmpty(processPath))
{
return Path.GetDirectoryName(processPath);
}
return AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar);
}
public static string GetEntryClassName()
{
// AppDomain.FriendlyName is reliable even when Assembly.GetEntryAssembly() returns null.
string friendlyName = AppDomain.CurrentDomain.FriendlyName;
if (!string.IsNullOrEmpty(friendlyName))
{
return Path.GetFileNameWithoutExtension(friendlyName);
}
Assembly assembly = Assembly.GetEntryAssembly();
if (assembly == null)
{
assembly = Assembly.GetExecutingAssembly();
}
return assembly.GetName().Name;
}
public static string GetCurrentProcessVersion()
{
if (currentProcessVersion == null)
{
string processPath = Environment.ProcessPath;
if (!string.IsNullOrEmpty(processPath))
{
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(processPath);
currentProcessVersion = fileVersionInfo.ProductVersion;
}
else
{
currentProcessVersion = "0.0.0.0";
}
}
return currentProcessVersion;
}
public static bool IsDevelopmentVersion()
{
// Official CI builds use version numbers where major > 0.
// Development builds always start with 0.
string version = ProcessHelper.GetCurrentProcessVersion();
return version.StartsWith("0.");
}
public static string GetProgramLocation(string programLocaterCommand, string processName)
{
ProcessResult result = ProcessHelper.Run(programLocaterCommand, processName);
if (result.ExitCode != 0)
{
return null;
}
string firstPath =
string.IsNullOrWhiteSpace(result.Output)
? null
: result.Output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
if (firstPath == null)
{
return null;
}
try
{
return Path.GetDirectoryName(firstPath);
}
catch (IOException)
{
return null;
}
}
public static ProcessResult Run(ProcessStartInfo processInfo, string errorMsgDelimeter = "\r\n", object executionLock = null)
{
using (Process executingProcess = new Process())
{
string output = string.Empty;
string errors = string.Empty;
// From https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx
// To avoid deadlocks, use asynchronous read operations on at least one of the streams.
// Do not perform a synchronous read to the end of both redirected streams.
executingProcess.StartInfo = processInfo;
executingProcess.ErrorDataReceived += (sender, args) =>
{
if (args.Data != null)
{
errors = errors + args.Data + errorMsgDelimeter;
}
};
if (executionLock != null)
{
lock (executionLock)
{
output = StartProcess(executingProcess);
}
}
else
{
output = StartProcess(executingProcess);
}
return new ProcessResult(output.ToString(), errors.ToString(), executingProcess.ExitCode);
}
}
private static string StartProcess(Process executingProcess)
{
executingProcess.Start();
if (executingProcess.StartInfo.RedirectStandardError)
{
executingProcess.BeginErrorReadLine();
}
string output = string.Empty;
if (executingProcess.StartInfo.RedirectStandardOutput)
{
output = executingProcess.StandardOutput.ReadToEnd();
}
executingProcess.WaitForExit();
return output;
}
}
}