Chr*_*lin 6 c++ console winapi console-application event-handling
我有一个控制台应用程序,用于SetConsoleCtrlHandler设置处理和处理的处理程序CTRL_CLOSE_EVENT.处理程序简单的返回TRUE,这将导致一个对话框出现,并提示用户继续关闭或取消.
该软件在Windows XP SP3和Windows Web Server 2008 SP2上运行.
在XP中,当单击控制台窗口中的"X"时,我的控制处理程序被调用,并预期会出现提示.在Server 2008上关闭控制台窗口不会调用我的控制处理程序,应用程序将关闭而不会提示.
要检查控制处理程序是否正确设置,我已添加了一个案例CTRL_C_EVENT.我可以看到为Ctrl-C调用代码.
Server 2008中处理关闭事件的方式有什么不同吗?好像他们根本没有通过ctrl处理程序.
编辑:看一下MSDN页面SetConsoleCtrlHandler约我无法找到任何信息CTRL_CLOSE_EVENT不再在Vista和更高版本正在处理.
如果你正在使用Windows处理(HWND),而不是控制台CTRL事件,是有可能得到发送到控制台窗口中的关闭消息,并处理这个问题?
以下是我在控制台应用程序(在 Windows 7 上运行)中执行的操作:
我。创建隐藏窗口以等待关闭/注销通知。重要:为其消息循环提供自己的线程
void interrupt::start()
{
WNDCLASSEX wc = {};
HINSTANCE hi = GetModuleHandle(NULL);
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
// . . . etc
if(!RegisterClassEx(&wc))
return;
hwnd_ = CreateWindowEx(WS_EX_CLIENTEDGE, class_name, "Waiting for user logoff event",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hi , NULL);
ShowWindow(hwnd_, SW_HIDE);
UpdateWindow(hwnd_);
MSG msg = {};
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// call internal function for sending "stop" notification to rest of program
ctrl.stop(CTRL_CLOSE_EVENT);
}
Run Code Online (Sandbox Code Playgroud)
二. 在窗口消息处理程序中实现“特殊事件”的处理
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_ENDSESSION:
if (lParam)
{
// call internal function for sending "stop" notification to rest of program
ctrl.stop(lParam == ENDSESSION_LOGOFF ? (int) interrupt::logoff : CTRL_CLOSE_EVENT);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
三. 实现处理“停止”请求的内部函数。它必须处理 2 个特殊情况:
A。当不是从窗口消息线程调用时,发送 WM_CLOSE 到窗口并等待其线程退出
b. 当不从主线程调用时,等待静态变量(至少一个)的终止。
这是因为 CtrlHandler 退出后,Windows 将无条件终止您的进程,而不给您的代码任何清理的机会。静态变量在主线程上被销毁,所以这个等待至少可以保证已经int main()退出。您可以在静态变量的构造函数中捕获主线程的线程ID(可能与启动“影子”窗口的相同)。
这是我在代码中的做法:
void interrupt::stop(int signal)
{
// . . .
// Set exit signal
InterlockedExchange(&stage_, 2L);
// Close shadow window if notification is from elsewhere
if (hwnd_ && GetCurrentThreadId() != thread_.id())
{
PostMessage(hwnd_, WM_CLOSE, 0, 0);
thread_.wait();
}
// Wait for completion of own destructor on main thread
if (GetCurrentThreadId() != main_thread_id_)
while(stage_ != 3L)
Sleep(10);
}
// My static variable to wait for
interrupt ctrl;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2355 次 |
| 最近记录: |