繁体   English   中英

当用户单击控制台窗口时,代码停止执行

[英]Code stops executing when a user clicks on the console window

我有一个控制台应用程序,无需用户交互即可执行我的代码。 如果用户有意或无意地在控制台窗口内单击,则所有执行都将停止。

这与从控制台窗口复制文本有关。 应用程序再次开始执行的唯一方法是,如果用户选择文本,然后右键单击控制台窗口,将其复制到剪贴板。

要查看此操作,请创建一个控制台应用程序并添加以下代码。

class Program
{
    static void Main(string[] args)
    {
        var task = Task.Run(async () =>
        {
            int i = 0;
            while (true)
            {
                Console.WriteLine(i++);
                await Task.Delay(1000);
            }
        });
        Console.ReadLine();
    }
}

单击控制台窗口时,任务线程停止执行。 这根本不是理想的行为,我想在我的控制台应用程序中防止这种情况发生。

我怎么能阻止这个? 据我所知,控制台窗口上的所有属性/事件都与控制此行为无关。

如你所见,当我在窗口内点击时出现光标。 当我按任意键 - 光标消失,应用程序继续工作 暂停的应用程序

如果在控制台窗口中启用了“快速编辑模式”,则会发生这种情 如果右键单击标题栏并选择“属性”,然后选择“选项”选项卡,则可以检查是否启用了“快速编辑模式”。 如果禁用“快速编辑模式”,则单击窗口时滚动不会停止。

滚动停止的原因是因为在窗口中单击鼠标用于选择文本。

您可以在程序中禁用控制台上的“快速编辑模式”,但这样做需要调用GetConsoleModeSetConsoleMode API函数。 这是你如何做到的:

[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetConsoleWindow();

[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool GetConsoleMode(
    IntPtr hConsoleHandle,
    out int lpMode);

[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool SetConsoleMode(
    IntPtr hConsoleHandle,
    int ioMode);

/// <summary>
/// This flag enables the user to use the mouse to select and edit text. To enable
/// this option, you must also set the ExtendedFlags flag.
/// </summary>
const int QuickEditMode = 64;

// ExtendedFlags must be combined with
// InsertMode and QuickEditMode when setting
/// <summary>
/// ExtendedFlags must be enabled in order to enable InsertMode or QuickEditMode.
/// </summary>
const int ExtendedFlags = 128;

void DisableQuickEdit()
{
    IntPtr conHandle = GetConsoleWindow();
    int mode;

    if (!GetConsoleMode(conHandle, out mode))
    {
        // error getting the console mode. Exit.
        return;
    }

    mode = mode & ~(QuickEditMode | ExtendedFlags);

    if (!SetConsoleMode(conHandle, mode))
    {
        // error setting console mode.
    }
}

void EnableQuickEdit()
{
    IntPtr conHandle = GetConsoleWindow();
    int mode;

    if (!GetConsoleMode(conHandle, out mode))
    {
        // error getting the console mode. Exit.
        return;
    }

    mode = mode | (QuickEditMode | ExtendedFlags);

    if (!SetConsoleMode(conHandle, mode))
    {
        // error setting console mode.
    }
}

如果沿着这条路走下去,那么在程序启动时保存原始控制台模式设置可能是个好主意,并在程序退出时恢复它。 所以在启动时:

GetConsoleMode(GetConsoleWindow(), ref saveConsoleMode);

当你的程序终止时:

SetConsoleMode(GetConsoleWindow(), saveConsoleMode);

当然,有适当的错误处理。 如果对GetConsoleMode的调用失败,则不希望恢复控制台模式。

我刚刚看到OP的问题评论中的这个答案包含了我自己发现的内容。 我会保留我的答案,因为人们可能看不到它,就像我一样,它会为他们节省很多时间。


吉姆的回答对我不起作用,我无法弄明白为什么。 我挖掘并找到了一个有效的解决方案,所以我将分享我的发现,希望能帮助处于相同情况的人。

问题是我从GetConsoleWindow()获得的句柄,它给出了Win32错误(0x6),当我尝试使用它时句柄无效。 SetConsoleMode()的调用什么也没做。

为了得到一个工作句柄,我使用GetStdHandle()来获取控制台的Input句柄。 将此添加到Jim的代码中:

public const int STD_INPUT_HANDLE = -10;

[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);

然后更换GetConsoleWindow()GetStdHandle(STD_INPUT_HANDLE)DisableQuickEdit()EnableQuickEdit()在吉姆的代码。

调用DisableQuickEdit() ,在控制台中禁用选择。

谢谢吉姆!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM