I've been trying to make a program to automate the process of running different processes on my computer. So far I've got the following program running a console version of BleachBit(It's like CCleaner), the process appears in task manager, it hits around 25kb process RAM then CPU usage goes to 0% and just sits there doing nothing for ages and never quits.
Is there something wrong I'm doing in my code that could cause this to happen?
I've tried editing the app.manifest to make sure the program has to be run as admin in case it needed more privileges
Also when running similar code in a bat file to run the program, it's opens its own windows and runs fine, so I'm not sure. Any help in the right direction would be fantastic.
The code I'm running is below.
static void Main(string[] args)
{
string Log = "";
if (File.Exists(Environment.CurrentDirectory + "\\BleachBit\\bleachbit_console.exe"))
{
Log += "File exists";
Log += RunProgramCapturingOutput("\\BleachBit\\bleachbit_console.exe", "--preset --clean");
}
else
Log += "Program not found. Please place at \\BleachBit\\bleachbit_console.exe";
File.WriteAllText("log.txt", Log);
Console.ReadLine();
}
public static string RunProgramCapturingOutput(string filename, string arguments)
{
ProcessStartInfo processInfo = new ProcessStartInfo()
{
FileName = Environment.CurrentDirectory + filename,
Arguments = arguments,
CreateNoWindow = false,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(Environment.CurrentDirectory + filename),
RedirectStandardError = false,
RedirectStandardOutput = true
};
Process process = Process.Start(processInfo);
process.WaitForExit();
string output = output = process.StandardOutput.ReadToEnd();
Console.WriteLine("Output: " + output);
process.Close();
return output;
}
Switching these lines to this:
string output = output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
allows to avoid deadlocks. The program seems to be a relatively slow running program due to hard-drive I/O, just give it time and you'll see it complete.
I found this deadlock issue from https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx
Where it states in a code block: "// To avoid deadlocks, always read the output stream first and then wait."
Related
When I run App1 project to started another process(App2.exe), the program quickly exited itself, and then I got this information.
"Process finished with exit code 500"
Originally, I thought this situation should be very common, but I didn't find the information about this exit code on the search engine.
What the hell is going on? I feel very confused.
//App1
using System.Diagnostics;
var app2 = new Process()
{
StartInfo =
{
FileName = "App2.exe",
UseShellExecute = false,
CreateNoWindow = false
}
};
app2.Start();
// App2
while (true)
{
string input = Console.ReadLine();
Console.WriteLine("Input is " + input);
}
Here is the solution, you can reproduce it on your own computer.
https://github.com/Andy-AO/Shared/tree/master/exit_code_500
The above problem occurs when I run it in Rider, but it does not occur when I run it in Visual Studio.
i have a c# console program .Im using .net 2.0 . Im launching an exe from my console program.
That exe shows progress bar on taskbar.
Here i want to read progress percentage from that exe and want to display (1% 2% 3% etc) on my console app program.
(i dont want to display whole output of that exe into my program.
i also did test of setting following code but it shows all output of that exe
i only want to display percentage )
Is this possible using .net 2.0 ?
im beginner in c#
i have following working code
string fullName = "A.exe" ;
Process p1 = new Process();
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.StartInfo.UseShellExecute = true;
p1.StartInfo.FileName = fullName;
p1.Start();
p1.WaitForExit();
To read program's progress, you should redirect the standard output and define a method DataReceived that handles OutputDataReceived event of the specified Process instance. This method, for example, gets the percentage of the text, assuming it contains a single number (see GetPercent ), and updates the progress information as you see fit.
static class Program
{
static void Main(string[] args)
{
using (Process proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "A.exe", // Type filename here.
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
})
{
proc.OutputDataReceived += DataReceived;
proc.Start();
proc.WaitForExit();
}
}
// Updates a progress value.
static void DataReceived(object sender, DataReceivedEventArgs e)
{
// The e.Data property contains programs output string.
// Esc-symbol \r means overwriting the current line.
Console.Write("\rTotal " + GetPercent(e.Data) + " completed.");
}
// Gets the percentage from the output string.
static string GetPercent(string data)
{
// The regular expression that finds a number from a string.
Regex regex = new Regex(#"([^\d]|^)\d{1,2}([^\d]|$)");
Match match = regex.Match(data);
return match.Value;
}
}
This code should be modified for the specific output format of your program.
We have a C# application that executes PowerShell scripts as an extension point, we don't have access to change this code but it is pretty much the following:
string command = #"C:\temp.ps1";
var fileName = "powershell";
var args = $"-ExecutionPolicy unrestricted . '{command}'";
var process = CreateProcess(fileName, args);
ExecuteProcess(ref process);
private Process CreateProcess(string fileName, string args)
{
return new Process
{
StartInfo =
{
FileName = fileName,
Arguments = args,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
}
private int ExecuteProcess(ref Process proc)
{
proc.Start();
string text = string.Empty;
string text2 = string.Empty;
while (!proc.HasExited)
{
Thread.Sleep(1000);
text += proc.StandardOutput.ReadToEnd();
text2 += proc.StandardError.ReadToEnd();
}
proc.WaitForExit();
text2 += proc.StandardError.ReadToEnd();
text += proc.StandardOutput.ReadToEnd();
Console.WriteLine(text);
Console.WriteLine(text2);
return proc.ExitCode;
}
We have a PowerShell script that gets executed from this code that has a long-running process, to keep this simple we'll just use ping.exe with a -t argument.
ping -t google.com
We want to be able to fork the ping.exe process so that the c# application can resume execution as soon as possible and that the ping.exe in this example continues on it's merry way.
I've tried to run Start-Process inside the powershell script but this still just blocks the execution of the C# application until all the processes have fully executed (so it eventually runs to completion):
Start-Process ping -ArgumentList "-t","google.com" -RedirectStandardOutput ".\out.log" -RedirectStandardError ".\err.log"
I've also tried to run Start-Job and wrap the start process in a separate job, however, this seems to start the job but never completes
Start-Job -ScriptBlock { Start-Process ping -ArgumentList "-t","google.com" -RedirectStandardOutput ".\out.log" -RedirectStandardError ".\err.log" }
Is there any way to start a new process from within PowerShell and allow the C# application to continue executing?
I've kinda found a workaround - if I pass in -Verb Open to Start-Process it seems to resume execution to the C# application straight away. The only problem is that you can't redirect the standard out or error to files.
Start-Process ping -ArgumentList "-t","google.com" -Verb Open
I am using a FilesystemWatcher class to convert audio to a listenable format as they come in. This worked perfectly for a while, until right around the time we upgraded to 4.5 on that server. Now, to get it to work, I need to debug it and set a breakpoint so the method does not exit before the process runs.
It only takes a few milliseconds for sox to convert the audio. Setting a Thread.sleep(10000) doesnt fix the issue. Downgrading the project to .net 2.0 did nothing.
What's really frustrating, is process.WaitForExit() seemingly does not block. While debugging, I step right over it and wait until the file shows up in the folder.
As always, I really appreciate the assistance.
Attached is the relevant code:
void FileCreated(object sender, FileSystemEventArgs e)
{
string newname = String.Format(#"{0}{1}.mp3", _mp3FolderPath, e.Name.Replace(".wav", ""));
string soxArgs = #"-t wav -r 8k -c 1";
ProcessStartInfo p = new ProcessStartInfo
{
FileName = _soxPath,
Arguments = string.Format("{0} {1} {2}", soxArgs, e.FullPath, newname),
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = false,
RedirectStandardInput = false,
RedirectStandardOutput = false
};
using (Process process = Process.Start(p))
{
process.WaitForExit();
Thread.Sleep(10000);
//process.Close();
}
}
I am trying to restart an application in WPF.
I tried the following:
Process.Start(Application.ExecutablePath);
Process.GetCurrentProcess().Kill();
And it doesn't work because the application is setup as a single instances application.
Then I tired this:
Process.GetCurrentProcess().Kill();
Process.Start(Application.ExecutablePath);
And it doesn't work because once we Kill the process it will not hit line 2
Is there a way to schedule a the .Start so that I don't run into issue #1.
You could launch a secondary application that would then re-launch your main program after the delay. When I wrote a self-updater a few years ago, that was the implementation path that I took. It was just a simple program that took the executable as a command line arg, would sleep for a tenth of a second, then .Start it.
A better implementation path than I took would be to have the newly-launched program wait for the process that launched it to terminate. Waiting the arbitrary length of time could complicate matters. In order to accomplish this, I would probably pass the process ID to the re-launcher so that it would know exactly which process to wait on.
It's not as hard as you think. All you need to do is call the following method, passing in the command line for the restarted instance:
public static void RestartMe(string commandLine)
{
var myId = Process.GetCurrentProcess().Id;
var myPath = Assembly.GetEntryAssembly().CodeBase.Replace("file:///", "");
var systemPath = typeof(object).Assembly.CodeBase.Replace("file:///", "");
var tempPath = Path.GetTempFileName();
File.WriteAllText(tempPath + ".cs", #"
using System;
using System.Diagnostics;
public class App
{
public static void Main(string[] args)
{
try { Process.GetProcessById(" + myId + #").WaitForExit(); } catch {}
Process.Start(""" + myPath + #""", Environment.CommandLine);
}
}");
var compiler = new ProcessStartInfo
{
FileName = Path.Combine(Path.GetDirectoryName(systemPath), "csc.exe"),
Arguments = tempPath + ".cs",
WorkingDirectory = Path.GetDirectoryName(tempPath),
WindowStyle = ProcessWindowStyle.Hidden,
};
var restarter = new ProcessStartInfo
{
FileName = tempPath + ".exe",
Arguments = commandLine,
WindowStyle = ProcessWindowStyle.Hidden,
};
Process.Start(compiler).WaitForExit();
Process.Start(restarter); // No WaitForExit: restarter WaitForExits us instead
File.Delete(tempPath);
File.Delete(tempPath + ".cs");
Environment.Exit(0);
}
How it works: This actually does create another "restarter" program but does it painlessly and automatically. The restarter program has the current process id and the executable filename built right into it. It will always find the compiler because NET Framework version ships with a compatible csc.exe in the same folder as System.dll.