Служба зависает в WaitForExit после вызова командного файла

У меня есть служба, которая иногда вызывает командный файл. Пакетный файл занимает 5-10 секунд для выполнения:

System.Diagnostics.Process proc = new System.Diagnostics.Process(); // Declare New Process
    proc.StartInfo.FileName = fileName;
    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    proc.StartInfo.CreateNoWindow = true;
    proc.Start();
    proc.WaitForExit();

Файл существует, и код работает, когда я запускаю тот же код в консоли. Однако, когда он работает внутри службы, он зависает на WaitForExit(). Я должен убить командный файл из процесса, чтобы продолжить. (Я уверен, что файл существует, поскольку я вижу его в списке процессов.)

Как я могу исправить это зависание?

Обновление № 1:

Код Кевина позволяет мне получить вывод. Один из моих командных файлов все еще висит.

"C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \ pg_dump.exe" -i -h localhost -p 5432 -U postgres -F p -a -D -v -f "c: \ backupcasecocher \ backupdateevent2008.sql" -t "\" public \ ". \" dateevent \ "" "DbTest"

Другой пакетный файл:

"C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \uumdb.exe" -U postgres -d DbTest

Я проверил путь, и postgresqlпуть в порядке. Выходной каталог существует и все еще работает за пределами службы. Любые идеи?

Обновление № 2:

Вместо пути к пакетному файлу я написал «C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \ pg_dump.exe» для proc.StartInfo.FileNameи добавил все параметры в proc.StartInfo.Arguments. Результаты не изменились, но я вижу pg_dump.exeв окне процесса. Опять же, это происходит только внутри сервиса.

Обновление № 3:

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

Обновление № 4:

Я создал простой сервис для записи трассировки в журнал событий и запуска командного файла, который содержит «dir». Теперь он будет зависать proc.Start();- я попытался изменить учетную запись с LocalSystem на User, и я установил пользователя и пароль администратора, но ничего не вышло.

11.12.2008 21:46:04
@nzpcmad: Откуда ты взял идею изменить тег ОП?
GEOCHET 11.12.2008 21:57:26
Я не nzpcmad, но мое предположение таково: поскольку он говорит: «У меня есть веб-сервис», я предполагаю, что у него есть веб-служба (.asmx), а не служба Windows.
Michael Stum♦ 11.12.2008 22:06:32
@Michael: я не вижу, как это оправдывает / меняет / тег ОП.
GEOCHET 11.12.2008 22:08:29
Это не веб-сервис, я написал его в первой строке, может быть, он очень устал. Хорошим является "сервис". Сожалею.
Patrick Desjardins 11.12.2008 22:22:59
@Daok: я понял, но теги - это все-таки ваш выбор.
GEOCHET 11.12.2008 22:30:15
8 ОТВЕТОВ
РЕШЕНИЕ

Вот что я использую для выполнения командных файлов:

proc.StartInfo.FileName                 = target;
proc.StartInfo.RedirectStandardError    = true;
proc.StartInfo.RedirectStandardOutput   = true;
proc.StartInfo.UseShellExecute          = false;

proc.Start();

proc.WaitForExit
    (
        (timeout <= 0)
            ? int.MaxValue : timeout * NO_MILLISECONDS_IN_A_SECOND *
                NO_SECONDS_IN_A_MINUTE
    );

errorMessage = proc.StandardError.ReadToEnd();
proc.WaitForExit();

outputMessage = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();

Я не знаю, поможет ли это вам, но у меня нет проблемы с этим.

28
12.02.2014 01:34:12
Да .. Делай, что говорит Кевин. Он перенаправляет stderr и stdout, как я уже упоминал, но одно из больших отличий заключается в том, что он устанавливает «UseShellExecute» в false, и это то, что вы должны учитывать, когда дело доходит до Vista ... Хороший ответ, Кевин ... Ларри
LarryF 11.12.2008 22:01:10
Позвольте мне попробовать! Я вернусь после.
Patrick Desjardins 11.12.2008 22:15:56
Почему в секунду нет миллисекунд?
Jay Bazuzi 11.12.2008 22:27:16
Я думаю, что НЕТ - это сокращение для числа в этом контексте.
alexandrul 11.12.2008 22:31:54
Я думаю, что это как-то связано с параметрами в командном файле. Я столкнулся с этой проблемой, и мне пришлось их устранить. У меня не хватило времени, и мне пришлось быстро найти решение без них. Завтра утром на работе буду ковыряться, если никто не выложил решение.
kemiller2002 12.12.2008 00:11:35

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

Также убедитесь, что вы делаете что-то вроде usin в команде copy, чтобы перезаписать файл, который вы делаете что-то вроде:

echo Y | copy foo.log c:\backup\

Кроме того, убедитесь, что вы используете полные пути для командных команд и т. Д. Если пакетный файл запускает приложение с графическим интерфейсом в каком-то режиме «Консоль», это тоже может быть проблемой. Помните, что сервисы не имеют «рабочего стола» (если вы не включили «взаимодействие с рабочим столом») для рисования окон или окон сообщений любого типа. В вашей программе вы можете захотеть открыть каналы stdout и stderr и читать их во время выполнения, если вы получаете какие-либо сообщения об ошибках или что-то еще.

WebServices, вероятно, выполняются как учетная запись IUSR или как анонимная учетная запись, что может быть проблемой для вас. Если он работает, когда вы запускаете его в консоли, это только первый шаг. :)

Я не помню, если System.Diagnostics. доступны только в отладочной или нет. Возможно нет, но некоторые из них могут быть. Я должен проверить это для тебя.

Надеюсь, что это дает вам некоторые идеи.

Larry

3
11.12.2008 21:58:52

Вероятно, pg_dump.exe запрашивает ввод данных пользователем. Требуется ли для этой базы данных аутентификация? Вы полагаетесь на какие-либо переменные ОКРУЖАЮЩЕЙ СРЕДЫ, которые не будут присутствовать для службы? Я не знаю pg_dump, но каковы другие возможные причины, по которым он запрашивает ввод?

3
12.12.2008 15:10:41
Я могу сделать эту команду из командной строки cmd.exe, и она работает без запроса.
Patrick Desjardins 12.12.2008 15:25:37

Следующий шаг, который я хотел бы сделать, - запустить отладчик и посмотреть, сможете ли вы сказать, что ожидает программа. Если у вас есть опыт отладки в сборке, вы можете получить ИДЕЮ того, что происходит, используя такие инструменты, как ProcExp, FileMon и т. Д.

Быть Windows SERVICE, а не веб-сервисом, имеет большое значение. В любом случае, вы попробовали мое предложение установить «Разрешить службе взаимодействовать с рабочим столом»?

Если вы в отчаянии, вы можете попробовать запустить cmd.exe вместо вашего командного файла. Затем, используя параметры строки cmd.exe cmd.exe, вы можете настроить IT на запуск командного файла. Это, вероятно, даст вам окно приглашения cmd для просмотра фактического вывода, если вы включите взаимодействие с рабочим столом.

Для полной справки по cmd.exe просто наберите cmd /? в любой командной строке.

Larry

3
12.12.2008 18:51:16
Теперь командный файл содержит только «dir». Я создал решение за пределами реального проекта и пытаюсь его выполнить. Это все еще висит. Последний журнал у меня есть только перед методом proc.Start ().
Patrick Desjardins 13.12.2008 18:00:03

Вот решение. Решение не ясно, потому что я столько раз менял код, и теперь он работает!

Я пытался использовать учетную запись пользователя, и это не то, что сработало. Используйте LocalSystem. Вот код, который выполняется, в основном то, что дал мне Кевин.

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = fileName;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;


            proc.Start();
            proc.WaitForExit();
            output1 = proc.StandardError.ReadToEnd();
            proc.WaitForExit();
            output2 = proc.StandardOutput.ReadToEnd();
            proc.WaitForExit();

Спасибо всем, я проголосую за всех и приму Кевина, так как он помогает мне с самого начала. Очень странно, потому что это работает сейчас ...

1
13.12.2008 19:35:24
Это хорошо, если вы просто делаете разовую вещь, но, пожалуйста, не поставляйте программное обеспечение, которое запускает сценарии как локальная система, его очень сложно защитить
Ana Betts 13.12.2008 20:30:04
Да. Вместо этого заставьте их выполнять ActiveScript, чтобы злоумышленник мог, по крайней мере, использовать vbScript, чтобы заставить мяч двигаться ... :) (Конечно, вы, ребята, все должны знать, что я просто шучу. Я рад, что он нашел свое решение, просто с ума сошел, что Кевин понял это правильно сначала хе-хе ..) :) СНОВА K / K СНОВА. Никто не злится на меня сейчас ...
LarryF 15.12.2008 23:56:57

Даок, похоже, что единственное, что вы изменили, - это время ожидания начального WaitForExit (). Вы должны быть ОЧЕНЬ осторожны с этим. Если что - то ДЕЛАЕТ повесить службу, он никогда не вернется (и хорошо, очень много работы , как это было для вас до сих пор .. хе), но это не будет хорошо для конечных пользователей ...

Теперь, возможно, вы знаете, что вызывает это зависание, вы можете отладить его дальше и найти полное решение ...

Это, или раскрутить это в каком-то потоке, который вы можете отслеживать, и убить, если он висит слишком долго.

Только мои 2 цента, что обычно не так много. ;)

1
27.02.2009 21:26:45
using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    namespace VG
    {
        class VGe
        {
            [STAThread]
            static void Main(string[] args)
            {
                Process proc = null;
                try
                {                
                    string targetDir = string.Format(@"D:\adapters\setup");//this is where mybatch.bat lies
                    proc = new Process();
                    proc.StartInfo.WorkingDirectory = targetDir;
                    proc.StartInfo.FileName = "mybatch.bat";
                    proc.StartInfo.Arguments = string.Format("10");//this is argument
                    proc.StartInfo.CreateNoWindow = false;
                    proc.Start();
                    proc.WaitForExit();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception Occurred :{0},{1}", ex.Message,ex.StackTrace.ToString());
                }
            }
        }
    }
11
21.03.2018 19:07:02
Почти то, что у меня было в начале, не так ли?
Patrick Desjardins 7.01.2010 19:00:05
            string targetDir = string.Format(@"D:\");//PATH
            proc = new Process();
            proc.StartInfo.WorkingDirectory = targetDir;
            proc.StartInfo.FileName = "GetFiles.bat";
            proc.StartInfo.Arguments = string.Format("10");//argument
            proc.StartInfo.CreateNoWindow = false;
            proc.Start();
            proc.WaitForExit();

Проверено, работает понятно.

4
9.05.2013 05:13:26