Skip to content
Permalink
c8bb522b99
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
#region
/*
**************************************************************
* Author: Rick Strahl
* © West Wind Technologies, 2011
* http://www.west-wind.com/
*
* Created: 6/19/2011
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**************************************************************
*/
#endregion
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Diagnostics;
namespace Westwind.Utilities
{
/// <summary>
/// Windows specific shell utility functions
/// </summary>
public static class ShellUtils
{
#region Open in or Start Process
/// <summary>
/// Opens a File or Folder in Explorer. If the path is a file
/// Explorer is opened in the parent folder with the file selected
/// </summary>
/// <param name="filename"></param>
public static void OpenFileInExplorer(string filename)
{
if (Directory.Exists(filename))
ShellUtils.GoUrl(filename);
else
{
if (!File.Exists(filename))
filename = Path.GetDirectoryName(filename);
Process.Start("explorer.exe", $"/select,\"{filename}\"");
}
}
/// <summary>
/// Executes a Windows process with given command line parameters
/// </summary>
/// <param name="executable">Executable to run</param>
/// <param name="arguments">Command Line Parameters passed to executable</param>
/// <param name="timeoutMs">Timeout of the process in milliseconds. Pass -1 to wait forever. Pass 0 to not wait.</param>
/// <param name="windowStyle">Hidden, Normal etc.</param>
/// <returns>process exit code or 0 if run and forget. 1460 for time out. -1 on error</returns>
public static int ExecuteProcess(string executable,
string arguments = null,
int timeoutMs = 0,
ProcessWindowStyle windowStyle = ProcessWindowStyle.Hidden)
{
Process process;
try
{
using (process = new Process())
{
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.WindowStyle = windowStyle;
if (windowStyle == ProcessWindowStyle.Hidden)
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.Start();
if (timeoutMs < 0)
timeoutMs = 99999999; // indefinitely
if (timeoutMs > 0)
{
if (!process.WaitForExit(timeoutMs))
{
Console.WriteLine("Process timed out.");
return 1460;
}
}
else // run and don't wait - no exit code
return 0;
return process.ExitCode;
}
}
catch (Exception ex)
{
Console.WriteLine("Error executing process: " + ex.Message);
return -1; // unhandled error
}
}
/// <summary>
/// Executes a Windows process with given command line parameters
/// and captures console output into a string.
///
/// Writes command output to the output StringBuilder
/// from StdOut and StdError.
/// </summary>
/// <param name="executable">Executable to run</param>
/// <param name="arguments">Command Line Parameters passed to executable</param>
/// <param name="timeoutMs">Timeout of the process in milliseconds. Pass -1 to wait forever. Pass 0 to not wait.</param>
/// <param name="output">Pass in a string reference that will receive StdOut and StdError output</param>
/// <param name="windowStyle">Hidden, Normal, etc.</param>
/// <returns>process exit code or 0 if run and forget. 1460 for time out. -1 on error</returns>
public static int ExecuteProcess(string executable,
string arguments,
int timeoutMs,
out StringBuilder output,
ProcessWindowStyle windowStyle = ProcessWindowStyle.Hidden)
{
return ExecuteProcess(executable, arguments, timeoutMs, out output, null, windowStyle);
}
/// <summary>
/// Executes a Windows process with given command line parameters
/// and captures console output into a string.
///
/// Pass in a String Action that receives output from
/// StdOut and StdError as it is written (one line at a time).
/// </summary>
/// <param name="executable">Executable to run</param>
/// <param name="arguments">Command Line Parameters passed to executable</param>
/// <param name="timeoutMs">Timeout of the process in milliseconds. Pass -1 to wait forever. Pass 0 to not wait.</param>
/// <param name="writeDelegate">Delegate to let you capture streaming output of the executable to stdout and stderror.</param>
/// <param name="windowStyle">Hidden, Normal etc.</param>
/// <returns>process exit code or 0 if run and forget. 1460 for time out. -1 on error</returns>
public static int ExecuteProcess(string executable,
string arguments,
int timeoutMs,
Action<string> writeDelegate,
ProcessWindowStyle windowStyle = ProcessWindowStyle.Hidden)
{
return ExecuteProcess(executable, arguments, timeoutMs, out StringBuilder output, writeDelegate, windowStyle);
}
/// <summary>
/// Executes a Windows process with given command line parameters
/// and captures console output into a string.
///
/// Writes original output into the application Console which you can
/// optionally redirect to capture output from the command line
/// operation using `Console.SetOut` or `Console.SetError`.
/// </summary>
/// <param name="executable">Executable to run</param>
/// <param name="arguments"></param>
/// <param name="timeoutMs">Timeout of the process in milliseconds. Pass -1 to wait forever. Pass 0 to not wait.</param>
/// <param name="output">StringBuilder that will receive StdOut and StdError output</param>
/// <param name="writeDelegate">Action to capture stdout and stderror output for you to handle</param>
/// <param name="windowStyle"></param>
/// <returns>process exit code or 0 if run and forget. 1460 for time out. -1 on error</returns>
private static int ExecuteProcess(string executable,
string arguments,
int timeoutMs,
out StringBuilder output,
Action<string> writeDelegate = null,
ProcessWindowStyle windowStyle = ProcessWindowStyle.Hidden)
{
Process process;
try
{
using (process = new Process())
{
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.WindowStyle = windowStyle;
if (windowStyle == ProcessWindowStyle.Hidden)
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
var sb = new StringBuilder();
process.OutputDataReceived += (sender, args) =>
{
if (writeDelegate != null)
writeDelegate.Invoke(args.Data);
else
sb.AppendLine(args.Data);
};
process.ErrorDataReceived += (sender, args) =>
{
if (writeDelegate != null)
writeDelegate.Invoke(args.Data);
else
sb.AppendLine(args.Data);
};
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
if (timeoutMs < 0)
timeoutMs = 99999999; // indefinitely
if (timeoutMs > 0)
{
if (!process.WaitForExit(timeoutMs))
{
Console.WriteLine("Process timed out.");
output = null;
return 1460;
}
}
else
{
// no exit code
output = sb;
return 0;
}
output = sb;
return process.ExitCode;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error executing process: {ex.Message}");
output = null;
return -1; // unhandled error
}
}
/// <summary>
/// Opens a Terminal window in the specified folder
/// </summary>
/// <param name="folder"></param>
/// <param name="mode">Powershell, Command or Bash</param>
/// <returns>false if process couldn't be started - most likely invalid link</returns>
public static bool OpenTerminal(string folder, TerminalModes mode = TerminalModes.Powershell)
{
try
{
string cmd = null, args = null;
if (mode == TerminalModes.Powershell)
{
cmd = "powershell.exe";
args = "-noexit -command \"cd '{0}'\"";
}
else if(mode == TerminalModes.Command)
{
cmd = "cmd.exe";
args = "/k \"cd {0}\"";
}
Process.Start(cmd,string.Format(args, folder));
}
catch
{
return false;
}
return true;
}
#endregion
#region URL and HTTP Access
/// <summary>
/// Uses the Shell Extensions to launch a program based on URL moniker or file name
/// Basically a wrapper around ShellExecute
/// </summary>
/// <param name="url">Any URL Moniker that the Windows Shell understands (URL, Word Docs, PDF, Email links etc.)</param>
/// <returns></returns>
public static int GoUrl(string url, string workingFolder = null)
{
string TPath = Path.GetTempPath();
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.Verb = "Open";
info.WorkingDirectory = TPath;
info.FileName = url;
using (Process process = new Process())
{
process.StartInfo = info;
process.Start();
}
return 0;
}
/// <summary>
/// Wrapper around the Shell Execute API
/// </summary>
/// <param name="url"></param>
/// <param name="arguments"></param>
/// <param name="workingFolder"></param>
/// <param name="verb"></param>
/// <returns></returns>
public static int ShellExecute(string url, string arguments, string workingFolder = null, string verb = "Open")
{
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.Verb = "Open";
info.FileName = url;
info.Arguments = arguments;
info.WorkingDirectory = workingFolder;
using (Process process = new Process())
{
process.StartInfo = info;
process.Start();
}
return 0;
}
/// <summary>
/// Executes a Windows Command Line using Shell Execute as a
/// single command line with parameters. This method handles
/// parsing out the executable from the parameters.
/// </summary>
/// <param name="fullCommandLine">Full command line - Executable plus arguments. Recommend double quotes for best command parsing experience</param>
/// <param name="workingFolder">Optional - the folder the executable runs in. If not specified uses current folder.</param>
/// <param name="waitForExitMs">Optional - Number of milliseconds to wait for completion. 0 don't wait.</param>
/// <param name="verb">Optional - Shell verb to apply. Defaults to "Open"</param>
/// <param name="windowStyle">Optional - Windows style for the launched application. Default style is normal</param>
public static void ExecuteCommandLine(string fullCommandLine,
string workingFolder = null,
int waitForExitMs = 0,
string verb = "OPEN",
ProcessWindowStyle windowStyle = ProcessWindowStyle.Normal)
{
string executable = fullCommandLine;
string args = null;
if (executable.StartsWith("\""))
{
int at = executable.IndexOf("\" ");
if (at > 0)
{
args = executable.Substring(at+1).Trim();
executable = executable.Substring(0, at);
}
}
else
{
int at = executable.IndexOf(" ");
if (at > 0)
{
if (executable.Length > at +1)
args = executable.Substring(at + 1).Trim();
executable = executable.Substring(0, at);
}
}
var pi = new ProcessStartInfo();
//pi.UseShellExecute = true;
pi.Verb = verb;
pi.WindowStyle = windowStyle;
pi.FileName = executable;
pi.WorkingDirectory = workingFolder;
pi.Arguments = args;
using (var p = Process.Start(pi))
{
if (waitForExitMs > 0)
{
if (!p.WaitForExit(waitForExitMs))
throw new TimeoutException("Process failed to complete in time.");
}
}
}
/// <summary>
/// Displays a string in in a browser as HTML. Optionally
/// provide an alternate extension to display in the appropriate
/// text viewer (ie. "txt" likely shows in NotePad)
/// </summary>
/// <param name="text"></param>
/// <param name="extension"></param>
/// <returns></returns>
public static int ShowString(string text, string extension = null)
{
if (extension == null)
extension = "htm";
string File = Path.GetTempPath() + "\\__preview." + extension;
StreamWriter sw = new StreamWriter(File, false, Encoding.Default);
sw.Write(text);
sw.Close();
return GoUrl(File);
}
/// <summary>
/// Shows a string as HTML
/// </summary>
/// <param name="htmlString"></param>
/// <returns></returns>
public static int ShowHtml(string htmlString)
{
return ShowString(htmlString, null);
}
/// <summary>
/// Displays a large Text string as a text file in the
/// systems' default text viewer (ie. NotePad)
/// </summary>
/// <param name="TextString"></param>
/// <returns></returns>
public static int ShowText(string TextString)
{
string File = Path.GetTempPath() + "\\__preview.txt";
StreamWriter sw = new StreamWriter(File, false);
sw.Write(TextString);
sw.Close();
return GoUrl(File);
}
/// <summary>
/// Simple method to retrieve HTTP content from the Web quickly
/// </summary>
/// <param name="url">Url to access</param>
/// <returns>Http response text or null</returns>
public static string HttpGet(string url)
{
string errorMessage;
return HttpGet(url, out errorMessage);
}
/// <summary>
/// Simple method to retrieve HTTP content from the Web quickly
/// </summary>
/// <param name="url">Url to access</param>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static string HttpGet(string url, out string errorMessage)
{
string responseText = string.Empty;
errorMessage = null;
using (WebClient Http = new WebClient())
{
try
{
responseText = Http.DownloadString(url);
}
catch (Exception ex)
{
errorMessage = ex.Message;
return null;
}
}
return responseText;
}
/// <summary>
/// Retrieves a buffer of binary data from a URL using
/// a plain HTTP Get.
/// </summary>
/// <param name="url">Url to access</param>
/// <returns>Response bytes or null on error</returns>
public static byte[] HttpGetBytes(string url)
{
string errorMessage;
return HttpGetBytes(url,out errorMessage);
}
/// <summary>
/// Retrieves a buffer of binary data from a URL using
/// a plain HTTP Get.
/// </summary>
/// <param name="url">Url to access</param>
/// <param name="errorMessage">ref parm to receive an error message</param>
/// <returns>response bytes or null on error</returns>
public static byte[] HttpGetBytes(string url, out string errorMessage)
{
byte[] result = null;
errorMessage = null;
using (var http = new WebClient())
{
try
{
result = http.DownloadData(url);
}
catch (Exception ex)
{
errorMessage = ex.Message;
return null;
}
}
return result;
}
#endregion
}
public enum TerminalModes
{
Powershell,
Command,
Bash
}
}