Код перестает выполняться, когда пользователь нажимает на окно консоли

У меня есть консольное приложение, которое выполняет мой код без вмешательства пользователя. Если пользователь щелкает в окне консоли, намеренно или случайно, все выполнение останавливается.

Это как-то связано с копированием текста в окне консоли. Единственный способ для приложения, чтобы начать выполнение снова, если пользователь выбирает текст, а затем щелкните правой кнопкой мыши на окне консоли, копируя его в буфер обмена.

чтобы увидеть это в действии, создать консоль применение и добавить следующий код.

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

при нажатии на окно консоли поток задач прекращает выполнение. Это нежелательное поведение вообще, и я хочу предотвратить это в моем консольном приложении.

Как я могу предотвратить это? Насколько я вижу, ни одно из свойств/событий в окне консоли не имеет никакого отношения к управлению этим поведением.

Как вы можете видеть, когда я щелкните в окне появляется курсор. Когда я нажмите любую клавишу-курсор ушел, и приложение продолжит работу Paused app

2 ответов


это происходит, если в окне консоли включен режим быстрого редактирования. Если вы щелкните правой кнопкой мыши на строке заголовка и выберите Свойства, Затем выберите вкладку Параметры, вы можете проверить, включен ли режим быстрого редактирования. Если вы отключите режим быстрого редактирования, прокрутка не остановится при нажатии кнопки в окне.

причина остановки прокрутки заключается в том, что щелчок мыши в окне используется для выбора текста.

вы можете отключить режим быстрого редактирования на консоли в программа, но для этого требуется вызвать GetConsoleMode и SetConsoleMode функции 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() чтобы получить ручку ввода для консоли. Добавьте это в код Джима:

public const int STD_INPUT_HANDLE = -10;

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

затем заменить GetConsoleWindow() by GetStdHandle(STD_INPUT_HANDLE) на DisableQuickEdit() и EnableQuickEdit() в коде Джима.

после вызова DisableQuickEdit(), выбор в консоли отключен.

Спасибо Джим !