关于c#:Service在调用批处理文件后挂起在WaitForExit上

Service hangs up at WaitForExit after calling batch file

我有一个有时调用批处理文件的服务。批处理文件需要5-10秒才能执行:

1
2
3
4
5
6
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号:

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:enterprisedbpostgres8.3inpg dump.exe",并将所有参数添加到proc.StartInfo.Arguments中。结果是不变的,但我在进程窗口中看到了pg_dump.exe。同样,这只发生在服务内部。

更新第3号:

我已经使用管理员组中的一个用户运行了该服务,但没有用。我为服务的用户名和密码恢复了null

更新第4号:

我创建了一个简单的服务,在事件日志中写入跟踪,并执行一个包含"dir"的批处理文件。现在它将挂在EDOCX1上(6),我尝试将帐户从localsystem更改为user,并设置admnistrator用户和密码,但仍然没有。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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());
                }
            }
        }
    }


1
2
3
4
5
6
7
8
            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();

经过测试,工作正常。


我将采取的下一步是启动调试器,看看您是否可以告诉程序正在等待什么。如果您在程序集调试方面有经验,那么您可能能够使用ProcExp、FileMon等工具了解正在发生的事情。

作为一个Windows服务,而不是Web服务,有很大的不同。不管怎样,你有没有尝试过我的建议设置"允许服务与桌面交互"?

如果您不顾一切,可以尝试启动cmd.exe而不是批处理文件。然后,使用cmd.exe的cmd行参数,可以让它启动批处理文件。如果打开"与桌面交互",这可能会给您一个命令提示窗口来查看实际输出。

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

拉里


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


批处理文件的作用是什么?您确定启动进程时有足够的权限来执行批处理文件吗?服务可以限制在允许的范围内。

另外,请确保您正在执行如下操作:使用copy命令覆盖执行以下操作的文件:

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

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

webservices可能以iusr帐户或匿名帐户的形式执行,这可能是您的一个问题。如果它在控制台中运行时有效,那么这只是第一步。:)

我不记得是不是System.Diagnostics。只有在调试时才可用。可能不是,但其中一些可能是。我得帮你查一下。

希望这能给你一些建议。

拉里


daok,看起来您唯一更改的是初始waitForExit()的超时时间。你得小心点。如果有什么东西挂起了你的服务,它将永远不会回来(而且,到目前为止,它对你来说已经是相当大的工作了)。呵呵),但这对最终用户不好……

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

或者把它放到你可以监视的线程中,如果它挂得太久就杀死它。

只是我的2美分价值,这通常不是很多。;)


这是解决方案。解决方案不清楚,因为我更改了太多的代码,现在它开始工作了!

我试过使用一个用户帐户,但这不是有效的。使用本地系统。这是执行的代码,主要是凯文给我的。

1
2
3
4
5
6
7
8
9
10
11
12
13
            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();

谢谢大家,我会投票给所有人,接受凯文,因为他从一开始就帮助我。很奇怪,因为它现在起作用了…