如果从命令行启动,则输出到命令行

Yes*_*ke. 6 command-line .net-2.0

我正在编写一个可以作为标准WinForms应用程序启动的应用程序,也可以从命令行以无人值守模式启动.该应用程序是使用VS 2k5标准WinForms模板构建的.

当从命令行执行应用程序时,我希望它输出可由执行应用程序的脚本捕获的信息.当我直接从Console.WriteLine()执行此操作时,输出不会出现,尽管它可以通过管道传输到文件来捕获.

另一方面,我可以通过在kernel32上对AllocConsole()执行P/Invoke来强制应用程序弹出第二个控制台.但这不是我想要的.我希望输出出现在调用应用程序的同一窗口中.

这是允许我从命令行弹出控制台的显着代码:

<STAThread()> Public Shared Sub Main()

    If My.Application.CommandLineArgs.Count = 0 Then
        Dim frm As New ISECMMParamUtilForm()
        frm.ShowDialog()
    Else
        Try
            ConsoleControl.AllocConsole()
            Dim exMan As New UnattendedExecutionManager(ConvertArgs())
            IsInConsoleMode = True
            OutputMessage("Application started.")
            If Not exMan.SetSettings() Then
                OutputMessage("Execution failed.")
            End If
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        Finally
            ConsoleControl.FreeConsole()
        End Try

    End If

End Sub

Public Shared Sub OutputMessage(ByVal msg As String, Optional ByVal isError As Boolean = False)
    Trace.WriteLine(msg)
    If IsInConsoleMode Then
        Console.WriteLine(msg)
    End If

    If isError Then
        EventLog.WriteEntry("ISE CMM Param Util", msg, EventLogEntryType.Error)
    Else
        EventLog.WriteEntry("ISE CMM Param Util", msg, EventLogEntryType.Information)
    End If

End Sub
Run Code Online (Sandbox Code Playgroud)

Mic*_*urr 11

Raymond Chen最近发布了一篇关于此问题的简短文章(问题发布于SO之后一个月).

如何编写可以作为控制台或GUI应用程序运行的程序?

你不能,但你可以尝试假装它.

每个PE应用程序在其标头中包含一个字段,用于指定在其下运行的子系统.您可以说 IMAGE_SUBSYSTEM_WINDOWS_GUI将自己标记为Windows GUI应用程序,或者您可以说 IMAGE_SUBSYSTEM_WINDOWS_CUI您是一个控制台应用程序.如果您是GUI应用程序,那么程序将在没有控制台的情况下运行.

子系统确定内核如何为程序准备执行环境.如果程序在控制台子系统中标记为正在运行,则内核将程序的控制台连接到其父控制台,如果父级没有控制台,则创建新控制台.(这是一个不完整的描述,但细节与讨论无关.)另一方面,如果程序被标记为作为GUI应用程序运行,那么内核将在没有任何控制台的情况下运行程序.

在那篇文章中,他指出了Junfeng Zhang的另一篇文章,讨论了几个程序(Visual Studio和ildasm)如何实现这种行为:

如何将应用程序作为GUI和控制台应用程序?

在VisualStudio案例中,实际上有两个二进制文件:devenv.com和devenv.exe.Devenv.com是一款控制台应用.Devenv.exe是一个GUI应用程序.当您键入devenv时,由于Win32探测规则,会执行devenv.com.如果没有输入,devenv.com将启动devenv.exe,并退出.如果有输入,devenv.com会将它们作为普通的控制台应用程序处理.

在ildasm的情况下,只有一个二进制文件:ildasm.exe.它首先被编译为GUI应用程序.稍后editbin.exe用于将其标记为控制台子系统.在其主要方法中,它确定是否需要以控制台模式或GUI模式运行.如果需要以GUI模式运行,它会将自身重新启动为GUI应用程序.

在对Raymond Chen的文章的评论中,laonianren将此添加到Junfeng Zhang关于Visual Studio如何工作的简要描述中:

devenv.com是一个通用的控制台模式存根应用程序.当它运行时,它会创建三个管道来重定向控制台的stdin,stdout和stderr.然后它找到自己的名字(通常是devenv.com),用".exe"替换".com"并使用stdin管道的读取端和stdout的写入端启动新的应用程序(即devenv.exe)和stderr管道作为标准手柄.然后它就坐下来等待devenv.exe退出并在控制台和管道之间复制数据.

因此即使devenv.exe是一个gui应用程序,它也可以使用其标准句柄读写"父"控制台.

您可以将devenv.com自己用于myapp.exe,方法是将其重命名为myapp.com.但你不能在实践中因为它属于MS.


Iga*_*ban 2

更新1:

正如迈克尔·伯尔(Michael Burr)的回答中所说,雷蒙德·陈(Raymond Chen)最近发表了一篇关于此的短文。我很高兴看到我的猜测并没有完全错误。

更新0:

免责声明:这个“答案”主要是猜测。我发布它只是因为已经过去了足够的时间来确定没有多少人能够回答这个看似基本的问题。

我认为应用程序是 GUI 还是控制台的“决定”是在编译时而不是在运行时做出的。因此,如果您将应用程序编译为 gui 应用程序,即使您不显示 gui,它仍然是一个 gui 应用程序并且没有控制台。如果您选择将其编译为控制台应用程序,那么在进入 GUI“模式”之前至少您将有一个控制台窗口闪烁。而且我不知道在托管代码中是否可能。

我认为这个问题是根本性的,因为控制台应用程序必须“控制”调用控制台应用程序。它必须在子应用程序的代码运行之前执行此操作。