Invoke UI application in a thread - c#

I've 2 exe (A, B) and one dll (C).
A is an exe that user invokes from commandline with argument -ui or -file_path.
if -ui is passed: B is used to show UI.
if -file_path is passed, C is used for further functionality.
if -ui is passed, i use following code (in Main method):
System.Threading.Thread a = new System.Threading.Thread(yah);
a.Start();
static void yah()
{
SyngoViaInstallerUI.Program.Main();
}
but it blocks the command line from where exe A was invoked. is it possible to unblock the cmdLine or i should to create a new process for -ui argument?
Thanks.

you have to create seperate process for B in order to release the process A and finish gracefully.

Following code works, but is this correct way?
System.Diagnostics.Process pr = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = #"file_path";
pr.StartInfo = psi;
pr.Start();
Thanks.

Related

Function lock and Mutex usage behaving differently in IIS Express and IIS

In my web application I use wkhtmltopdf to process reports to output them as a PDF. I have a few functions that compile some HTML together, some headers etc. and then pass this information to wkhtmltopdf to compile the PDF and serve it to the user.
Something like:
public JsonResult BuildPDF(string one, string two, SomeData[] data, SomeList[] {
lock(PDFLock) {
// ... Code here to compile HTML and save to files
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"C:\inetpub\wwwroot\MySite\wkhtmltopdf.exe";
psi.UseShellExecute = true;
psi.Verb = "runas";
...
Process p = Process.Start(psi);
p.WaitForExit();
}
}
After the PDF is compiled I push it to the user then delete the file.
As you can see I have a lock around this function to prevent two attempts at processing a PDF at one time. On IIS Express this function behaves as I would expect: if two requests are made at the exact same time, the request that makes it in first will be processed, and the 2nd request will sit and wait on the lock until the first request is complete.
In release IIS, it appears to be ignoring this lock, and does not wait for the first request to be finished. It actually ends up skipping through the function so quickly that the first request is still running while the 2nd request completes (unsuccessfully), so the user receives a message that the request failed.
I am unsure why it would ignore this lock, or why it would work in debug (IIS Express).
Is there any possibility this is due to IIS's configuration?
Edit:
The issue with lock was a problem of multiple worker processes in IIS. I am testing Mutex again now with multiple processes.
Edit:
Mutex usage: the Mutex is declared in the class as private static Mutex mut = new Mutex();
public JsonResult BuildPDF(string one, string two, SomeData[] data, SomeList[] {
mut.WaitOne();
// ... Code here to compile HTML and save to files
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"C:\inetpub\wwwroot\MySite\wkhtmltopdf.exe";
psi.UseShellExecute = true;
psi.Verb = "runas";
...
Process p = Process.Start(psi);
p.WaitForExit();
//... Return some JSON to user
}
Then inside the Download method:
public virtual void Download() {
// ... Response headers and stuff
Response.TransmitFile(#"C:\inetpub\wwwroot\MySite\temppdfs\pdfout.pdf");
Response.End();
System.IO.File.Delete(#"C:\inetpub\wwwroot\MySite\temppdfs\pdfout.pdf");
mut.ReleaseMutex();
}
My understanding was a bit off on lock and Mutex usage.
The reason lock was not working is my application pool in IIS had multiple worker processes allowed (4), so the lock could not work cross-process.
I was using the Mutex improperly by declaring it outside the functions, now the proper usage of Mutex in my case (release IIS with multiple processes in the application pool):
public JsonResult BuildPDF(string one, string two, SomeData[] data, SomeList[] {
Mutex mut = new Mutex(false, #"Global\PDFMutex");
mut.WaitOne();
// ... Code here to compile HTML and save to files
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"C:\inetpub\wwwroot\MySite\wkhtmltopdf.exe";
psi.UseShellExecute = true;
psi.Verb = "runas";
...
Process p = Process.Start(psi);
p.WaitForExit();
mut.ReleaseMutex();
//... Return some JSON to user
}
This usage of Mutex appears to be successful across multiple processes and multiple functions.

controlling an application solution with multiple multithreaded projects

from my main project I am running some other executables mainly from the current solution.
the output window shows me info on exiting threads when I suspect they shouldn't, what leads me to the question, how do I run my application child projects so I could process which is which ?
mainApp.exe , sideProj1.exe ...
in main app I do as follows :
public static bool LounchSideProj1Exec()
{
/*
here I could simply call it via Process.Start();
or if I could somehow, execute it via thread start,
so I could name the thread and then see it in the output window and other places...
*/
System.Diagnostics.ProcessStartInfo Pinf = new System.Diagnostics.ProcessStartInfo();
var CurMachingMatchsProcs = System.Diagnostics.Process.GetProcesses().Where(p => p.ProcessName.ToLower().Equals("sideproj1"));
//check count, take first, this is a running process of SideProj1 else excute sideProj1:
sideProj1Proc = CurMachingMatchsProcs.First();
// or else...
SideProj1Proc = new System.Diagnostics.Process();
Pinf.FileName = #"G:\...sideProj1.exe";
sideProj1Proc.StartInfo = Pinf;
bool okTh = false;
ThreadStart ths = new ThreadStart(() => { okTh = sideProj1Proc.Start(); });
Thread th = new Thread(ths);
th.Name = "sideProj1THREAD";
th.Start();
}
what is the right approach to "Be In touch" With ..Concert Of Executed projects & main?
so for the issue of recognizing which thread is which
in the constructor of main form
System.Threading.Thread.CurrentThread.Name = "AppMainTRD";
according to the project name..
and another thing I did not know is that I could execute the whole solution as starting project, which will accrue only for debug purpose which is good for now.

.Exited event problems

The .Exited is not working for all cases, for example: to C:\foo.png when I close the responsible application that show the image, I don't get the MessageBox.Show("exited!");
here's my code:
public static void TryOpenFile(string filename)
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo(filename);
proc.EnableRaisingEvents = true;
proc.Exited += (a,b) => { MessageBox.Show("Exited!"); }
proc.Start();
}
how I call the function TryOpenFile(#"C:\foo.png");. How to fix this?
Is it possible that you already have your image editing program open? When you call proc.Start(), if the process is already running, then the existing process is reused. You should check the return value of proc.Start() to see if this is the case.
From MSDN:
Return Value
true if a process resource is started; false if no new
process resource is started (for example, if an existing process is
reused).
...
Remarks
...
If the process resource specified by the FileName member of the StartInfo property is
already running on the computer, no additional process resource is started. Instead, the
running process resource is reused and false is returned.

Process.Start vs Process `p = new Process()` in C#?

As is asked in this post, there are two ways to call another process in C#.
Process.Start("hello");
And
Process p = new Process();
p.StartInfo.FileName = "hello.exe";
p.Start();
p.WaitForExit();
Q1 : What are the pros/cons of each approach?
Q2 : How to check if error happens with the Process.Start() method?
With the first method you might not be able to use WaitForExit, as the method returns null if the process is already running.
How you check if a new process was started differs between the methods. The first one returns a Process object or null:
Process p = Process.Start("hello");
if (p != null) {
// A new process was started
// Here it's possible to wait for it to end:
p.WaitForExit();
} else {
// The process was already running
}
The second one returns a bool:
Process p = new Process();
p.StartInfo.FileName = "hello.exe";
bool s = p.Start();
if (s) {
// A new process was started
} else {
// The process was already running
}
p.WaitForExit();
For simple cases, the advantage is mainly convenience. Obviously you have more options (working path, choosing between shell-exec, etc) with the ProcessStartInfo route, but there is also a Process.Start(ProcessStartInfo) static method.
Re checking for errors; Process.Start returns the Process object, so you can wait for exit and check the error code if you need. If you want to capture stderr, you probably want either of the ProcessStartInfo approaches.
Very little difference. The static method returns a process object, so you can still use the "p.WaitForExit()" etc - using the method where you create a new process it would be easier to modify the process parameters (processor affinity and such) before launching the process.
Other than that - no difference. A new process object is created both ways.
In your second example - that is identical to this:
Process p = Process.Start("hello.exe");
p.WaitForExit();

Hanging process when run with .NET Process.Start -- what's wrong?

I wrote a quick and dirty wrapper around svn.exe to retrieve some content and do something with it, but for certain inputs it occasionally and reproducibly hangs and won't finish. For example, one call is to svn list:
svn list "http://myserver:84/svn/Documents/Instruments/" --xml --no-auth-cache --username myuser --password mypassword
This command line runs fine when I just do it from a command shell, but it hangs in my app. My c# code to run this is:
string cmd = "svn.exe";
string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml --no-auth-cache --username myuser --password mypassword";
int ms = 5000;
ProcessStartInfo psi = new ProcessStartInfo(cmd);
psi.Arguments = arguments;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8);
proc.WaitForExit(ms);
if (proc.HasExited)
{
return output.ReadToEnd();
}
This takes the full 5000 ms and never finishes. Extending the time doesn't help. In a separate command prompt, it runs instantly, so I'm pretty sure it's unrelated to an insufficient waiting time. For other inputs, however, this seems to work fine.
I also tried running a separate cmd.exe here (where exe is svn.exe and args is the original arg string), but the hang still occurred:
string cmd = "cmd";
string arguments = "/S /C \"" + exe + " " + args + "\"";
What could I be screwing up here, and how can I debug this external process stuff?
EDIT:
I'm just now getting around to addressing this. Mucho thanks to Jon Skeet for his suggestion, which indeed works great. I have another question about my method of handling this, though, since I'm a multi-threaded novice. I'd like suggestions on improving any glaring deficiencies or anything otherwise dumb. I ended up creating a small class that contains the stdout stream, a StringBuilder to hold the output, and a flag to tell when it's finished. Then I used ThreadPool.QueueUserWorkItem and passed in an instance of my class:
ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream,
Encoding.UTF8);
ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler);
proc.WaitForExit(ms);
if (proc.HasExited)
{
bufferHandler.Stop();
return bufferHandler.ReadToEnd();
}
... and ...
private class ProcessBufferHandler
{
public Stream stream;
public StringBuilder sb;
public Encoding encoding;
public State state;
public enum State
{
Running,
Stopped
}
public ProcessBufferHandler(Stream stream, Encoding encoding)
{
this.stream = stream;
this.sb = new StringBuilder();
this.encoding = encoding;
state = State.Running;
}
public void ProcessBuffer()
{
sb.Append(new StreamReader(stream, encoding).ReadToEnd());
}
public string ReadToEnd()
{
return sb.ToString();
}
public void Stop()
{
state = State.Stopped;
}
}
This seems to work, but I'm doubtful that this is the best way. Is this reasonable? And what can I do to improve it?
One standard issue: the process could be waiting for you to read its output. Create a separate thread to read from its standard output while you're waiting for it to exit. It's a bit of a pain, but that may well be the problem.
Jon Skeet is right on the money!
If you don't mind polling after you launch your svn command try this:
Process command = new Process();
command.EnableRaisingEvents = false;
command.StartInfo.FileName = "svn.exe";
command.StartInfo.Arguments = "your svn arguments here";
command.StartInfo.UseShellExecute = false;
command.StartInfo.RedirectStandardOutput = true;
command.Start();
while (!command.StandardOutput.EndOfStream)
{
Console.WriteLine(command.StandardOutput.ReadLine());
}
I had to drop an exe on a client's machine and use Process.Start to launch it.
The calling application would hang - the issue ended up being their machine assuming the exe was dangerous and preventing other applications from starting it.
Right click the exe and go to properties. Hit "Unblock" toward the bottom next to the security warning.
Based on Jon Skeet's answer this is how I do it in modern day (2021) .NET 5
var process = Process.Start(processStartInfo);
var stdErr = process.StandardError;
var stdOut = process.StandardOutput;
var resultAwaiter = stdOut.ReadToEndAsync();
var errResultAwaiter = stdErr.ReadToEndAsync();
await process.WaitForExitAsync();
await Task.WhenAll(resultAwaiter, errResultAwaiter);
var result = resultAwaiter.Result;
var errResult = errResultAwaiter.Result;
Note that you can't await the standard output before the error, because the wait will hang in case the standard error buffer gets full first (same for trying it the other way around).
The only way is to start reading them asynchronously, wait for the process to exit, and then complete the await by using Task.WaitAll
I know this is an old post but maybe this will assist someone. I used this to execute some AWS (Amazon Web Services) CLI commands using .Net TPL tasks.
I did something like this in my command execution which is executed within a .Net TPL Task which is created within my WinForm background worker bgwRun_DoWork method which holding a loop with while(!bgwRun.CancellationPending). This contains the reading of the Standard Output from the Process via a new Thread using the .Net ThreadPool class.
private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
while (!bgwRun.CancellationPending)
{
//build TPL Tasks
var tasks = new List<Task>();
//work to add tasks here
tasks.Add(new Task(()=>{
//build .Net ProcessInfo, Process and start Process here
ThreadPool.QueueUserWorkItem(state =>
{
while (!process.StandardOutput.EndOfStream)
{
var output = process.StandardOutput.ReadLine();
if (!string.IsNullOrEmpty(output))
{
bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
{
Type = "ExecutionInfo",
Text = output,
Configuration = s3SyncConfiguration
}));
}
if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
{
break;
}
}
});
});//work Task
//loop through and start tasks here and handle completed tasks
} //end while
}
I know my SVN repos can run slow sometimes, so maybe 5 seconds isn't long enough? Have you copied the string you are passing to the process from a break point so you are positive it's not prompting you for anything?

Categories