Registro de una función de identificador de control
Ejemplo de controlador de control básico
Este es un ejemplo de la función SetConsoleCtrlHandler que se utiliza para instalar un controlador de control.
Cuando se recibe una señal CTRL+C, el controlador de control devuelve TRUE, lo que indica que controló la señal. Esto impide que se llame a otros controladores de control.
Cuando se recibe una señal CTRL_CLOSE_EVENT, el controlador de control devuelve TRUE y el proceso finaliza.
Cuando se recibe una señal CTRL_BREAK_EVENT, CTRL_LOGOFF_EVENT o CTRL_SHUTDOWN_EVENT, el controlador de control devuelve FALSE. Esto hace que la señal se pase a la siguiente función del controlador de control. Si no se registró ningún otro controlador de control o ninguno de los controladores registrados devuelve TRUE, se usará el controlador predeterminado, lo que dará lugar a que finalice el proceso.
Nota:
Al llamar a AttachConsole, AllocConsole o FreeConsole, la tabla de identificadores de control en el proceso de cliente se restablecerá a su estado inicial. Los controladores se deben registrar de nuevo cuando cambia la sesión de la consola adjunta.
// CtrlHandler.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <windows.h>
#include <stdio.h>
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
printf("Ctrl-C event\n\n");
Beep(750, 300);
return TRUE;
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT:
Beep(600, 200);
printf("Ctrl-Close event\n\n");
return TRUE;
// Pass other signals to the next handler.
case CTRL_BREAK_EVENT:
Beep(900, 200);
printf("Ctrl-Break event\n\n");
return FALSE;
case CTRL_LOGOFF_EVENT:
Beep(1000, 200);
printf("Ctrl-Logoff event\n\n");
return FALSE;
case CTRL_SHUTDOWN_EVENT:
Beep(750, 500);
printf("Ctrl-Shutdown event\n\n");
return FALSE;
default:
return FALSE;
}
}
int main(void)
{
if (SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
printf("\nThe Control Handler is installed.\n");
printf("\n -- Now try pressing Ctrl+C or Ctrl+Break, or");
printf("\n try logging off or closing the console...\n");
printf("\n(...waiting in a loop for events...)\n\n");
while (1) {}
}
else
{
printf("\nERROR: Could not set control handler");
return 1;
}
return 0;
}
Ejemplo de escucha con ventana oculta
De acuerdo con los comentarios, si se cargan las bibliotecas gdi32.dll o user32.dll, no se llama a SetConsoleCtrlHandler para los eventos CTRL_LOGOFF_EVENT y CTRL_SHUTDOWN_EVENT. La solución alternativa especificada es crear una ventana oculta, si no existe ninguna ventana, llamando al método CreateWindowEx con el parámetro dwExStyle establecido en 0 y escuchar los mensajes de ventana WM_QUERYENDSESSION y WM_ENDSESSION. Si ya existe una ventana, agregue los dos mensajes al procedimiento de ventana existente.
Para encontrar más información sobre cómo configurar una ventana y su bucle de mensajes, consulte Creación de una ventana.
// CtrlHandler.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <Windows.h>
#include <stdio.h>
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
printf("Ctrl-C event\n\n");
Beep(750, 300);
return TRUE;
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT:
Beep(600, 200);
printf("Ctrl-Close event\n\n");
return TRUE;
// Pass other signals to the next handler.
case CTRL_BREAK_EVENT:
Beep(900, 200);
printf("Ctrl-Break event\n\n");
return FALSE;
case CTRL_LOGOFF_EVENT:
Beep(1000, 200);
printf("Ctrl-Logoff event\n\n");
return FALSE;
case CTRL_SHUTDOWN_EVENT:
Beep(750, 500);
printf("Ctrl-Shutdown event\n\n");
return FALSE;
default:
return FALSE;
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_QUERYENDSESSION:
{
// Check `lParam` for which system shutdown function and handle events.
// See https://video2.skills-academy.com/windows/win32/shutdown/wm-queryendsession
return TRUE; // Respect user's intent and allow shutdown.
}
case WM_ENDSESSION:
{
// Check `lParam` for which system shutdown function and handle events.
// See https://video2.skills-academy.com/windows/win32/shutdown/wm-endsession
return 0; // We have handled this message.
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int main(void)
{
WNDCLASS sampleClass{ 0 };
sampleClass.lpszClassName = TEXT("CtrlHandlerSampleClass");
sampleClass.lpfnWndProc = WindowProc;
if (!RegisterClass(&sampleClass))
{
printf("\nERROR: Could not register window class");
return 2;
}
HWND hwnd = CreateWindowEx(
0,
sampleClass.lpszClassName,
TEXT("Console Control Handler Sample"),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
nullptr,
nullptr
);
if (!hwnd)
{
printf("\nERROR: Could not create window");
return 3;
}
ShowWindow(hwnd, SW_HIDE);
if (SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
printf("\nThe Control Handler is installed.\n");
printf("\n -- Now try pressing Ctrl+C or Ctrl+Break, or");
printf("\n try logging off or closing the console...\n");
printf("\n(...waiting in a loop for events...)\n\n");
// Pump message loop for the window we created.
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
else
{
printf("\nERROR: Could not set control handler");
return 1;
}
}