【问题标题】:WinForm App running a console - Disabling minimize/maximize/close buttons on console issue运行控制台的 WinForm 应用程序 - 在控制台问题上禁用最小化/最大化/关闭按钮
【发布时间】:2011-11-10 18:41:08
【问题描述】:

我正在编写一个可以启动控制台进行调试的 Windows 窗体应用程序。我想禁用控制台的关闭按钮,以便无法通过控制台的关闭按钮关闭 windows 窗体应用程序。我已经构建了测试代码框架并且它可以工作。代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Diagnostics;
using System.Runtime.InteropServices;

namespace bsa_working
{
    public partial class Form1 : Form
    {
        static bool console_on = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (ViewConsole.Checked)
            {
                Win32.AllocConsole();
                ConsoleProperties.ConsoleMain();

                // Set console flag to true
                console_on = true;  // will be used later
            }
            else
                Win32.FreeConsole();
        }
    }

    public class Win32
    {
        [DllImport("kernel32.dll")]
        public static extern Boolean AllocConsole();
        [DllImport("kernel32.dll")]
        public static extern Boolean FreeConsole();
    }

    public class ConsoleProperties
    {
        [DllImport("user32.dll")]
        static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        static extern IntPtr RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

        internal const uint SC_CLOSE = 0xF060;
        internal const uint MF_GRAYED = 0x00000001;
        internal const uint MF_BYCOMMAND = 0x00000000;

        public static void ConsoleMain()
        {
            IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle;
            IntPtr hSystemMenu = GetSystemMenu(hMenu, false);

            EnableMenuItem(hSystemMenu, SC_CLOSE, MF_GRAYED);
            RemoveMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND);

            // Set console title
            Console.Title = "Test Console";

            // Set console surface foreground and background color
            Console.BackgroundColor = ConsoleColor.DarkBlue;
            Console.ForegroundColor = ConsoleColor.White;
            Console.Clear();
        }
    }
}

代码运行良好,除了:

  1. 第一次编译和运行代码时,控制台上的 X 不是灰显的,但它在 Windows 窗体应用程序中灰显。但是,当代码关闭并再次运行时,代码会正常工作;也就是说,控制台上的 X 是灰色的,Windows 窗体应用程序应该是这样的。任何想法为什么以及如何解决这个问题?

  2. 有时控制台会出现在 win 表单后面。有什么方法可以强制控制台始终排在首位?

顺便说一句,有什么方法可以将控制台固定到 WinForm 上的特定位置?应用程序?我可以设置它的大小,所以如果我可以将它固定在特定位置,我可以在表单上为其创建一个位置。

【问题讨论】:

  • 你为什么不在你的应用程序中简单地有一个 Windows 窗体,例如另一个窗体或控件在启用多行的文本框中,然后你将控制台的标准输出重定向到这个控件,而不需要所有这些魔法你正在尝试做什么?
  • 因为控制台主要是调试用的,我不一定想一直看。
  • @Zeos6:我在一些应用程序中做同样的事情。我真的很喜欢它的工作方式。而不是调用Process.GetCurrentProcess().MainWindowHandle(这可能导致窗体和控制台窗口之间的竞争),在调用 AllocConsole() 之后,通过调用 GetConsoleWindow() 获取控制台窗口句柄
  • 我认为 GetConsoleWindow() 只适用于 XP,我希望它即使在非 XP OS 环境中也能工作。
  • 我无法在我的系统(Win7 64 位)上进行复制。这确实支持了 Boo 关于比赛条件的建议。虽然我不明白为什么控制台会成为进程的主窗口。

标签: c# winforms winforms-interop


【解决方案1】:

要完成这项工作,您需要将IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle; 更改为使用控制台窗口的窗口句柄(您可以通过调用GetConsoleWindow() 获得)。

要使其显示在顶部,您可以使用例如SetForegroundWindow with the Console Window Handle

关于固定,我真的不确定这是否可能。

【讨论】:

  • 感谢您的建议。我同意比赛条件,我也认为固定可能是不行的。我只是想问一下,以防我遗漏了什么。我对 GetConsoleWindow() 唯一的反对是它只适用于 Win 2000 和 XP。如果您尝试解决方法(存在),那么如果您有多个 comsoles,则会出现问题,因为解决方法只能找到 z 顺序中最近的一个。我希望避免使用 GetConsoleWindow()。
  • @Zeos6 最多只有一个控制台与您的应用程序关联(请参阅msdn.microsoft.com/en-us/library/windows/desktop/…),所以这不会是一个问题......而且GetConsoleWindow 也适用于更高版本的 Windows!请不要忘记投票/标记为已接受任何有帮助的答案(请参阅meta.stackexchange.com/questions/5234/…
  • 谢谢叶海亚。我会标记答案。我同意你的看法,只有一个带有 alloc 的控制台。我想我的困惑是,如果我有多个应用程序并且每个应用程序都创建一个控制台,那么我会得到哪个控制台?据我了解,您将以 z 顺序获得最近的控制台,不一定是链接到您想要的应用程序的控制台。另外,感谢 SetForeGroundWindow。无论如何,我可能需要使用 GetConsoleWindow(),尽管我不想这样做。
  • @Zeos6 您绝对不会得到“最近的”,但根据 MS 的说法,与您的应用程序相关联的控制台(请参阅 msdn.microsoft.com/en-us/library/windows/desktop/…)...此 API 调用仅考虑进程上下文而不是任何屏幕坐标。
  • 太棒了!非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-02-19
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 2015-05-29
相关资源
最近更新 更多