Почему нельзя прервать вызов ReadConsole?
Dec 29, 2009 · CommentsКонсольПрограммированиеWindows
Представьте, что где-то в коде есть такой кусок:
BOOL Res =
ReadConsole(
GetStdHandle(STD_INPUT_HANDLE),
Buffer,
sizeof(Buffer),
&ReadChars,
NULL);
Теперь, скажем, нам в какой-то момент нужно корректно прервать вызов ReadConsole() (из другого потока). Как это сделать?
Как выясняется, ни CancelIoEx(), ни CancelSynchronousIo() не работают в этом случае. CancelIoEx() возвращает ошибку ERROR_INVALID_HANDLE, а CancelSynchronousIo() - ERROR_OBJECT_NOT_FOUND. Также интересно, то GetStdHandle() возвращает значение “3”, что не очень-то похоже на описатель (handle) ядерного объекта.
Проблема заключается в том, что консольная подсистема обслуживается системным процессом Csrss (в Windows 7 - Conhost). Консольные функции вроде ReadConsole() на самом деле выполняют RPC вызовы в Csrss, вместо обращения в ядро. Соответственно, прервать текущую операцию можно было бы вызвав CancelIoEx() с описателем LPC порта, поверх которого «ходит» RPC. Правда добраться до этого описателя не очень реально. Да и RPC соединение после такого финта ушами может быть потеряно.
Остаются всякие окольные методы. Во-первых, можно насильно завершить поток, читающий консоль. Во-вторых, можно имитировать консольный ввод с помощью WriteConsoleInput(), разблокировав тем самым ReadConsole(). В некоторых случаях можно отказаться от построчного ввода и реализовать ReadConsole() в виде надстройки над ReadConsoleInput(). Хотя этот путь только для настоящих джедаев. В общем, не просто это все…