• Программинг

Нужны источники бесперебойного питания?

Источники бесперебойного питания от дизельстор

Читаем стандартный вывод консольного приложения + DOS to UTF

Добрый день друзья, сегодня я расскажу, как можно использовать стандартный вывод запускаемого консольного приложения.

Существует еще достаточно большое количество приложений, у которых нет окон и «кнопочного» интерфейса. Все, что выводят на экран – это простой текст, который даже скопировать не всегда можно. Брать переписывать все консольные приложения нет смысла, тем более что автор уже все за вас написал. Если вам нужно использовать консольную программу, но не хочется видеть на экране консоль, тогда можно написать свою оболочку GUI (графический интерфейс пользователя). Эта оболочка должна в фоновом режиме запускать консольное приложение, управлять им и получать результаты работы.

Давайте создадим два проекта. Один из них будет консольным приложением, другой основанный на Windows Form.
1. В Visual Studio создайте новое Console Application и вставьте следующий код в область метода Main. Добавим пару методов, которые выводят текстовую информацию на экран. Проверьте приложение на работоспособность.

1 static void Main(string[] args)
2 {
3     string command = string.Empty;
4  
5     if (args.Length != 0)
6     {
7         switch (args[0])
8         {
9             case "-view": view();
10                 break;
11             case "-ver": version();
12                 break;
13             default: Console.WriteLine("Аргумент " + args[0] + " не используется!");
14                 break;
15         }
16     }
17  
18     while (true)
19     {
20         command = Console.ReadLine();
21         switch (command.ToLower())
22         {
23             case "view": view();
24                 break;
25             case "ver": version();
26                 break;
27             case "exit": return;
28         }
29     }
30 }
31  
32 private static void view()
33 {
34     Console.WriteLine(string.Format("{0,-26}:{1}", "Имя текущего пользователя", Environment.UserName));
35     Console.WriteLine(string.Format("{0,-26}:{1}", "Версия ОС", Environment.OSVersion));
36     Console.WriteLine(string.Format("{0,-26}:{1}", "Имя компьютера", Environment.MachineName));
37 }
38  
39 private static void version()
40 {
41     Console.ForegroundColor = ConsoleColor.Green;
42     Console.WriteLine(string.Format("{0,-26}:{1}", "Текущая версия .NET", Environment.Version));
43     Console.ForegroundColor = ConsoleColor.White;
44 }

2. Создайте новое Windows Form приложение, в котором мы реализуем функции работы с консольным приложением.

Для реализации задуманного, нам понадобиться реализовать три метода.
Первый метод будет запускать внешнюю программу и инициализировать перехват данных. Код метода Run:

1 private void run(string utilityName, string arguments)
2 {
3     try
4     {
5         //очищаем поле вывода
6         clearOutput();
7         //создаем новый процесс, который будет работать с консолью
8         pr = new Process();
9         //задаем имя запускного файла
10         pr.StartInfo.FileName = utilityName;
11         //задаем аргументы для этого файла
12         pr.StartInfo.Arguments = arguments;
13         //отключаем использование оболочки, чтобы можно было читать данные вывода
14         pr.StartInfo.UseShellExecute = false;
15         //перенаправляем данные вовода
16         pr.StartInfo.RedirectStandardOutput = true;
17         //задаем кодировку, чтобы читать кириллические символы
18         pr.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
19         //запрещаем создавать окно для запускаемой программы
20         pr.StartInfo.CreateNoWindow = true;
21         //подписываемся на событие, которые возвращает данные
22         pr.OutputDataReceived += new DataReceivedEventHandler(sortOutputHandler);
23         //включаем возможность определять когда происходит выход из программы, которую будем запускать
24         pr.EnableRaisingEvents = true;
25         //подписываемся на событие, когда процесс завершит работу
26         pr.Exited += new EventHandler(whenExitProcess);
27         //запускаем процесс
28         pr.Start();
29         //начинаем читать стандартный вывод
30         pr.BeginOutputReadLine();
31     }
32     catch (Exception error)
33     {
34         MessageBox.Show("Ошибка при запуске!\n" + error.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
35     }
36 }

Порядок выполнения описан в комментариях. Для правильной работы с русскими сим-волами вы должны всегда использовать строку pr.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866), которая правильно задает кодировку выходного потока. Следует помнить, что pr.Start() автоматически запускает внешнее приложение в отдельном потоке.

Второй и третий методы, это функции для событий получения данных и завершения работы приложения.

1 private void sortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
2 {
3     //используем делегат для доступа к элементу формы из другого потока
4     BeginInvoke(new MethodInvoker(delegate
5     {
6         if (!String.IsNullOrEmpty(outLine.Data))
7         {
8             //выводим результат в консоль
9             txtOutput.AppendText(outLine.Data + Environment.NewLine);
10         }
11     }));
12 }
13  
14 private void whenExitProcess(Object sender, EventArgs e)
15 {
16     BeginInvoke(new MethodInvoker(delegate
17     {
18         txtOutput.AppendText("Программа завершила свою работу!");
19     }));
20 }

BeginInvoke(new MethodInvoker(delegate… позволяет получить доступ к элементу интерфейса из другого потока.

Метод run вызывается следующим образом:

1 run(Path.Combine(Application.StartupPath, "test.exe"), "-view");

После завершения работы, скопируйте файл test.exe в папку со вторым приложением. Вот что у нас получилось:

1    run(Path.Combine(Application.StartupPath, "test.exe"), "-view");

После завершения работы, скопируйте файл test.exe в папку со вторым приложением. Вот что у нас получилось:

31

Бонус:

Функция перекодировки из DOS в UTF:

1 /// <summary>
2         /// Перекодировка из dos в UTF8
3         /// </summary>
4         /// <param name="src"></param>
5         /// <returns></returns>
6         private string DosToUtf(string src)
7         {
8             try
9             {
10                 //создаем кодовую таблицу для кодировки DOS
11                 Encoding dos866 = Encoding.GetEncoding(866);
12                 //получаем массив байтов для строки
13                 byte[] srcBytes = dos866.GetBytes(src);
14                 //конвертируем из кодировки DOS в UTF8
15                 byte[] dstBytes = Encoding.Convert(dos866, UTF8Encoding.UTF8, srcBytes);
16                 //получем результирующую строку
17                 string source = UTF8Encoding.UTF8.GetString(dstBytes);
18                 return source;
19             }
20             catch (Exception error) //задаем исключение, если что-то пойдет не так
21             {
22                 MessageBox.Show(error.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
23             }
24             return "";
25         }

Заключение

Разобрали как запустить внешнее приложение.
Как из него читать выходные данные.
Как определить завершение внешнего приложения.

Этим все не ограничивается. Разработчику также доступны функции RedirectStandardError и RedirectStandardInput, соответственно для перехвата ошибок и отправки данных внешнему приложению.

Единственно, что нельзя сделать – подключиться с стандартному выводу приложения, которое уже было запущено до нас.