我的代码以前AllocConsole
是这样使用的:
AllocConsole();
var arg = Console.ReadLine();
// do stuff with arg
它运行良好。但是,我不喜欢这样一个事实,即如果我从控制台启动应用程序(例如MyApp.exe
在 CMD 窗口中运行),它会创建一个新的控制台实例,所以我改为AllocConsole
:
if(!AttachConsole(-1))
AllocConsole();
输出仍然打印到控制台,但如果我点击“输入”,就会发生奇怪的事情。
从图像中可能不太容易看到,但我所做的是运行应用程序。然后它会输出几行关于使用情况的信息,并要求输入(“Action [run|install|uninstall|quit]”)。我写了“运行”并按回车,但控制台将输入指向 CMD,而不是我的应用程序。因此,当我的应用程序仍在运行时,它没有得到任何输入。这有点像在 linux 中运行应用程序&
。
有什么方法可以让我的应用程序从启动它的 CMD 窗口中获取输入?
[编辑] 完整代码:
#region Custom Launching Helpers (for when not launced as a service)
private enum Action
{
Run,
Install,
Uninstall
}
private static string PrintUsage()
{
Console.WriteLine("Usage: <application-name> [run|install|uninstall]");
Console.WriteLine("Use run to run a single itteration of the program.");
Console.WriteLine("Use install to install the service.");
Console.WriteLine("Use uninstall to uninstall the service.");
Console.Write("Action [run|install|uninstall|quit]: ");
return Console.ReadLine();
}
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
private static extern bool FreeConsole();
[DllImport("kernel32.dll")]
private static extern bool SetConsoleTitle(String lpConsoleTitle);
private static void RequireConsole()
{
if (!AttachConsole(-1))
AllocConsole();
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
// Environment.UserInteractive will be true when launced as a normal application
// (for instance by double-clicking, or running form a cmd-prompt).
//
// Services can't run this way, thus we present the user with a menu (if no spesific action
// was passed allong as a startup-parameter) that enables the user either to run a single
// itteration, or to install/uninstall the service.
if (Environment.UserInteractive)
{
try
{
// open a console
// since AssemblyService isn't a console-application, one must be crated explicitly.
RequireConsole();
SetConsoleTitle("AssemblyService 2");
Action action;
// If no command-line arguments are provided, print usage
// and enable the user to input an argument while running.
var arg = args.Length == 0 ? PrintUsage() : args[0];
while (true)
{
switch (arg)
{
case "run":
action = Action.Run;
goto execute;
case "install":
action = Action.Install;
goto execute;
case "uninstall":
action = Action.Uninstall;
goto execute;
case "quit":
return;
default:
// If the argument is invalid, keep asking the user
// untill a valid argument is given.
arg = PrintUsage();
Console.WriteLine("Got arg: {0}", arg);
break;
}
}
execute:
; // empty statement so it compiles
// unimportant, does stuff;
}
finally
{
// Release the console.
Console.WriteLine();
FreeConsole();
}
}
else
{
// Run as service (only in non-interactive session).
//ServiceBase.Run(new AssemblyService());
// rather just exit
}
}
[编辑 2] 我尝试添加以下内容:
var inputHandle = GetStdHandle((int) StdHandle.Stdin);
var safeInputHandle = new SafeFileHandle(inputHandle, true);
var input = new FileStream(safeInputHandle, FileAccess.Read);
Console.SetIn(new StreamReader(input));
它根本没有打印到控制台上(所以我不知道发生了什么)。然后我尝试为 StdOut 和 StdErr 添加设置器:
var outputHandle = GetStdHandle((int) StdHandle.Stdout);
var safeOutputHandle = new SafeFileHandle(outputHandle, true);
var output = new FileStream(safeOutputHandle, FileAccess.Write);
Console.SetOut(new StreamWriter(output));
var errHandle = GetStdHandle((int) StdHandle.Stderr);
var safeErrHandle = new SafeFileHandle(errHandle, true);
var err = new FileStream(safeErrHandle, FileAccess.Write);
Console.SetError(new StreamWriter(err));
仍然没有输出到控制台。
[编辑 3] 启动应用程序
start /wait "AssemblyService 2.exe"
导致创建了一个显示 CMD 提示的新窗口,但仍然不允许我输入应用程序的输入。它也不显示输出。