Код перестает выполняться, когда пользователь нажимает на окно консоли
У меня есть консольное приложение, которое выполняет мой код без вмешательства пользователя. Если пользователь щелкает в окне консоли, намеренно или случайно, все выполнение останавливается.
Это как-то связано с копированием текста в окне консоли. Единственный способ для приложения, чтобы начать выполнение снова, если пользователь выбирает текст, а затем щелкните правой кнопкой мыши на окне консоли, копируя его в буфер обмена.
чтобы увидеть это в действии, создать консоль применение и добавить следующий код.
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();
}
}
при нажатии на окно консоли поток задач прекращает выполнение. Это нежелательное поведение вообще, и я хочу предотвратить это в моем консольном приложении.
Как я могу предотвратить это? Насколько я вижу, ни одно из свойств/событий в окне консоли не имеет никакого отношения к управлению этим поведением.
Как вы можете видеть, когда я щелкните в окне появляется курсор. Когда я нажмите любую клавишу-курсор ушел, и приложение продолжит работу
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()
, выбор в консоли отключен.
Спасибо Джим !