Windows服务更改批处理文件中回显/流重定向的行为

3
创建一个名为c:\test\first.bat的Windows批处理文件:
@echo off
echo A
call second.bat < empty.txt
echo B
echo C

还需要两个空文件 c:\test\second.bat 和 c:\test\empty.txt (如果它们不是空的也是同样的情况。)

运行 first.bat。预期输出为

A
B
C

现在,不再直接运行批处理文件,而是创建一个C#命令行应用程序:

using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var processInfo = new ProcessStartInfo("cmd.exe", @"/c c:\test\first.bat");
            processInfo.CreateNoWindow = true;
            processInfo.UseShellExecute = false;
            processInfo.RedirectStandardError = true;
            processInfo.RedirectStandardOutput = true;
            var process = new Process();
            process.EnableRaisingEvents = true;
            var log = new BlockingCollection<string>();
            process.OutputDataReceived += (sender, e) => log.Add(e.Data);
            process.Exited += (sender, e) =>
            {
                process.Dispose();
                File.WriteAllText(@"c:\test\log.txt", string.Join("\n", log));
            };
            process.StartInfo = processInfo;
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            process.WaitForExit();
        }
    }
}

正如预期的那样,文件c:\test\log.txt已创建并包含以下内容:

A
B
C

现在,不再是命令行应用程序,而是创建一个Windows服务:
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;

namespace WindowsService1
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
            this.CanStop = true;
        }

        protected override void OnStart(string[] args)
        {
            var processInfo = new ProcessStartInfo("cmd.exe", @"/c c:\test\first.bat");
            processInfo.CreateNoWindow = true;
            processInfo.UseShellExecute = false;
            processInfo.RedirectStandardError = true;
            processInfo.RedirectStandardOutput = true;
            var process = new Process();
            process.EnableRaisingEvents = true;
            var log = new BlockingCollection<string>();
            process.OutputDataReceived += (sender, e) => log.Add(e.Data);
            process.Exited += (sender, e) =>
            {
                process.Dispose();
                File.WriteAllText(@"c:\test\slog.txt", string.Join("\n", log));
            };
            process.StartInfo = processInfo;
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        protected override void OnStop()
        {
        }
    }
}

安装并启动服务(允许所有相关文件的必要权限)。 (看起来无论使用哪个帐户(用户、本地服务、本地系统...)都没有关系。) 再次创建文件c:\test\slog.txt,但现在它包含:
A
echo B
B
echo C
C

为什么?
(可能相关:如果在first.bat文件中的“echo C”后没有换行符,则slog.txt会包含:
A
echo B
B
more?

为什么?

尝试添加 processInfo.RedirectStandardInput = true; - Gennady
谢谢您的建议。是的,这使得服务的行为更符合我的预期。有什么想法吗?使用这个方法有什么不利之处吗? - Peter
当批处理器没有有效的标准输入流时,似乎会遇到问题。我想当重定向到 empty.txt 完成后,它尝试将标准输入句柄设置回原始(无效)值时,底层问题就会发生。 - Harry Johnston
1个回答

1

(在评论中提供了解决方案。转换为社区 wiki 答案。请参见 没有答案的问题,但在评论中解决(或在聊天中扩展) )

@Gennadiy 写道:

尝试添加 processInfo.RedirectStandardInput = true;

OP 写道:

是的,这使得服务的行为更像我预期的那样。有什么缺点使用这个方法吗?

@Harry Johnston 写道:

看起来当批处理器没有有效的标准输入流时会遇到麻烦。我想在重定向到 empty.txt 完成后,当它尝试将标准输入句柄设置回原始(无效)值时,潜在的问题就会发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接