18

我有一项有时会调用批处理文件的服务。批处理文件需要 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\vacuumdb.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并设置管理员用户和密码,但仍然没有。

4

8 回答 8

28

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

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

我不知道这是否对你有用,但我没有挂起的问题。

于 2008-12-11T21:54:43.730 回答
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());
                }
            }
        }
    }
于 2010-01-07T09:47:59.020 回答
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();

经测试,工作清晰。

于 2013-05-09T05:13:26.640 回答
3

批处理文件有什么作用?您确定该进程正在以足够的权限启动以执行批处理文件吗?服务可以被限制在他们被允许做的事情上。

还要确保您是否正在执行类似使用复制命令覆盖文件的操作,例如:

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

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

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

我不记得是否 System.Diagnostics。是否仅在调试中可用。可能不是,但其中一些可能是。我得为你检查一下。

希望这能给你一些想法。

拉里

于 2008-12-11T21:58:52.317 回答
3

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

于 2008-12-12T15:10:41.837 回答
3

我将采取的下一步是启动调试器,看看你是否能知道程序正在等待什么。如果您在汇编调试方面经验丰富,您可能能够使用 ProcExp、FileMon 等工具了解正在发生的事情。

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

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

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

拉里

于 2008-12-12T18:51:16.197 回答
1

这是解决方案。解决方案尚不清楚,因为我已经更改了很多次代码,现在它可以工作了!

我曾尝试使用用户帐户,但它不起作用。使用本地系统。这是执行的代码,主要是 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();

谢谢大家,我会投票给大家并接受凯文,因为他从一开始就帮助我。很奇怪,因为它现在可以工作了......

于 2008-12-13T19:35:24.450 回答
1

Daok,看起来您唯一更改的是初始 WaitForExit() 的超时时间。你需要非常小心。如果某些东西确实挂起您的服务,它将永远不会返回(好吧,到目前为止,您所做的工作几乎都是如此......呵呵),但这对最终用户不利......

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

那,或者在您可以监视的某个线程中将其关闭,如果挂起时间过长,则将其杀死。

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

于 2008-12-15T23:53:46.207 回答