Обработчик закрытия консоли
От: Abyss_01  
Дата: 05.01.09 10:53
Оценка:
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++. Прикладные вопросы' — Кодт
Re: Обработчик закрытия консоли
От: Аноним  
Дата: 05.01.09 21:32
Оценка:
Здравствуйте, 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. Понимаю, что на эти вопросы вряд ли уже когда-нибудь ответят, потому что они в разряде философских, а не практических.
Re[2]: Обработчик закрытия консоли
От: Arsenicum Россия  
Дата: 15.01.09 14:42
Оценка:
Здравствуйте, Аноним, Вы писали:

...

atexit() уже отменили?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.