Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: при старте cmd.eхе из c#-программы в командном окне отсутствует output  (Прочитано 5149 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Malaja
Команда клуба

de
Offline Offline
Пол: Женский

« : 14-10-2013 14:46 » 

Господа,
ситуация какая-то странная - зависла там, где не предполагала.
Исходная ситуация:
- студия 2010
- язык c#
- простая программка с одной формой и несколькими элементами на ней.

В определенный момент мне надо стартовать cmd.eхе, чтобы в ней запустить парочку clearcase - команд.
Сначала я слегка споткнулась на том, что в окне не появлялась сформированная команда. Но с этим разобралась быстро - оказалось, что строка должна начинаться с "/c" (в этом случае после выполнения команды окно закроется) или "/k" (окно останется):


Команды запускаются и выполняются без проблем, но есть одно маленькое "но":
я хотела считывать сообщения, выдаваемые после выполнения команд (это было бы неплохо, т.к. иногда команда не выполняется). И тут я поняла, что я вообще никаких сообщений в окне не вижу... Соответственно, output пустой тоже.

Код:
      System.Diagnostics.Process cmd = new System.Diagnostics.Process();
      cmd.StartInfo.Arguments = sArgs;
      cmd.StartInfo.FileName = "cmd.exe";
      cmd.StartInfo.RedirectStandardOutput = true;
      //cmd.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(DebuggerOutputHandler);
      cmd.StartInfo.UseShellExecute = false;
      cmd.Start();

      // пробовала разными путями: Nr.1
      string sOutput = cmd.StandardOutput.ReadToEnd();

      int nCount = 50;
      while (false == cmd.HasExited && nCount > 0)
      {
        System.Threading.Thread.Sleep(50);
        nCount--;

      } // while (false == cmd.HasExited || nCount > 0)

      // пробовала разными путями: Nr. 2
      System.IO.StreamReader outputOfproc = cmd.StandardOutput;
      string sLogFromProcess = "";
      while (outputOfproc.Peek() >= 0)
      {
        sLogFromProcess += outputOfproc.ReadLine() + Environment.NewLine;
      }
      sLogFromProcess += Environment.NewLine;

Вопрос: и чего ему не хватает?
да, все происходит на д:
« Последнее редактирование: 14-10-2013 14:49 от Malaja » Записан

холоднокровней, Маня, Ви не на работе
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 14-10-2013 18:57 » 

Стандартные потоки проверь. При создании нового процесса можно определить эти потоки. В Win32 это делается так. В шарпе наверняка должно быть что-то похожее.

Я имел в иду, проверь, куда эти потоки идут — в консоль или в никуда.
« Последнее редактирование: 14-10-2013 19:21 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 14-10-2013 20:27 » 

Malaja, всё у тебя правильно. Просто cmd.Start - это асинхронный вызов. Т.е. к моменту твоей попытки прочитать output там ещё ничего нет. Подожди, и всё будет. Можно ждать cmd.WaitForExit - с таймаутом ожидания или без. Можно подписаться на событие cmd.OutputDataReceived.

Кстати, что значит "в окне ничего не вижу"? Флажок UseShellExecute = false как раз  говорит, что в окне ничего и не должно быть. Даже больше: самого окна консоли не должно быть.

И остаётся за кадром, что ты передаёшь в аргументы. Передай "/c echo Hello world" - если увидишь в "Hello world", значит всё работает, а проблема в чём-то другом - в вызываемой из консоли программе, например.
« Последнее редактирование: 14-10-2013 20:32 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 15-10-2013 07:05 » 

Ир, всё делаешь правильно. Для считывания ошибок тебе надо добавить флаг:

Код: (C#)
cmd.StartInfo.RedirectStandardError = true;

Ну и потом сделать проще (вместо твоих циклов). Как Димка сказал, с ожиданием:

Код: (C#)
cmd.Start();
cmd.BeginOutputReadLine();
var output = cmd.StandardError.ReadToEnd();
cmd.WaitForExit();

После этого в output все тексты консоли.

Проверить успешность завершения можно:

Код: (C#)
if (cmd.ExitCode == 0)
{
   ...
}
« Последнее редактирование: 15-10-2013 07:09 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Malaja
Команда клуба

de
Offline Offline
Пол: Женский

« Ответ #4 : 15-10-2013 09:38 » 

Спасибочки всем!!! Подождать я не додумалась, решила, что результат туда сразу сливается по ходу выполнения команды. "И жить торопится", и начальство наседает Ага

Дим, с cmd.OutputDataReceived я сначала делала, но поняла, что в моей ситуации это неудобно, т.к. нужна static - переменная для сохранения текста. Начала искать пути для менее обременительного получения и хранения данных. И тут был облом... Спасибочки за инфу!
кстати, а почему ты говоришь, что при  UseShellExecute = false не должно быть самого окна? Оно прекрасно существует, только техт в окне отсутствует. Чтобы не появлялось окно, надо устанавливать cmd1.StartInfo.CreateNoWindow = true.

Джон,
спасибочки за подсказку насчет StandardError!

Кстати, определила, что:
1) cmd.StandardError.ReadToEnd() работает как в асинхронном, так и в синхронном режиме, а вот cmd.StandardOutput.ReadToEnd() - только в
синхронном.
2) cmd.BeginOutputReadLine() запускает асинхронный режим, после чего вызов cmd.StandardOutput.ReadToEnd() становится невозможным.

В результате вот (кусок из программки для всяких проб):
т.е. вызов команды для cleartool всегда будет давать ошибку.
ну а вызов dir обычно должен работать Ага

Код:

        private void btn_cmd_Click(object sender, EventArgs e)
        {
            string sArgs = " /c cleartool co -c \"test\" D:\\irina\\prog\\Exercises_c#\\UpdateStatusFiles\\Tebelewa_Test_Status_OMSp_CPPUNIT_EXE_GroupingOfVar_MPC.txt";
            string outputErr = "";
            TestCmd_asynchExecute(ref outputErr, sArgs);

            sArgs = " /c dir";
            string outputResult = "";
            TestCmd_synchExecute(ref outputErr, ref outputResult, sArgs);
        }


        /// <summary>
        /// start cmd - window and read output in asynchronous mode
        /// </summary>
        /// <param name="outputErr">out: error string</param>
        /// <param name="sArgs">in: argument - string</param>
        public void TestCmd_asynchExecute(ref string outputErr,
                                          string sArgs)
        {

            System.Diagnostics.Process cmd1 = new System.Diagnostics.Process();
            cmd1.StartInfo.Arguments = sArgs;
            cmd1.StartInfo.FileName = "cmd.exe";
            cmd1.StartInfo.RedirectStandardOutput = true;
            cmd1.StartInfo.RedirectStandardError = true;
            cmd1.StartInfo.UseShellExecute = false;
            cmd1.Start();
            cmd1.BeginOutputReadLine();
            outputErr = cmd1.StandardError.ReadToEnd();
            cmd1.WaitForExit();

            if (cmd1.ExitCode != 0)
            {
                outputErr += " *** return code = " + Convert.ToString(cmd1.ExitCode);
            }
        }


        /// <summary>
        /// start cmd - window and read output in synchronous mode
        /// </summary>
        /// <param name="outputErr">out: error string</param>
        /// <param name="outputResult">out: output string</param>
        /// <param name="sArgs">in: argument - string</param>
        public void TestCmd_synchExecute(ref string outputErr,
                                         ref string outputResult,
                                         string sArgs)
        {

            System.Diagnostics.Process cmd1 = new System.Diagnostics.Process();
            cmd1.StartInfo.Arguments = sArgs;
            cmd1.StartInfo.FileName = "cmd.exe";
            cmd1.StartInfo.RedirectStandardOutput = true;
            cmd1.StartInfo.RedirectStandardError = true;
            cmd1.StartInfo.UseShellExecute = false;
            cmd1.Start();

            outputErr = cmd1.StandardError.ReadToEnd();
            outputResult = cmd1.StandardOutput.ReadToEnd();
            cmd1.WaitForExit();

            if (cmd1.ExitCode != 0)
            {
                outputErr += " *** return code = " + Convert.ToString(cmd1.ExitCode);
            }
        }
« Последнее редактирование: 15-10-2013 09:42 от Malaja » Записан

холоднокровней, Маня, Ви не на работе
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 15-10-2013 12:03 » 

BeginOutputReadLine, если верить MSDN, нужен как раз, чтобы начали генерироваться события OutputDataReceived. Каждое такое событие, судя по всему, есть эквивалент ReadLine - т.е. происходит, когда в потоке встречается перевод строки.

Про их синхронность и асинхронность я тоже задумался. Но поскольку экспериментировал с PowerShell, и эксперименты эти меня увели вообще к вопросу многопоточности в PowerShell, каковая тут возможна явно через неблаговидное место, я по этому поводу высказываться не стал. Отсутствие асинхронности в PowerShell - это не показатель.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Malaja
Команда клуба

de
Offline Offline
Пол: Женский

« Ответ #6 : 15-10-2013 12:49 » 

Дим,

в проектах иногда приходится стартовать специально созданные .ехе, что я и делаю с помощью cmd. Там я пользуюсь OutputDataReceived, добавляя специально функцию обработки сообщений (они потом перенаправляются дальше). так вот я ни разу не вызывала для этого BeginOutputReadLine()... И все работало...

Все остальное я просто за вчера и сегодня проверила на практике, когда пыталась считать текст - результат выполнения команды. Глубоко копать просто не было времени.

Вот вариант с OutputDataReceived():

Код:

    /// <summary>
    /// start old client
    /// </summary>
    /// <param name="sNameClientExe">in: exe name</param>
    /// <param name="sArguments">in: arguments</param>
    /// <returns>error</returns>
    Managed.Error StartOldClient( string sNameClientExe,
                                  string sArguments)
    {
      const string cFuncName = "StartOldClientForCheck()";

       Log(cFuncName, "START >>>>>>>>>>>>>>>>>>>>>>>>>>>>... OK");

      // create a new process
      System.Diagnostics.Process oldClient = new System.Diagnostics.Process();

      // set name of process to execute
      oldClient.StartInfo.FileName = sNameClientExe;

      // fill StartInfo
      oldClient.StartInfo.UseShellExecute = false;
      oldClient.StartInfo.RedirectStandardOutput = true;
      oldClient.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(DebuggerOutputHandler);
      oldClient.StartInfo.Arguments = sArguments;

      // start process
      bool bRet = oldClient.Start();
      System.Threading.Thread.Sleep(10000);
      oldClient.WaitForExit(5000);

      // wait till process will stop.
      // is process is still running, stop it and close its window
      for (int i = 0; i < 50; i++)
      {
        if (false == oldClient.HasExited)
        {
          oldClient.Refresh();
          Thread.Sleep(2000);
        }
      }
      if (false == oldClient.HasExited && null != oldClient.MainWindowHandle)
      {
        oldClient.CloseMainWindow();
        oldClient.Refresh();
      }


      // get ExitCode
      if (null != oldClient && oldClient.HasExited)
      {
        int nResult = oldClient.ExitCode;
        if (nResult != 0)
        {
          // save this code 
          // тут свой код;

          // save all outputs from process in Log
          string sLogFromProcess = "" + Environment.NewLine + Environment.NewLine + Environment.NewLine +
                                    "LOG FROM oldClient.exe *** " + Environment.NewLine;

          // only if redirection is on
          if (oldClient.StartInfo.RedirectStandardOutput == true)
          {
            // get Output from process
            System.IO.StreamReader outputOfproc = oldClient.StandardOutput;

            // read all outputs in one string
            while (outputOfproc.Peek() >= 0)
            {
              sLogFromProcess += outputOfproc.ReadLine() + Environment.NewLine;
            }
            sLogFromProcess += Environment.NewLine;

            // write it in Log
           Log(cFuncName, sLogFromProcess);

            // for error - case:
            if (nResult < 0)
            {
              Log(cFuncName, " error = " + Convert.ToString((Managed.ErrorCode)nResult));
              Assert.Fail(cFuncName, " error = " + Convert.ToString((Managed.ErrorCode)nResult));
            } //if (nResult < 0)

          } // if (oldClient.StartInfo.RedirectStandardOutput == true)

        } // if (nResult != 0)

      } // if (null != oldClient && oldClient.HasExited)

      // stop process
      oldClient.Close();

       Log(cFuncName, "END >>>>>>>>>>>>>>>>>>>>>>>>>>>>... OK");

      return error;
    }



    /// <summary>
    /// write log in output
    /// </summary>
    /// <param name="proc">process</param>
    /// <param name="data">info</param>
    private static void DebuggerOutputHandler(object proc, System.Diagnostics.DataReceivedEventArgs data)
    {
      System.Console.WriteLine("OMS+ debugger output: " + data.Data);

    }

« Последнее редактирование: 15-10-2013 14:01 от Malaja » Записан

холоднокровней, Маня, Ви не на работе
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines