关于c#:当用户单击控制台窗口时,代码停止执行


c#console-application

Code stops executing when a user clicks on the console window

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

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

要查看实际效果,请创建一个控制台应用程序并添加以下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

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

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

我该如何预防?据我所知,控制台窗口上的所有属性/事件都与控制此行为无关。

如您所见,当我在窗口中单击时出现光标。当我按任意键时-光标消失并且应用程序继续工作

 相关讨论

  • 什么是"工作区应用程序"?输出结果如何?产生输出的代码是什么样的?
  • 工作区表示控制台窗口,应用程序输出-处理操作的日志,例如"将文件A移至存储B ..."
  • "医生,我这样做会很痛!""那么,那就不要那样做!"
  • 请停止编辑,我已经重写了,希望可以弄清楚发生了什么。 @ShannonHolsinger的问题是,您不能确切地告诉用户不要意外单击控制台窗口...
  • @ShannonHolsinger哦,真聪明。它的客户的愿望。
  • 我不确定,但是这可能是Windows 10中的新功能。如果您在客户端计算机上运行了长时间运行的控制台应用程序,并且尝试聚焦窗口时,它们意外地停止了执行,则此行为将不是最佳选择。而且没有迹象表明发生了什么,或者如何使应用程序再次运行。
  • 看到这个,可能不是一个确切的例子,但是包含有用的提示。
  • @将感谢您的编辑。就像您说的那样,客户不小心在窗口中单击,并认为该应用程序已冻结。在解释了应用程序刚刚暂停后,客户希望禁用此行为以避免此类情况
  • 我无法复制。您提供的代码可以正常工作。
  • @Mahdi是什么操作系统?我相信此更改是Windows 10的新功能。
  • @Sinatr多数民众赞成在绝对相同的问题。
  • @将Windows 10专业版。
  • @Mahdi还是一样,我绝对可以复制。
  • 您还可以使用System.Diagnostics从另一个进程运行该进程,并完全隐藏控制台窗口。
  • 这是如何通过互操作调用将其关闭stackoverflow.com/q/13656846/1997232


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

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

您可以在程序的控制台上禁用"快速编辑模式",但是需要调用GetConsoleMode和SetConsoleMode API函数。这是您的处理方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

[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.
    }
}

如果沿这条路线走,最好在程序启动时保存原始控制台模式设置,并在程序退出时恢复原来的控制台模式设置。因此,在启动时:

1

GetConsoleMode(GetConsoleWindow(), ref saveConsoleMode);

当程序终止时:

1

SetConsoleMode(GetConsoleWindow(), saveConsoleMode);

当然,通过适当的错误处理。如果对GetConsoleMode的调用失败,则您不想恢复控制台模式。

 相关讨论

  • 这似乎仅在从Visual Studio进行调试时运行。 单独启动程序时,即使以管理员身份运行,也仍然会出现问题。 有任何想法吗?
  • @tayoung-检查每个系统调用返回的错误,并在发生错误时尝试调用Marshal.GetLastWin32Error(),例如:var error = Marshal.GetLastWin32Error(); var errorMessage = new Win32Exception(error).Message;
  • @tayoung:即使独立运行,这也对我有用。 如果您可以用其他方式说明,请通过示例发表问题。
  • @jimMischel Im面临类似问题。 我检查了您的两种解决方案(该解决方案可在您的旧帖子中找到)。 我检查了快速编辑模式的开和关。 (两者都得到相同的结果)。 我还没有找到解决方案。 有什么解决方法,我该如何解决这个错误。


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

吉姆的答案对我不起作用,我不知道为什么。
我四处寻找并找到了可行的解决方案,因此我将分享我的发现,希望能帮助处于相同情况的某人。

问题出在我从GetConsoleWindow()获得的手柄上,它给出了Win32错误(0x6),其中当我尝试使用它时手柄无效。对SetConsoleMode()的调用没有执行任何操作。

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

1
2
3
4

public const int STD_INPUT_HANDLE = -10;

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

然后在Jim的代码中将GetConsoleWindow()替换为DisableQuickEdit()中的GetStdHandle(STD_INPUT_HANDLE)和EnableQuickEdit()。

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

正确代码:

在控制台中:
        private static void OnTimedEvent(object source, ElapsedEventArgs e)
        {
          
            Console.WriteLine(DateTime.Now);
        }
        [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;


        public const int STD_INPUT_HANDLE = -10;

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetStdHandle(int nStdHandle);
        // 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;

    static     void DisableQuickEdit()
        {
            IntPtr conHandle = GetStdHandle(STD_INPUT_HANDLE);
            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.
            }
        }

     static    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.
            }
        }

Main函数调用:   DisableQuickEdit();//禁止快捷编辑

                                  do something

                              EnableQuickEdit()//启用快捷编辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值