BOOL CtrlHandler( DWORD fdwCtrlType )
{
switch( fdwCtrlType )
{
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT: case CTRL_C_EVENT: case CTRL_BREAK_EVENT:
case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT:
delete server;
DeleteCriticalSection(&cs);
CloseHandle(hEvent);
return TRUE;
default:
return FALSE;
}
}
С помощью SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) устанавливаю обработчик событий консоли, чтобы отлавливать её закрытие.
Код этого обработчика выше. Я конечно понимаю, что он в отдельном потоке исполняется. Но почему когда я в дебаге пытаюсь отследить выполнение этого обработчика, программа завершается сама по себе? Я просто ставлю breakpoint, даже ничего не делаю, но программа через некоторое время завершается сама по себе.
Возможно, дело в том, что управление возвращает функция main(), то есть первичный поток. Но если я и там ставлю breakpoint, то эффект тот же. Программа просто завершается. Хочу понять самое главное, выполняется ли весь код и в обработчике, и во входной функции main()?
05.01.09 15:52: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
Здравствуйте, Abyss_01, Вы писали:
Рылся долго. Оказалось, что нажатие на крестик никак не отменить(вроде бы), точней оно работает нестабильно. В MSDN сказано, что если зарегистрированная функция-обработчик возвращает TRUE, то управление не передаётся стандартному обработчику, которое и закрывает консоль. В случае с Ctrl-C (CTRL_C_EVENT) и Ctrl-Break (CTRL_BREAK_EVENT) все действительно так, даже мессадж боксы с глупыми вопросами можно вешать.
Теперь про крестик. В случае CTRL_CLOSE_EVENT (это и есть нажатие на красный крестик в верхнем правом углу), если обработчик вернёт TRUE, то случится всего навсего:
система показывает на экране выскакивающее диалоговое окно, которое спрашивает пользователя, завершать ли работу процесса. Система также показывает на экране диалоговое окно, если процесс не отвечает в пределах некоторого промежутка времени задержки (5 секунд для CTRL_CLOSE_EVENT, и 20 секунд для CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT).
У меня это диалоговое окно не выскакивает. Через 5 секунд процесс вырубается, будто я вызывал функция SetConsoleCtrlHandler (0x280,SHUTDOWN_NORETRY)
SHUTDOWN_NORETRY — Система завершает работу процесса без показа на экране диалогового окна подтверждения действия для пользователя.
В конечном итоге обнаружил я такое замечание:
[msdn]
Система создает сигналы CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT, когда пользователь закрывает консоль, заканчивает работу в сети, или прекращает работу системы так, чтобы процесс имел возможность очиститься перед завершением. Консольные функции, или любые функции периода исполнения языка программирования C, которые вызывают консольные функции, не могут работать надежно в течение обработки любого из этих трех сигналов, упомянутых перед этим. Причина заключается в том, что некоторые или все внутренние консольные процедуры очистки, возможно, были вызваны перед выполняющимся обработчиком особой ситуации сигнала процесса.
[/msdn]
CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT вроде бы аналогично CTRL_CLOSE_EVENT.
С CTRL_CLOSE_EVENT выход для меня такой, убрать возможность закрытия консоли через "красный крестик" вообще.
HWND ConsoleWnd = GetConsoleHwnd();//FindWindow(_T("ConsoleWindowClass"),pszOldWindowTitle);
HMENU hm = GetSystemMenu( ConsoleWnd, FALSE );
DeleteMenu(hm, SC_CLOSE , MF_BYCOMMAND);
DrawMenuBar(ConsoleWnd);
Для CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT что делать пока не знаю, но в моём случае это и не надо.
Так морочился со всем этим, потому что мне надо было, чтобы все ресурсы гарантированно очищались.
Остался только два вопроса,
1. Как сделать действия, обратные SetConsoleCtrlHandler (0x280,SHUTDOWN_NORETRY), ведь второй параметр документированно у неё может быть только один — SHUTDOWN_NORETRY = 0x00000001, то есть 1.
Если посмотреть на значение второго параметра возвращаемое GetProcessShutdownParameters(&a,&b) до этого, то b=0.
2. Не могу первый вопрос проверить на практике, потому что у меня (может из-за Висты) не вызывается стандартное диалоговое окно, которое якобы и надо отменять с помощью SetConsoleCtrlHandler (0x280,SHUTDOWN_NORETRY). Вопрос, почему же оно не вызывается, если обработчик событий возвращает TRUE?
P.S. Понимаю, что на эти вопросы вряд ли уже когда-нибудь ответят, потому что они в разряде философских, а не практических.