Почему нельзя прервать вызов ReadConsole?

December 29th, 2009

Представьте, что где-то в коде есть такой кусок:

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(). Хотя этот путь только для настоящих джедаев. В общем, не просто это все…

, ,

  1. Билл Гейтс
    December 29th, 2009 at 23:23 | #1

    Вы уволены.

  2. December 29th, 2009 at 23:30 | #2

    Билл Гейтс :
    Вы уволены.

    :-)

  3. Александр
    December 30th, 2009 at 01:41 | #3

    Иногда у меня создаётся впечатление, что работа с консолью и параметрами командной строки в Windows настолько извращенной сделана осознанно, а вовсе не является результатом последовательных компромиссов и необходимости обратной совместимости, как это видно в других местах API.

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

  4. MaximillianGreat
    December 30th, 2009 at 06:30 | #4

    Билл Гейтс :Вы уволены.

    Э нет, это Вы уволены.

  5. December 30th, 2009 at 07:24 | #5

    Александр :
    а вовсе не является результатом последовательных компромиссов и необходимости обратной совместимости, как это видно в других местах API.

    Необходимость с компромиссах возникает, если изначальный дизайн не соответствует сегодняшним реалиям. Иногда это означает, что критерии изменились и изначально неплохой дизайн стал плохим. В других случаях это говорит о том, что дизайн с самого начала никуда не годился.

    Я не возмусь судить что произошло в данном случае. Консоль в Windows традиционна заброшена маркетологами и, в результате, не получала должного внимания (читай – денег на разработку) == развития.

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

    Элементарно, Ватсон. Программа собирается как GUI приложение. Из WinMain вызывается либо AttachConsole, либо AllocConsole в зависимости от параметров. Цикл сообщений не создается.

    Можно зайти с другой стороны. Сравните “start” и “start /B”. Если указан /B, то флаг CREATE_NEW_CONSOLE в CreateProcess не передается.

  6. Anonymous
  1. No trackbacks yet.
Comments are closed.