Thursday, October 21, 2010

sending Enter keystoke to console application process

Use Case.

One console application (A) should open another console application (B) in separate process and send Enter keystroke when work is done.

Solution.

Application B is simple WCF server hosted in console application, which looks like:


        static void Main(string[] args)
        {
            try
            {
                using (ServiceHost host = WorkflowRuntimeHostFactory.Create(typeof(MyService)))
                {
                    host.Open();

                    Console.WriteLine("Press any key to stop server...");
                    Console.ReadLine();

                    host.Close();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                Console.ReadLine();
            }
        }

Application A looks like this:

            string returnvalue = string.Empty;

            string args = "";
            string fileName = "path to application A";

            ProcessStartInfo info = new ProcessStartInfo(fileName);
            info.UseShellExecute = false;
            info.Arguments = args;
            info.RedirectStandardInput = true;
            info.RedirectStandardOutput = false;
            info.RedirectStandardError = false;
            info.CreateNoWindow = false;
            info.WorkingDirectory = Path.GetDirectoryName(fileName);

            try
            {
                using (Process process = Process.Start(info))
                {
                    try
                    {
                        // Do some work with server
                        Thread.Sleep(2000);
                    }
                    finally
                    {
                        // Shutdown console server
                        try
                        {
                            process.StandardInput.WriteLine("close");
                            if (!process.HasExited)
                            {
                                if (process.Responding)
                                {
                                    try
                                    {
                                        process.Close();
                                    }
                                    catch
                                    {
                                        throw new InvalidOperationException("Unable to close process");
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        process.Kill();
                                    }
                                    catch
                                    {
                                        throw new InvalidOperationException("Unable to kill process");
                                    }
                                }
                            }
                        }
                        catch (Exception e) 
                        {
                            Console.WriteLine("Error occured: " + e.ToString());
                            throw new ServerShutdownException(e);
                        }
                        finally
                        {
                            // Cleanup code
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw;
            }

The key string in the code above is:
process.StandardInput.WriteLine("close");

The trick is that WriteLine method send also \n symbol required by Application B. This is not elegant solution, but it works fine for me. More investigations pointed me to following code (google for GenerateConsoleCtrlEvent):

GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, process.Id);

but accidentally it was not working properly and Application B was not closed.


GenerateConsoleCtrlEvent Win32 API has a special limitation. From MSDN: "Only those processes in the  group that share the same console as the calling process receive the signal."

This makes GenerateConsoleCtrlEvent impossible to use in our case.

No comments:

Post a Comment