Friday, July 29, 2016

Running sqlPlus.exe as a System.Diagnostics.Process? Here's how to kill it.

I recently had a project that required me to execute the Oracle command line tool, sqlPlus.exe. To execute the process and pass the required parameters was no problem. However, I needed to run this process multiples times in a row for various files. As I was doing so, I would watch task manager and I noticed that I had multiple sqlPlus.exe processes running, even though my process that I wrote was only run once.

To start, lets look at my code that executs sqlPlus.exe.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psiProc = new System.Diagnostics.ProcessStartInfo();
psiProc.WorkingDirectory = gcnfgOracle.SqlPlusLocation;
psiProc.FileName = "sqlPlus.exe";
psiProc.RedirectStandardOutput = true;
psiProc.RedirectStandardError = true;
psiProc.UseShellExecute = false;
process.StartInfo = psiProc;
dbProcess.Start();
dbProcess.WaitForExit();
string lstrStdOut = dbProcess.StandardOutput.ReadToEnd(); //Read my Output
int liExitCode = dbProcess.ExitCode; // What is my return code
dbProcess.Close();

So this looks all well and good, however, after looking a the sqlPlus.exe process myself, the process never exists on its ownAfter it processes my request, the process remains open waiting for user input, .WaitForExit() just waited.

I had attempted some workaround that required me to wait a certain number of seconds and then forcibly killing the process but I could be killing an inflight transaction and did not want to do that. So I came up with this solution.

Here is my solution. I will use the same code as above, just highlighting the changes:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psiProc = new System.Diagnostics.ProcessStartInfo();
psiProc.WorkingDirectory = gcnfgOracle.SqlPlusLocation;
psiProc.FileName = "sqlPlus.exe";
psiProc.RedirectStandardOutput = true;
psiProc.RedirectStandardError = true;

psiProc.RedirectStandardInput = true; // Allow me to send input to this process

psiProc.UseShellExecute = false;
process.StartInfo = psiProc;
dbProcess.Start();
dbProcess.WaitForExit();

StreamWriter swConsoleInput = dbProcess.StandardInput; // Get the stream of the input
swConsoleInput.WriteLine("exit"); // Send in the command that will exit the sqlPlus.exe process

string lstrStdOut = dbProcess.StandardOutput.ReadToEnd(); // Read my Output
int liExitCode = dbProcess.ExitCode; // What is my return code
dbProcess.Close();

That's it.. just get a stream to the input and send it "Exit". Keep in mind that you need to press the Enter Key after typing exit. To do this, I am using the WriteLine Method of the StreamWriter. That is very important If you use Write vs WriteLine, you will need to send the enter key manually.

No comments:

Post a Comment