代码之家  ›  专栏  ›  技术社区  ›  InfinitiesLoop

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

  •  12
  • InfinitiesLoop  · 技术社区  · 15 年前

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

    作为一个小背景,起初,我尝试在WPF中从头实现一个控制台窗口,这是成功的,除了一个巨大的问题——它非常慢。请参见以下问题:
    VT100 Terminal Emulation in Windows WPF or Silverlight

    因为这似乎不是一个选项,所以我希望在我的WPF应用程序中托管一个实际的控制台窗口,我已经学习了如何按照下面的描述进行操作:

    No output to console from a WPF application?

    这很好,但理想情况下,我希望控制台窗口看起来像是其他WPF应用程序的一部分。我知道使用WinForms应用程序是可能的,正如我所看到的,它涉及到使用setParent win32 API。您可以看到一个.NET项目的例子,它使用这个将控制台窗口嵌入shell的命令栏项目执行此操作:

    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);
    

    但是,有一个大问题。出于某种原因,控制台窗口有一个呈现工件。就好像它没有在左下角和右上角重新粉刷一样。工件的宽度类似于标题栏的宽度和粗边框,事实上,如果我将粗边框保留为工件的大小,则会下降。但简单地重新粉刷不会有帮助,因为它重新出现。例如,我可以将窗口从屏幕上移开,然后再向后移动以修复它,但它很快就会自行重新出现:

    rendering artifact http://img837.imageshack.us/img837/6241/renderissue.png

    更新2: 即使我不将其设置为WindowsFormsHost控件的父级,效果也会发生。要重现它,我只需要启动控制台(使用alloconsole()),然后用setwindowlong删除它的标题栏。这是一台Win7机器。

    更新3: 似乎不支持这样的窗口。控制台窗口计算它的文本区域,假设有标题,所以没有办法解决这个问题。我认为在WPF中获得类似控制台的行为的唯一选择是编写一个自定义winforms控件,然后将其嵌入到WPF中。

    2 回复  |  直到 6 年前
        1
  •  7
  •   Reed Copsey    15 年前

    您应该能够使用与Windows窗体应用程序相同的技术,方法是将其重新命名为 HwndHost . 您甚至可以调整Windows窗体代码,并将其直接放入 WindowsFormsHost 控制。

        2
  •  8
  •   Community CDub    8 年前

    除了 reed copsey 关于在WPF应用程序中嵌入控制台窗口的极好建议之外,另一种非常容易实现的策略是通过process类简单地发出命令,并将两个流重定向到本机WPF文本块中。这是截图…

    此WPF应用程序(连接到“exe”文件的Windows资源管理器上下文菜单)执行程序,并将结果传输到相应的窗口。

    当你想运行一个控制台实用程序时,它被设计成有帮助的,当你点击它时,它会在一个控制台窗口中呼啸而过,你永远看不到发生了什么。它还连接到“csproj”文件,以便从资源管理器对其运行msbuild。

    重点是有时自己做比尝试托管控制台窗口更容易和更可扩展…。

    这个应用程序的内部使用这个类…

    公共类处理器 { 公共字符串stdout get;private set; 公共字符串stderr get;private set; 公共字符串exmessage get;set; public void start(fileinfo exe,string args,action<processpiper>oncomplete) { processStartInfo psi=新的processStartInfo(exe.fullname,args); psi.RedirectStandardError=真; psi.RedirectStandardOutput=真; psi.useShellExecute=假; psi.workingdirectory=path.getdirectoryname(exe.fullname); task.factory.startNew(()=> { 尝试 { exmessage=string.empty; 流程流程=新流程(); process.startinfo=psi; process.start(); process.waitForexit(); stdout=process.standardoutput.readToend(); stderr=process.standardError.readToEnd(); 完成(这个); } catch(异常ex) { ex message=例如message; } (}); } } < /代码>

    此类执行名为“exe”的文件并捕获输出,然后调用视图模型。整个编码训练大约需要一个小时…

    process类的文档如下: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

    对于将控制台窗口嵌入到WPF应用程序中,一个非常容易实现的替代策略是通过进程类简单地发出命令,并将两个流重定向到本机WPF文本块中。这是截图…

    enter image description here

    这个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”的文件并捕获输出,然后调用视图模型。整个编码训练大约要花一个小时…

    流程类的文档如下: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

    推荐文章