open System
open System.Diagnostics
let runProc filename args startDir : seq<string> * seq<string> =
let timer = Stopwatch.StartNew()
let procStartInfo =
ProcessStartInfo(
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
FileName = filename,
Arguments = args
match startDir with | Some d -> procStartInfo.WorkingDirectory <- d | _ -> ()
let outputs = System.Collections.Generic.List<string>()
let errors = System.Collections.Generic.List<string>()
let outputHandler f (_sender:obj) (args:DataReceivedEventArgs) = f args.Data
use p = new Process(StartInfo = procStartInfo)
p.OutputDataReceived.AddHandler(DataReceivedEventHandler (outputHandler outputs.Add))
p.ErrorDataReceived.AddHandler(DataReceivedEventHandler (outputHandler errors.Add))
let started =
p.Start()
with | ex ->
ex.Data.Add("filename", filename)
reraise()
if not started then
failwithf "Failed to start process %s" filename
printfn "Started %s with pid %i" p.ProcessName p.Id
p.BeginOutputReadLine()
p.BeginErrorReadLine()
p.WaitForExit()
timer.Stop()
printfn "Finished %s after %A milliseconds" filename timer.ElapsedMilliseconds
let cleanOut l = l |> Seq.filter (fun o -> String.IsNullOrEmpty o |> not)
cleanOut outputs,cleanOut errors
The code for the
runProc
function was written by
ImaginaryDevelopment
and is available under the
Microsoft Public License
.
A
Process
component provides access to a process that is running on a computer. A process, in the simplest terms, is a running app. A thread is the basic unit to which the operating system allocates processor time. A thread can execute any part of the code of the process, including parts currently being executed by another thread.
The
Process
component is a useful tool for starting, stopping, controlling, and monitoring apps. You can use the
Process
component, to obtain a list of the processes that are running, or you can start a new process. A
Process
component is used to access system processes. After a
Process
component has been initialized, it can be used to obtain information about the running process. Such information includes the set of threads, the loaded modules (.dll and .exe files), and performance information such as the amount of memory the process is using.
This type implements the
IDisposable
interface. When you have finished using the type, you should dispose of it either directly or indirectly. To dispose of the type directly, call its
Dispose
method in a
try
/
finally
block. To dispose of it indirectly, use a language construct such as
using
(in C#) or
Using
(in Visual Basic). For more information, see the "Using an Object that Implements IDisposable" section in the
IDisposable
interface documentation.
Important
Calling methods from this class with untrusted data is a security risk. Call the methods from this class only with trusted data. For more information, see
Validate All Inputs
.
32-bit processes cannot access the modules of a 64-bit process. If you try to get information about a 64-bit process from a 32-bit process, you will get a
Win32Exception
exception. A 64-bit process, on the other hand, can access the modules of a 32-bit process.
The process component obtains information about a group of properties all at once. After the
Process
component has obtained information about one member of any group, it will cache the values for the other properties in that group and not obtain new information about the other members of the group until you call the
Refresh
method. Therefore, a property value is not guaranteed to be any newer than the last call to the
Refresh
method. The group breakdowns are operating-system dependent.
If you have a path variable declared in your system using quotes, you must fully qualify that path when starting any process found in that location. Otherwise, the system will not find the path. For example, if
c:\mypath
is not in your path, and you add it using quotation marks:
path = %path%;"c:\mypath"
, you must fully qualify any process in
c:\mypath
when starting it.
A system process is uniquely identified on the system by its process identifier. Like many Windows resources, a process is also identified by its handle, which might not be unique on the computer. A handle is the generic term for an identifier of a resource. The operating system persists the process handle, which is accessed through the
Handle
property of the
Process
component, even when the process has exited. Thus, you can get the process's administrative information, such as the
ExitCode
(usually either zero for success or a nonzero error code) and the
ExitTime
. Handles are an extremely valuable resource, so leaking handles is more virulent than leaking memory.
This class contains a link demand and an inheritance demand at the class level that applies to all members. A
SecurityException
is thrown when either the immediate caller or the derived class does not have full-trust permission. For details about security demands, see
Link Demands
.
.NET Core Notes
In .NET Framework, the
Process
class by default uses
Console
encodings, which are typically code page encodings, for the input, output, and error streams. For example code, on systems whose culture is English (United States), code page 437 is the default encoding for the
Console
class. However, .NET Core may make only a limited subset of these encodings available. If this is the case, it uses
Encoding.UTF8
as the default encoding.
If a
Process
object depends on specific code page encodings, you can still make them available by doing the following
before
you call any
Process
methods:
Retrieve the
EncodingProvider
object from the
CodePagesEncodingProvider.Instance
property.
Pass the
EncodingProvider
object to the
Encoding.RegisterProvider
method to make the additional encodings supported by the encoding provider available.
The
Process
class will then automatically use the default system encoding rather than UTF8, provided that you have registered the encoding provider before calling any
Process
methods.
Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object.
(Inherited from
MarshalByRefObject
)
Obsolete.
Retrieves the current lifetime service object that controls the lifetime policy for this instance.
(Inherited from
MarshalByRefObject
)
Returns an object that represents a service provided by the
Component
or by its
Container
.
(Inherited from
Component
)
Obsolete.
Obtains a lifetime service object to control the lifetime policy for this instance.
(Inherited from
MarshalByRefObject
)
Causes the
Process
component to wait the specified
timeout
for the associated process to enter an idle state.
This overload applies only to processes with a user interface and, therefore, a message loop.