2008-12-03 151 views
6

我正在編寫一個應用程序,它可以作爲標準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 

回答

2

更新1:

正如邁克爾·伯爾答說,最近Raymond Chenposted a short article about this。我很高興看到我的猜測並非完全錯誤。

更新0:

免責聲明:本 「答案」 主要是炒作。我只是因爲有足夠的時間來證明沒有多少人能夠回答什麼是一個基本問題而發佈它。

我認爲,如果應用程序是GUI或控制檯的「決定」是在編譯時創建的,而不是在運行時創建的。所以,如果你將應用程序編譯爲GUI應用程序,即使你不顯示GUI,它仍然是一個GUI應用程序,並沒有控制檯。如果您選擇將其編譯爲控制檯應用程序,那麼至少您將有一個控制檯窗口閃爍,然後轉至gui「模式」。我不知道在託管代碼中是否可行。

問題是根本的,我認爲,因爲控制檯應用程序必須對調用控制檯應用程序進行「控制」。而且它必須在子應用程序的代碼運行之前這樣做。

9

雷蒙德陳最近發佈(一個月的問題在這裏張貼在SO)之後很短的文章關於這一點:

How do I write a program that can be run either as a console or a GUI application?

你不能,但你可以嘗試假了。

每個PE應用程序在其標題中包含一個字段 ,該字段指定它被設計爲運行 下的哪個 子系統。你可以說 IMAGE_SUBSYSTEM_WINDOWS_GUI,以紀念自己 作爲一個Windows GUI應用程序, 或者你可以說 IMAGE_SUBSYSTEM_WINDOWS_CUI說 你是一個控制檯應用程序。如果 您是GUI應用程序,那麼 程序將在沒有控制檯的情況下運行。

子系統確定 內核如何爲程序準備執行 環境。如果 程序被標記爲在 控制檯子系統運行,那麼內核 將程序的控制檯連接到 其父的控制檯,創建一個新的 控制檯,如果家長沒有 的控制檯。 (這是一個不完整的 描述,但細節不 相關的討論。)在 另一方面,如果該計劃被標記爲 運行的GUI應用程序,然後 內核將運行程序 無任何控制檯。

在這篇文章中他指出,另一個由俊峯張,討論了幾個方案(Visual Studio和反彙編)如何實現這一行爲:

How to make an application as both GUI and Console application?

在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有這個添加到的Studio如何視覺作品李俊峯張的簡要說明:

devenv.com是一個通用的控制檯模式的stub應用程序。當它運行時,它會創建三個管道來重定向控制檯的stdin,stdout和stderr。然後它找到自己的名稱(通常是devenv.com),用「.exe」替換「.com」,並使用stdin管道的讀取結束和stdout的寫入結束啓動新應用程序(即devenv.exe)和stderr管道作爲標準手柄。然後,它只是坐着等待devenv.exe退出並在控制檯和管道之間複製數據。

因此,儘管devenv.exe是一個GUI應用程序,它可以使用其標準手柄讀寫「父」控制檯。

您可以自己使用devenv.com將myapp.exe重命名爲myapp.com。但你不能在實踐中,因爲它屬於MS。