C++ 如何在控制台应用程序中处理WM_ENDSESSION
我编写了一个程序来注册鼠标事件,我希望它在计算机关闭时终止(然后执行刷新和最终打印) 我试过使用CtrlHandler,但它仅在系统关闭时使用Ctrl-C,因为我使用的是Win32库,根据MSDN: 如果控制台应用程序加载gdi32.dll或user32.dll库,则在调用SetConsoletrlHandler时指定的HandlerRoutine函数不会在CTRL\u LOGOFF\u事件和CTRL\u SHUTDOWN\u事件中被调用。操作系统将加载gdi32.dll或user32.dll的进程识别为Windows应用程序,而不是控制台应用程序。对于不直接调用gdi32.dll或user32.dll中的函数,而是调用函数(如Shell函数)的控制台应用程序,也会发生此行为,而Shell函数则反过来调用gdi32.dll或user32.dll中的函数 要在用户注销或设备在这些情况下关闭时接收事件,请在控制台应用程序中创建一个隐藏窗口,然后处理隐藏窗口接收的WM_QUERYENDSESSION和WM_ENDSESSION窗口消息。通过调用CreateWindowEx方法,将dwExStyle参数设置为0,可以创建隐藏窗口 因此,首先我必须创建一个隐藏窗口,然后我必须截获WM_ENDSESSION消息。但是怎么做呢 我试着读一些例子,但我不知道怎么做 这是我的密码:C++ 如何在控制台应用程序中处理WM_ENDSESSION,c++,winapi,mouseevent,C++,Winapi,Mouseevent,我编写了一个程序来注册鼠标事件,我希望它在计算机关闭时终止(然后执行刷新和最终打印) 我试过使用CtrlHandler,但它仅在系统关闭时使用Ctrl-C,因为我使用的是Win32库,根据MSDN: 如果控制台应用程序加载gdi32.dll或user32.dll库,则在调用SetConsoletrlHandler时指定的HandlerRoutine函数不会在CTRL\u LOGOFF\u事件和CTRL\u SHUTDOWN\u事件中被调用。操作系统将加载gdi32.dll或user32.dll的
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 FALSE; //TRUE
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT:
Beep(600, 200);
printf("Ctrl-Close event\n\n");
return FALSE; //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");
myfile << "totale :" << tot;
myfile.flush();
myfile.close();
return TRUE; //FALSE
case CTRL_SHUTDOWN_EVENT:
Beep(750, 500);
printf("Ctrl-Shutdown event\n\n");
myfile << "totale :" << tot;
myfile.flush();
myfile.close();
return TRUE; //FALSE
default:
return FALSE;
}
}
int main(){
if (SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
printf("\nThe Control Handler is installed.\n");
for(;;)
{
code that print the mouse event(........)
}
}
else
{
printf("\nERROR: Could not set control handler");
return 1;
}
return 0;
}
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
开关(fdwCtrlType)
{
//处理CTRL-C信号。
/*案例控制事件:
printf(“Ctrl-C事件\n\n”);
嘟嘟声(750300);
返回FALSE;//TRUE
//CTRL-CLOSE:确认用户想要退出。
案例控制关闭事件:
嘟嘟声(600200);
printf(“Ctrl-Close事件\n\n”);
返回FALSE;//TRUE
//将其他信号传递给下一个处理程序。
案例控制中断事件:
嘟嘟声(900200);
printf(“Ctrl-Break事件\n\n”);
返回FALSE;
*/案例控制\注销\事件:
嘟嘟声(1000200);
printf(“Ctrl注销事件\n\n”);
myfile您只需在控制台应用程序中创建一个隐藏的GUI窗口,并在窗口过程中处理WM_ENDSESSION
,如下所示
#包括
HWND g_hidden_window=nullptr;
LRESULT回调wnd_过程(HWND、UINT、WPARAM、LPARAM);
//应用程序的主要入口点
int main(){
hmodulecurrent_instance=::GetModuleHandle(L“”);
//注册窗口类
WNDCLASSEX窗口_类_ex={0};
window_class_ex.cbSize=sizeof(WNDCLASSEX);
窗口类前lpfnWndProc=wnd程序;
window_class_ex.lpszClassName=L“Foo”;
window\u class\u ex.hInstance=当前\u实例;
if(!::注册表类(&window\u class\u ex)){
返回1;
}
//创建重叠窗口
g_hidden_window=::CreateWindow(
L“Foo”,
L“,
W_重叠,
0, 0, 0, 0,
nullptr,
nullptr,
当前_实例,
0);
如果(!g_隐藏窗口){
返回1;
}
消息;
//主消息循环
while(::GetMessage(&message,nullptr,0,0)){
::DispatchMessage(&message);
}
}
现在,在主窗口过程中,您应该处理WM\u ENDSESSION
。在您的情况下,我认为没有理由处理WM\u QUERYENDSESSION
。您还应该处理WM\u CLOSE
和/或WM\u DESTROY
以退出主消息循环:
//主窗口过程
LRESULT回调wnd_proc(HWND window_句柄、UINT window_消息、WPARAM WPARAM、LPARAM LPARAM){
开关(窗口信息){
案例WM_ENDSESSION:
if(wparam){
//根据MSDN,当系统即将关闭时,该值将为1:https://docs.microsoft.com/en-us/windows/win32/shutdown/wm-endsession
//在这里调用你的函数
CtrlHandler(CTRL\u关闭\u事件);
}
打破
案例WM_结束:
车窗(车窗把手);
打破
案例WM_销毁:
::PostQuitMessage(0);
打破
违约:
return::DefWindowProc(窗口句柄、窗口消息、wparam、LPRAM);
}
返回0;
}
要优雅地关闭应用程序,您必须中断该消息循环。为此,您必须发送WM\u CLOSE
消息:
SendMessage(g_隐藏窗口,WM_关闭,0,0);
或者,通过调用以下命令显式销毁窗口:
销毁窗口(g_隐藏窗口);
让我知道它是否有效。我还没有测试它,因为我现在在Mac上,但它应该可以工作。对于隐藏的消息窗口,不需要处理WM\u CLOSE
。默认情况下,DefWindowProc()
将调用DestroyWindow()
回复WM\u CLOSE
@RemyLebeau谢谢你!但我有另一个问题..如何运行消息循环和我的程序(检查鼠标位置是一个无限for循环)同时?如果我将for循环放在消息部分上方,它将不会运行,因为它位于while循环中。希望您理解我的问题,顺便告诉我是否应该发布代码。感谢将消息窗口创建和消息循环移动到单独的工作线程中。或者,将消息调度移到主while
循环,并将GetMessage()
更改为PeekMessage()
,这样就不会阻止循环代码。只需确保主循环定期检查挂起的消息。