2011-11-16 123 views
3

我有一个Web应用程序,其中有一个用户可以运行批处理文件的页面,查看输出并发送输入。当进程遇到导致其暂停的事件(例如暂停)或需要用户按Y或N以继续的问题时,会出现我的问题。为了这个问题我们会暂停。运行批处理文件并在暂停后读取最后一行输出

这是我的批处理文件:

pause 

当在Windows中运行,我得到我的屏幕“按任意键继续......”上显示的输出,我按enter键,并退出。但是当我的应用程序运行这个批处理文件时,我没有得到任何输出,但是我知道它在等待什么,所以我按下回车键,然后才看到输出“按任意键继续...”。

我在控制台应用程序中创建了我的代码的简化版本,并且发生了同样的情况,我得到一个空白屏幕,然后按Enter键,然后我看到“按任意键继续...”

任何想法我怎么去得到这一行的输出之前我需要按下键?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 
using System.IO; 

namespace BatchCaller 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ProcessStartInfo psi = new ProcessStartInfo() 
      { 
       FileName = @"C:\Projects\BatchCaller\BatchCaller\Test2.bat", 
       RedirectStandardOutput = true, 
       RedirectStandardInput = true, 
       UseShellExecute = false, 
       CreateNoWindow = true 
      }; 

      Process proc = new Process(); 

      proc.StartInfo = psi; 
      proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); 
      proc.Start(); 
      proc.BeginOutputReadLine(); 

      // Problem is not here, ignore this, just my temporary input method. 
      // Problem still occurs when these two lines are removed. 
      string inputText = Console.ReadLine(); 
      proc.StandardInput.WriteLine(inputText); 

      proc.WaitForExit(); 
     } 

     static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
     { 
      // This method doesnt get called for output: "Press any key to continue..." 
      // Why? 
      if (e.Data != null) 
       Console.WriteLine(e.Data); 
     } 
    } 
} 
+1

很好的问题。 +1。 – Kangkan

+0

我想我已经用我的临时输入法混淆了人。忽略输入,这不是问题,如果我从代码中删除它,我仍然看不到输出“按任意键继续...”。这是我想解决的问题。 – Owen

+0

也从批处理文件中删除@echo。它使问题更清楚,暂停显示在屏幕上,但没有“按任意键继续...” – Owen

回答

0

我意识到它并没有读取最后一行,因为data received事件只是在有一整行输出后触发,但当它暂停或询问问题时,光标仍然在同一行上。连续检查输出流的新线程是解决这个小问题的方法。

我也设法解决了我的整个问题,所以现在我运行脚本时所得到的结果与命令提示符窗口类似。

下面是它的工作原理很基本的总结:

我开始运行一个批处理文件的新方法。同时,我开始一个新的线程,不断循环询问进程的更多输出,并将该输出存储到队列中。我的.NET计时器不断检查队列中的文本,并将其输出到我的ajax面板。我使用文本框和ajax将文本输入到流程输入和我的ajax面板中。我还需要大量的JavaScript,并且我必须使用会话变量才能使其顺利运行。

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" 
    CodeBehind="Scripts.aspx.cs" Inherits="MITool.Scripts" %> 

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server"> 
</asp:Content> 
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 
    <script type="text/javascript" language="javascript"> 
     var script = ''; 

     function ShowScriptModal() { 
      $('#overlay').css({ width: $(document).width(), height: $(document).height(), 'display': 'block' }).animate({ opacity: 0.85 }, 0, function() { $('#scriptModal').show(); }); 
     } 

     function ScriptInputKeypress(e) { 
      if (e.keyCode == 13) { 
       ScriptInput(); 
      } 
     } 

     function ScriptInput() { 
      var txtInput = document.getElementById("txtInput"); 
      var input = txtInput.value; 
      var hiddenInput = document.getElementById("hiddenInput"); 

      if (input == '') 
       return; 

      hiddenInput.value = input; 

      txtInput.value = ''; 
     } 

     function CheckForNewOutput() { 
      var outputUpdatePanel = document.getElementById("OutputUpdatePanel"); 
      var pageScript = outputUpdatePanel.innerHTML; 
      if (script != pageScript) { 
       script = pageScript; 
       ScrollToBottom(); 
      } 
      setTimeout("CheckForNewOutput()", 100); 
     } 

     function ScrollToBottom() { 
      $('#OutputPanel').scrollTop($('#OutputUpdatePanel').height()); 
     } 
    </script> 
    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" EnablePartialRendering="true" LoadScriptsBeforeUI="true" /> 
    <div id="scriptModal"> 
     <div id="ScriptInputOutput"> 
      <asp:Panel ID="OutputPanel" runat="server" Width="700" Height="250" ScrollBars="Vertical" 
       Style="margin: 10px auto; border: 1px solid #CCC; padding: 5px;" ClientIDMode="Static"> 
       <controls:ScriptOutput ID="ScriptOutputControl" runat="server" /> 
      </asp:Panel> 
      <asp:Panel ID="InputPanel" runat="server" DefaultButton="btnScriptInput" > 
       <asp:TextBox ID="txtInput" runat="server" ClientIDMode="Static" onkeypress="ScriptInputKeypress(event)" /> 
       <asp:HiddenField ID="hiddenInput" runat="server" ClientIDMode="Static" /> 
       <asp:Button ID="btnScriptInput" runat="server" Text="Script Input" ClientIDMode="Static" OnClick="btnScriptInput_Click" style="display:none" />   
       <asp:Button ID="btnExit" runat="server" CssClass="floatRight" Text="Exit" OnClick="btnExit_Click" /> 
      </asp:Panel> 
     </div> 
    </div> 
    <asp:Literal ID="litScript" runat="server" /> 
    <ul id="breadcrumb"> 
     <li><a href="/dashboard.aspx">Main page</a> &gt;</li> 
     <li class="current">Scripts</li> 
    </ul> 
    <div class="content"> 
     <h2> 
      <asp:Label ID="lblHeader" runat="server" Text="Scripts" /></h2> 
     <div class="clear"> 
     </div> 
     <div class="table-content"> 
      <asp:Label ID="lblMessage" runat="server" CssClass="redMessage" /> 
      <asp:Repeater ID="rptScripts" runat="server" OnItemCommand="rptScripts_ItemCommand"> 
       <HeaderTemplate> 
        <table class="table" cellpadding="0" cellspacing="0"> 
         <tr> 
          <th> 
           ID 
          </th> 
          <th> 
           Name 
          </th> 
          <th> 
           Location 
          </th> 
          <th> 
          </th> 
         </tr> 
       </HeaderTemplate> 
       <ItemTemplate> 
        <tr> 
         <td> 
          <%# Eval("ScriptId") %> 
         </td> 
         <td> 
          <%# Eval("Name") %> 
         </td> 
         <td> 
          <%# Eval("Path") %> 
         </td> 
         <td> 
          <asp:LinkButton ID="btnRunScript" runat="server" Text="Run" CommandName="Run" CommandArgument='<%# Eval("ScriptId") %>' /> 
         </td> 
        </tr> 
       </ItemTemplate> 
       <FooterTemplate> 
        </table> 
       </FooterTemplate> 
      </asp:Repeater> 
      <div> 
      </div> 
     </div> 
    </div> 
    <script type="text/javascript" language="javascript"> 
     CheckForNewOutput(); 
    </script> 
</asp:Content> 

// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======// 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using MITool.Data.ScriptManager; 
using System.Diagnostics; 
using System.IO; 
using System.Web.Security; 
using System.Web.Services; 
using System.Collections.Concurrent; 
using System.Threading; 

namespace MITool 
{ 
    public partial class Scripts : System.Web.UI.Page 
    { 
     ConcurrentQueue<char> ScriptOutputQueue 
     { 
      get 
      { 
       return (ConcurrentQueue<char>)Session["ScriptOutputQueue"]; 
      } 
      set 
      { 
       Session["ScriptOutputQueue"] = value; 
      } 
     } 
     Process CurrentProcess 
     { 
      get 
      { 
       return (Process)Session["CurrentProcess"]; 
      } 
      set 
      { 
       Session["CurrentProcess"] = value; 
      } 
     } 
     bool ScriptRunning 
     { 
      get 
      { 
       if (CurrentProcess == null) 
        return false; 
       if (!CurrentProcess.HasExited || !CurrentProcess.StandardOutput.EndOfStream) 
        return true; 
       return false; 
      } 
     } 
     bool OutputProcessing 
     { 
      get 
      { 
       if (ScriptOutputQueue != null && ScriptOutputQueue.Count != 0) 
        return true; 
       return false; 
      } 
     } 

     Thread OutputThread; 

     void Reset() 
     { 
      ScriptOutputControl.SetTimerEnabled(false); 
      ScriptOutputControl.ClearOutputText(); 
      if (CurrentProcess != null && !CurrentProcess.HasExited) 
       CurrentProcess.Kill(); 
      if (OutputThread != null && OutputThread.IsAlive) 
       OutputThread.Abort(); 
      ScriptOutputQueue = new ConcurrentQueue<char>(); 

      litScript.Text = string.Empty; 
      txtInput.Text = string.Empty; 
     } 

     void Page_Load(object sender, EventArgs e) 
     { 
      if (IsPostBack) return; 

      Reset(); 

      FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity; 
      string role = id.Ticket.UserData; 

      ScriptData data = new ScriptData(); 
      List<Script> scripts = data.GetScriptsByRole(role); 
      rptScripts.DataSource = scripts; 
      rptScripts.DataBind(); 
     } 

     protected void rptScripts_ItemCommand(object source, RepeaterCommandEventArgs e) 
     { 
      switch (e.CommandName) 
      { 
       case "Run": StartScript(Int32.Parse(e.CommandArgument.ToString())); 
        break; 
      } 
     } 

     void StartScript(int id) 
     { 
      if (ScriptRunning || OutputProcessing) 
       return; 

      Reset(); 

      ScriptData data = new ScriptData(); 
      History history = new History() 
      { 
       UserName = HttpContext.Current.User.Identity.Name, 
       BatchFileId = id, 
       DateRun = DateTime.Now 
      }; 
      data.CreateHistory(history);    

      Script script = data.GetScript(id); 

      ProcessStartInfo psi = new ProcessStartInfo() 
      { 
       FileName = script.Path, 
       RedirectStandardOutput = true, 
       RedirectStandardInput = true, 
       UseShellExecute = false, 
       CreateNoWindow = true 
      }; 

      CurrentProcess = new Process(); 
      CurrentProcess.StartInfo = psi; 

      OutputThread = new Thread(Output); 

      CurrentProcess.Start(); 
      OutputThread.Start(); 

      ScriptOutputControl.SetTimerEnabled(true); 

      litScript.Text = "<script type=\"text/javascript\" language=\"javascript\">ShowScriptModal();</script>"; 

      SetFocus("txtInput"); 
     } 

     void Output() 
     { 
      while (ScriptRunning) 
      { 
       var x = CurrentProcess.StandardOutput.Read(); 
       if (x != -1) 
        ScriptOutputQueue.Enqueue((char)x); 
      } 
     } 

     public void btnScriptInput_Click(object sender, EventArgs e) 
     { 
      string input = hiddenInput.Value.ToString(); 

      ScriptOutputControl.Input(input); 

      foreach (char x in input.ToArray()) 
      { 
       if (CurrentProcess != null && !CurrentProcess.HasExited) 
       { 
        CurrentProcess.StandardInput.Write(x); 
       } 
       Thread.Sleep(1); 
      } 
     } 

     protected void btnExit_Click(object sender, EventArgs e) 
     { 
      Reset(); 
     } 
    } 
} 

// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======// 

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ScriptOutput.ascx.cs" 
    Inherits="MITool.Controls.ScriptOutput" %> 
<asp:Label ID="lblStats" runat="server" Style="color: Red" /> 
<br /> 
<asp:UpdatePanel ID="OutputUpdatePanel" runat="server" ClientIDMode="Static"> 
    <Triggers> 
     <asp:AsyncPostBackTrigger ControlID="UpdateTimer" EventName="Tick" /> 
     <asp:AsyncPostBackTrigger ControlID="btnScriptInput" EventName="Click" /> 
    </Triggers> 
    <ContentTemplate> 
     <asp:Literal ID="litOutput" runat="server" /> 
    </ContentTemplate> 
</asp:UpdatePanel> 
<asp:Timer ID="UpdateTimer" Interval="100" runat="server" OnTick="UpdateTimer_Tick" Enabled="false" /> 

// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======// 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Collections.Concurrent; 
using System.Diagnostics; 

namespace MITool.Controls 
{ 
    public partial class ScriptOutput : System.Web.UI.UserControl 
    { 
     string Output 
     { 
      get 
      { 
       if (Session["Output"] != null) 
        return Session["Output"].ToString(); 
       return string.Empty; 
      } 
      set 
      { 
       Session["Output"] = value; 
      } 
     } 

     ConcurrentQueue<char> ScriptOutputQueue 
     { 
      get 
      { 
       return (ConcurrentQueue<char>)Session["ScriptOutputQueue"]; 
      } 
      set 
      { 
       Session["ScriptOutputQueue"] = value; 
      } 
     } 
     Process CurrentProcess 
     { 
      get 
      { 
       return (Process)Session["CurrentProcess"]; 
      } 
      set 
      { 
       Session["CurrentProcess"] = value; 
      } 
     } 
     bool ScriptRunning 
     { 
      get 
      { 
       if (CurrentProcess == null) 
        return false; 
       if (!CurrentProcess.HasExited || CurrentProcess.StandardOutput.Peek() != -1) 
        return true; 
       return false; 
      } 
     } 
     bool OutputProcessing 
     { 
      get 
      { 
       if (ScriptOutputQueue != null && ScriptOutputQueue.Count != 0) 
        return true; 
       return false; 
      } 
     } 

     public void SetTimerEnabled(bool enabled) 
     { 
      UpdateTimer.Enabled = enabled; 
     } 
     public void ClearOutputText() 
     { 
      Output = string.Empty; 
      litOutput.Text = Output; 
     } 

     protected void UpdateTimer_Tick(object sender, EventArgs e) 
     { 
      ProcessOutput(); 

      if (!ScriptRunning && !OutputProcessing) 
      { 
       UpdateTimer.Enabled = false; 

       Output += "<br />// SCRIPT END //<br />"; 
       litOutput.Text = Output; 
      } 
     } 

     public void Input(string s) 
     { 
      Output += "<br />// " + s + "<br />"; 
     } 

     void ProcessOutput() 
     { 
      string s = string.Empty; 

      while (ScriptOutputQueue != null && ScriptOutputQueue.Any()) 
      { 
       char x; 
       if (ScriptOutputQueue.TryDequeue(out x)) 
       { 
        s += x; 
       } 
      } 

      if (s != string.Empty) 
      { 
       s = Server.HtmlEncode(s); 
       s = s.Replace("\r\n", "<br />"); 

       Output += s; 
      } 

      litOutput.Text = Output; 
     } 
    } 
} 
0

刚刚检查,我注意到暂停不会返回到下一行文本,直到您按下键。这可能是为什么它不显示,因为你的代码正在寻找线返回。 而不是使用ReadLine(),试着看看是否有一个会显示所有打印的字符。 (^应该给你里面有什么事情的更多的实时视图解决您的问题)

+0

不幸的是解决方案。我的主应用程序全部都是异步完成的,并且不断输出数据到屏幕上,直到没有剩余的数据,并且在这种情况下,在我按下回车键之前,它没有剩余数据输出。 如果我用“randomText”替换了Console.ReadLine(),它不会有任何区别。我正在做的是“按任意键继续” ReadLine()正在寻找用户输入,而不是处理输出这是这里的问题。 – Owen

0

我还以为你需要将你的:

string inputText = Console.ReadLine();    
proc.StandardInput.WriteLine(inputText); 

到OutputDataReceived处理程序。

在主

然后,调用proc.WaitForExit()与一点点运气(我没有测试过这一点)以下应该发生:

  • PROC的输出缓冲器刷新
  • 您OutputDataReceived处理程序执行
  • Console.Write与PROC的stdout
  • Console.Read和输入发送给PROC的标准输入
  • PROC退出
+0

不是我不认为的解决方案。我对我的输入没有任何问题,但我认为我已经将一些人与我的临时输入法混淆了。删除这两行:string inputText = Console.ReadLine(); proc.StandardInput.WriteLine(inputText的);并更改问题:为什么“按任意键继续...”没有显示在屏幕上。 – Owen

相关问题