Dot-Net

在 WPF 視窗中嵌入控制台視窗

  • November 29, 2018

是否可以在 WPF 視窗中嵌入控制台視窗?

作為一點背景知識,起初,我嘗試在 WPF 中從頭開始實現一個控制台視窗,除了一個大問題外,它是成功的——它非常慢。請參閱此處的問題:

Windows WPF 或 Silverlight 中的 VT100 終端仿真

由於這似乎不是一個選項,我轉而考慮在我的 WPF 應用程序中託管一個實際的控制台視窗,我已經學會瞭如何按照此處所述進行操作:

WPF 應用程序沒有輸出到控制台?

這很好,但理想情況下,我希望該控制台視窗看起來像是 WPF 應用程序其餘部分的一部分。我知道使用 WinForms 應用程序是可能的,正如我所看到的那樣,涉及使用 SetParent Win32 API。您可以看到一個範例 .NET 項目,該項目使用將控制台視窗嵌入 shell 的 CommandBar 項目來執行此操作:

http://www.codeproject.com/KB/cs/commandbar.aspx

所以我希望它也可以用 WPF 來完成,但我不知道你會怎麼做。非常感謝您的幫助(另外,如果您對我在 WPF 中從頭開始創建終端視窗的原始問題有任何出色的解決方案,因為這也可以解決我的需求)。

更新:

在 Reed Copsey 的幫助下,我能夠嵌入控制台視窗。但是,當然需要對其進行樣式設置和移動,否則它看起來就像 WPF 視窗中的正常控制台視窗。我需要刪除標題欄和大邊框。做研究我想出瞭如何使用 Win32 API 來做到這一點:

uint style = GetWindowLong(ConsoleManager.ConsoleWindowHandle, GWL_STYLE);
style &= ~(uint)WindowStyles.WS_CAPTION;
style &= ~(uint)WindowStyles.WS_THICKFRAME;
style &= ~(uint)WindowStyles.WS_DLGFRAME;
style &= ~(uint)WindowStyles.WS_POPUP;
SetWindowLong(ConsoleManager.ConsoleWindowHandle, GWL_STYLE, style);
MoveWindow(ConsoleManager.ConsoleWindowHandle, 0, 0, (int)WindowsFormsHost.ActualWidth, (int)WindowsFormsHost.ActualHeight, true);

但是,有一個大問題。出於某種原因,控制台視窗有一個渲染工件。就好像它沒有在左下角和右上角重繪自己。工件的寬度類似於標題欄和粗邊框的寬度,實際上,如果我離開粗邊框,工件的大小會下降。但簡單地重新粉刷它不會有幫助,因為它會重新出現。例如,我可以將視窗從螢幕上移開並再次移回以修復它,但它很快就會自行重新出現:

渲染神器 http://img837.imageshack.us/img837/6241/renderissue.png

**更新 2:**即使我沒有將其作為 WindowsFormsHost 控制項的父級,效果也會發生。重現它所需要做的就是啟動控制台(使用 AllocConsole()),然後使用 SetWindowLong 刪除其標題欄。這是win7機器。

**更新 3:**似乎不支持像這樣與其他視窗“混淆”。假設有標題,控制台視窗會計算其文本區域,所以沒有辦法解決這個問題。我認為在 WPF 中獲得類似控制台行為的唯一選擇是編寫一個自定義 WinForms 控制項,然後將其嵌入到 WPF 中。

您應該能夠使用與您通過重新設置為HwndHost顯示的 Windows 窗體應用程序相同的技術。您甚至可以調整 Windows 窗體程式碼,並將其直接放入WindowsFormsHost控制項。

除了Reed Copsey關於在 WPF 應用程序中嵌入控制台視窗的出色建議之外,另一種非常容易實現的替代策略是簡單地通過 Process 類發出命令並將兩個流重定向到本機 WPF TextBlocks。這是螢幕截圖…

在此處輸入圖像描述

此 WPF 應用程序(連接到“exe”文件的 Windows 資源管理器上下文菜單)執行程序並將結果通過管道傳輸到相應的視窗中。

它旨在幫助您在想要執行控制台實用程序時提供幫助,當您點擊它時,該實用程序會在控制台視窗中快速執行,而您永遠無法看到發生了什麼。它還連接到“csproj”文件以從資源管理器在它們上執行 MSBuild。

關鍵是有時自己做比嘗試託管控制台視窗更容易且更具可擴展性……

這個應用程序的內部使用這個類……

public class ProcessPiper
{
   public string StdOut { get; private set; }
   public string StdErr { get; private set; }
   public string ExMessage { get; set; }
   public void Start(FileInfo exe, string args, Action<ProcessPiper>onComplete)
   {
       ProcessStartInfo psi = new ProcessStartInfo(exe.FullName, args);
       psi.RedirectStandardError = true;
       psi.RedirectStandardOutput = true;
       psi.UseShellExecute = false;
       psi.WorkingDirectory = Path.GetDirectoryName(exe.FullName);
       Task.Factory.StartNew(() =>
           {
               try
               {
                   ExMessage = string.Empty;
                   Process process = new Process();
                   process.StartInfo = psi;
                   process.Start();
                   process.WaitForExit();
                   StdOut = process.StandardOutput.ReadToEnd();
                   StdErr = process.StandardError.ReadToEnd();
                   onComplete(this);
               }
               catch (Exception ex)
               {
                   ExMessage = ex.Message;
               }
           });
   }
}

此類執行命名的“exe”文件並擷取輸出,然後呼叫視圖模型。整個編碼練習大約需要一個小時左右……

Process 類的文件在這裡:http: //msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

引用自:https://stackoverflow.com/questions/3284500