im_*_*chc 8 c# stdin stdout process wsh
vbscript的要点是充当REPL或命令提示符/ bash环境,它简化为仅重印用户输入
因此,换句话说,cscript进程应保持活动状态,每次通过的用户输入应仅发送给该进程。
并且这也意味着应该为每次通过保留脚本的内部状态(一次=每次单击C#winform中的“发送”按钮,或者在vbscript的上下文中,一次=每次^ Z输入)。
例如,如果要修改vbscript以演示状态保持行为,则可以进行以下修改:
dim wsh,stmt,l...附加: dim passcnt : passcnt=1wsh.Echo("Enter lines of strings, press ctrl-z...,将最后一个右括号替换为& " (pass #" & passcnt & ")")wsh.Echo("End output")附加代码: passcnt = passcnt + 1运行vbscript控制台将显示通过次数在每次通过时递增。
- 只要上述条件仍然成立,就可以以任何方式修改C#winform。
- 尝试观察脚本的作用
cscript ask_SO.vbs,这应该使事情足够清楚
我认为这是我能够做到的最明确的目标。
我想使用System.Diagnostics.Process的stdout / stdin重定向将输入文本输入以下VBScript。
vbscript的作用在于,它允许用户向控制台输入多行字符串,并且当输入^ z字符时,脚本会将所有内容直接输出到控制台:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
Enter lines of strings, press ctrl-z when you are done (ctrl-c to quit):
I come with no wrapping or pretty pink bows.
got line
I am who I am, from my head to my toes.
got line
I tend to get loud when speaking my mind.
got line
Even a little crazy some of the time.
got line
I'm not a size 5 and don't care to be.
got line
You can be you and I can be me.
got line
got line
Source: https://www.familyfriendpoems.com/poem/be-proud-of-who-you-are
got line
^Z
=====================================
You have entered:
I come with no wrapping or pretty pink bows.
I am who I am, from my head to my toes.
I tend to get loud when speaking my mind.
Even a little crazy some of the time.
I'm not a size 5 and don't care to be.
You can be you and I can be me.
Source: https://www.familyfriendpoems.com/poem/be-proud-of-who-you-are
End output
Enter lines of strings, press ctrl-z when you are done (ctrl-c to quit):
Run Code Online (Sandbox Code Playgroud)
之后,用户可以输入另一段文本并重复该过程。
这是脚本代码:
dim wsh,stmt,l : set wsh = WScript
do
wsh.Echo("Enter lines of strings, press ctrl-z when you are done (ctrl-c to quit):")
'stmt=wsh.StdIn.ReadAll()
do
l=wsh.StdIn.ReadLine()
wsh.echo("got line")
stmt = stmt & l & vbcrlf
loop while (not wsh.StdIn.AtEndOfStream)
wsh.Echo("=====================================")
wsh.Echo("You have entered:")
wsh.Echo(stmt)
wsh.Echo("End output")
loop
Run Code Online (Sandbox Code Playgroud)
这是调用脚本的方法:
cscript ask_SO.vbs
Run Code Online (Sandbox Code Playgroud)
我出现了以下C#代码(项目类型设置为Console Application而不是Windows Forms):
public class frmPostSample : Form
{
Process proc_cscr;
StreamWriter sw;
public frmPostSample()
{
InitializeComponent2();
}
#region Copied from generated code
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent2()
{
this.txt_lines = new System.Windows.Forms.TextBox();
this.Btn_Send = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txt_lines2
//
this.txt_lines.Location = new System.Drawing.Point(41, 75);
this.txt_lines.Multiline = true;
this.txt_lines.Name = "txt_lines2";
this.txt_lines.Size = new System.Drawing.Size(689, 298);
this.txt_lines.TabIndex = 0;
//
// Btn_Send2
//
this.Btn_Send.Location = new System.Drawing.Point(695, 410);
this.Btn_Send.Name = "Btn_Send2";
this.Btn_Send.Size = new System.Drawing.Size(75, 23);
this.Btn_Send.TabIndex = 1;
this.Btn_Send.Text = "&Send";
this.Btn_Send.UseVisualStyleBackColor = true;
this.Btn_Send.Click += new System.EventHandler(this.Btn_Send_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.Btn_Send);
this.Controls.Add(this.txt_lines);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.TextBox txt_lines;
private System.Windows.Forms.Button Btn_Send;
#endregion
private void Btn_Send_Click(object sender, EventArgs e)
{
if (proc_cscr == null)
{
if (!File.Exists("ask_SO.vbs"))
{
MessageBox.Show("Script file not exist");
return;
}
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cscript";
startInfo.Arguments = "//nologo ask_SO.vbs";
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
proc_cscr = new Process();
proc_cscr.StartInfo = startInfo;
proc_cscr.Start();
sw = proc_cscr.StandardInput;
}
OutPrint();
foreach (var vbsline in txt_lines.Lines)
{
sw.WriteLine(vbsline); // <-------- SW WRITELINE
sw.Flush();
OutPrint();
}
//sw.Flush();
sw.Close();
while (true)
{
var s2 = proc_cscr.StandardOutput.ReadLineAsync();
s2.Wait();
Console.WriteLine(s2.Result);
if (proc_cscr.StandardOutput.Peek() == -1) break;
}
}
private void OutPrint()
{
string l;
while (proc_cscr.StandardOutput.Peek() != -1)
{
l = proc_cscr.StandardOutput.ReadLine();
Console.WriteLine(l);
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行该程序,并且如果您已将项目类型正确设置为“ Console Application”,则应显示一个控制台窗口和一个GUI窗口。您只需将文本粘贴到文本输入区域,然后按发送,然后在控制台窗口中观察结果。
但是,C#表单的行为与直接运行脚本不同cscript ask_SO.vbs:
SW WRITELINE-我知道这是因为我已经关闭了stdin流,但是否则我无法脚本前进...\ask_SO.vbs(8, 9) Microsoft VBScript runtime error: Input past end of file。SW WRITELINE),立即没有显示“获取行”回显。我已经在网上搜索以找到解决方案,但是大多数材料仅显示输入而没有使用^ z字符,换句话说,仅接受一次输入。
您可以在此处下载C#Visual Studio解决方案(包括vbscript-您只需在Visual Studio 2019中加载该解决方案并按F5键即可运行)。
编码从我得到了proc_cscr.StandardOutput.CurrentEncoding.BodyName和proc_cscr.StandardInput.Encoding.BodyName是big5,它是一个DBCSCodePageEncoding,用于编码字符的中国。
当我尝试将答案中提到的建议写入(char)26到stdin流中时,我意识到需要提及这一点。由于Encoding.GetEncoding("big5").GetBytes(new char[]{(char)26})仅返回一个字节(对于unicode:,为两个字节{byte[2]} [0]: 26 [1]: 0),我做了一个sw.Write((char)26);,并添加了一个sw.flush()。仍然没有用。
小智 1
我不认为这是可能做到的。
你的观点3:
C# 代码将行输入写入标准输入后,不会立即显示“got line”回显
这是因为您已重定向输出 ( startInfo.RedirectStandardOutput = true)。如果您重定向它,您写入的所有内容都会进入StandardOutput流,并且您必须手动读取它。因此,只要不重定向输出,您的got line消息就会立即生效。如果输出未重定向,则无法使用StandardOutput属性(但无论如何您都不需要它)。
剩下的就比较困难了。问题是,似乎没有办法发送流结束,因为这就是停止你的内部循环的原因vbs。当您完成流时,流就会结束 - 从技术上讲,当您关闭流或完成进程时。值 26 的字符表示为流的结尾(Ctrl + Z) 某处。但它在这里不起作用(我尝试过sw.Write(Convert.ToChar(26))。
我不知道是否可能(我不知道vbs),但也许你可以改变你的逻辑,而不检查流结束。它可以按字节(字符)读取并检查特定字符(例如 char(26))以跳出内部循环。