调用批处理文件后,服​​务在WaitForExit处挂起

时间:2008-12-11 21:46:04

标签: c# .net service windows-services

我有一项服务有时会调用批处理文件。批处理文件需要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()。我必须从Process中删除批处理文件才能继续。 (我确定文件存在,因为我可以在进程列表中看到它。)

如何修复此挂断?

更新#1:

Kevin的代码允许我获得输出。我的一个批处理文件仍然挂起。

  

“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 \ vacuumdb.exe”-U postgres -d DbTest

我检查了路径,postgresql路径没问题。输出目录确实存在,仍然可以在服务外部运行。有什么想法吗?

更新#2:

我为proc.StartInfo.FileName编写了“C:\ EnterpriseDB \ Postgres \ 8.3 \ bin \ pg_dump.exe”而不是批处理文件的路径,并将所有参数添加到proc.StartInfo.Arguments。结果没有变化,但我在进程窗口中看到pg_dump.exe。同样,这只发生在服务中。

更新#3:

我已经与管理员组中的用户一起运行该服务,但无济于事。我为服务的用户名和密码恢复了null

更新#4:

我创建了一个简单的服务来在事件日志中编写跟踪并执行包含“dir”的批处理文件。它现在将挂起proc.Start(); - 我尝试将帐户从LocalSystem更改为用户,我设置了admnistrator用户和密码,但仍然没有。

8 个答案:

答案 0 :(得分:29)

以下是我用来执行批处理文件的内容:

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();

我不知道这对你来说是否能解决问题,但我没有问题。

答案 1 :(得分:11)

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());
                }
            }
        }
    }

答案 2 :(得分:4)

            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();

经过测试,工作清晰。

答案 3 :(得分:3)

批处理文件有什么作用?您确定该进程是否已启动并具有足够的权限来执行批处理文件?可以限制服务的范围。

另外,请确保您是否在复制命令中执行类似操作,以覆盖您执行以下操作的文件:

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

此外,请确保您使用批处理命令的完整路径等。如果批处理文件以某种“控制台”模式启动GUI应用程序,这可能也是一个问题。请记住,服务没有“桌面”(除非您启用“与桌面交互”)以绘制任何类型的窗口或消息框。在您的程序中,您可能希望打开stdout和stderr管道并在执行期间从中读取它们,以防您收到任何错误消息或任何内容。

Web服务可能正在作为IUSR帐户或匿名帐户执行,这可能对您来说可能是一个问题。如果它在控制台中运行时有效,那只是第一步。 :)

我不记得是否有System.Diagnostics。仅在调试时可用。可能不是,但其中一些可能是。我将不得不检查你的情况。

希望这会给你一些想法。

拉​​里

答案 4 :(得分:3)

pg_dump.exe可能会提示用户输入。此数据库是否需要身份验证您是否依赖于服务不存在的任何环境变量?我不知道pg_dump但是它会提示输入的其他可能原因是什么?

答案 5 :(得分:3)

我将采取的下一步是启动调试器,看看你是否可以告诉程序正在等待什么。如果您在汇编中进行调试,则可以使用ProcExp,FileMon等工具获取正在发生的事情的IDEA。

作为Windows服务而不是Web服务,会产生很大的不同。无论如何,您是否尝试过设置“允许服务与桌面交互”的建议?

如果您绝望,可以尝试启动cmd.exe而不是批处理文件。然后,使用cmd.exe的cmd行参数,您可以让IT启动批处理文件。如果打开与桌面的交互,这可能会为您提供cmd提示窗口以查看实际输出。

有关cmd.exe的完整帮助,只需输入cmd /?在任何命令提示符下。

拉​​里

答案 6 :(得分:1)

这是解决方案。解决方案并不清楚,因为我已经改变了很多时间代码,现在它正在运行!

我曾尝试使用“用户帐户”,但这并不起作用。使用LocalSystem。这是执行的代码,主要是Kevin给我的。

            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();

谢谢大家,我会向所有人投票并接受凯文,因为他从一开始就帮助我。非常奇怪,因为它现在有效......

答案 7 :(得分:1)

Daok,看起来你唯一改变的是初始WaitForExit()的超时时间。你需要非常小心。如果某事 DOES 挂起你的服务,它将永远不会返回(好吧,到目前为止,它已经为你做了很多工作......嘿),但这对最终用户来说并不好。 ..

现在,也许你知道是什么导致它挂起,你可以进一步调试它并找到完整的解决方案......

那,或者在你可以监控的某个线程中将其关闭,如果挂起的时间过长就会终止。

价值2美分,通常不是很多。 ;)