在Windows Web Server 2008中的事件CTRL_CLOSE_EVENT上未调用CtrlHandler

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事件,是有可能得到发送到控制台窗口中的关闭消息,并处理这个问题?

bro*_*ekk 4

以下是我在控制台应用程序(在 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)