【问题标题】:Need a fairly "rude" program exit需要一个相当“粗鲁”的程序退出
【发布时间】:2014-10-05 17:39:29
【问题描述】:

环境是 Windows 7。我们有一个程序(用 C++ 编写并使用相当旧的 [大约 2000] 版本的 Qt)需要监视同一台 PC 上的服务(用 java 编写)。程序打开了一个到服务的套接字连接,两个人不断地闲聊(套接字连接本身表明了omnia praeclara)。

如果该服务通过关闭套接字或通过其他方式发出警报,我需要 C++ 程序显示一条消息,然后停止并终止。尽可能突兀地这样做会很好(我知道,不是你的正常票价)。

我想学习的是如何让程序弹出一个对话框或一些描述的窗口,占据整个屏幕,我可以在上面打印一条消息。同样可行的是,以 UAC 对话框的方式提出一个对话框(这有点使屏幕变暗并接管,迫使你处理它)。超时后(将其保留几分钟),它将毫不客气地终止程序。凯斯普拉特!

我知道使用 MessageBox(或 QMessageBox)来显示少量信息,并使用 Ok 按钮进行确认,但它们既不是全屏也不是(想不出这个词,但它们不是“接管接口”)。

我知道这是处理程序退出的一种粗鲁和可怕的方式......我故意这样做。这些机器位于用户可能已经离开的位置,需要提供某种形式的刺激物,最终迫使他们寻求帮助。

【问题讨论】:

  • 杀死你的程序最残酷的方法是std::abort。它不会调用析构函数,只需关闭您的程序并将一些执行不成功的代码返回给操作系统。
  • 您的问题是什么?你是在问如何检测socket已经关闭,如何制作一个全屏Qt窗口,或者如何优雅地退出当前进程?
  • 编辑了第三段。需要一个全屏对话框/窗口,不允许用户使用 Alt-tab 离开。可以使用 Qt 或标准 Windows 控件来完成。我知道如何关闭套接字,不用担心。
  • 您需要在搜索中使用的关键字是modal应用程序模式在处理弹出窗口之前您无法访问应用程序,但听起来您正在寻找系统范围的模式窗口。
  • @Jon - 对于全屏部分,您是否尝试过 QWidget::showFullScreen(),例如在 QMainWindow 上?

标签: c++ windows qt modal-dialog terminate


【解决方案1】:

我建议使用相当大的文本致电FatalAppExit,以便放大生成的消息框。

此消息框是系统模式的,位于除开始屏幕之外的所有内容之上。当然,您也可以创建一个最顶层的窗口(参见CreateWindowEx 的窗口样式)。但是FatalAppExit是Windows为这个东西提供的手段。

【讨论】:

  • 但它不是模态的,我可以完全访问应用程序以及桌面/系统上的所有其他内容。\
【解决方案2】:

因此,以标准方式,使用漂亮的 API,这似乎是不可行的。似乎 MS 不喜欢模式对话框和暂停系统(有充分的理由)。我们需要,所以我能想出的最好的就是以下,基于我发现的here。创建第二个桌面,切换到该桌面并弹出消息框。我更喜欢没有交互性的对话(会超时,哦,说 5-10 分钟 - 粗鲁!)但现在就可以了。甚至使 UAC 对话框的背景变暗。

这确实应该进入一个模态对话框类以供一般使用。该程序使用的是 Qt,因此是 TerminateProgram 方法的第一部分中的信号。

// This, and the background window proc, are declared static in header.
HDC ServiceMonitorThread::hBKDC;

void ServiceMonitorThread::TerminateProgram()
{
   unsigned int errorCode = 0x0a000000;
   string caption = "Error";
   string message = "In defiance of the gods, an error occurred!";

   // Emit the signal which will instruct the other parts of the program to stop doing what they are doing.
   emit ErrorOccurred();

   // Create the background for the error desktop
   CreateBackgroundBitmap();

   // Save the handle to the current desktop
   HDESK hDeskOld = GetThreadDesktop(GetCurrentThreadId());

   // Create a new desktop
   HDESK hDesk = CreateDesktop("ErrorDialogDT", NULL, NULL, 0, GENERIC_ALL, NULL);
   SwitchDesktop(hDesk);

   // Assign new desktop to the current thread
   SetThreadDesktop(hDesk);

   // Adjust the background to be not black.
   CreateBackgroundWindow();

   // Create and display the error dialog on the new desktop.
   MessageBox(NULL, 
              message.c_str(),
              caption.c_str(), 
              MB_SYSTEMMODAL | MB_ICONSTOP | MB_OK);

   // Switch back to the initial desktop
   SwitchDesktop(hDeskOld);
   CloseDesktop(hDesk);

   ::exit(errorCode);
}

// Takes a screenshot of the current desktop, dims it, then stores it 
// for display on the secondary desktop.
void ServiceMonitorThread::CreateBackgroundBitmap()
{
   // Retrieve desktop size
   RECT rcDesktop = {0};
   GetWindowRect(GetDesktopWindow(), &rcDesktop);

   // Prepare context for background
   HDC hDesktopDC = GetDC(GetDesktopWindow());
   hBKDC = CreateCompatibleDC(hDesktopDC);
   HGDIOBJ hBitmapBKOld = SelectObject(hBKDC, CreateCompatibleBitmap(hDesktopDC, rcDesktop.right, rcDesktop.bottom));

   // Grab a screenshot from current desktop
   BitBlt(hBKDC, 0, 0, rcDesktop.right, rcDesktop.bottom, hDesktopDC, 0, 0, SRCCOPY);

   // Reduce lighting
   HDC hBKDC2L = CreateCompatibleDC(hDesktopDC);
   HGDIOBJ hBitmapBK2LOld = SelectObject(hBKDC2L, CreateCompatibleBitmap(hDesktopDC, rcDesktop.right, rcDesktop.bottom));
   ReleaseDC(GetDesktopWindow(), hDesktopDC);
   FillRect(hBKDC2L, &rcDesktop, (HBRUSH)GetStockObject(BLACK_BRUSH));
   BLENDFUNCTION bf = {AC_SRC_OVER, 0, 128};
   BOOL b = AlphaBlend(hBKDC, 0, 0, rcDesktop.right, rcDesktop.bottom, hBKDC2L, 0, 0, rcDesktop.right, rcDesktop.bottom, bf);
}

// Window procedure of the background window
LRESULT CALLBACK ServiceMonitorThread::BackgroundWindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
   LRESULT res = FALSE;
   switch (nMessage)
   {
   // Implement WM_PAINT message handler
   case WM_PAINT:
      {
         PAINTSTRUCT ps = {0};
         HDC hDC = BeginPaint(hWnd, &ps);
         RECT rcDesktop = {0};
         GetWindowRect(GetDesktopWindow(), &rcDesktop);
         BitBlt(hDC, 0, 0, rcDesktop.right, rcDesktop.bottom, hBKDC, 0, 0, SRCCOPY);
         EndPaint(hWnd, &ps);
         res = TRUE;
      }
      break;

   // Ignore WM_CLOSE event
   case WM_CLOSE:
      break;

   default:
      res = DefWindowProc(hWnd, nMessage, wParam, lParam);
   }
   return res;
}

// Creates a background window on the current desktop (which will 
// actually be the secondary desktop).
void ServiceMonitorThread::CreateBackgroundWindow()
{
   // Create Window Class
   WNDCLASS wc = {0};
   wc.lpfnWndProc = (WNDPROC)ServiceMonitorThread::BackgroundWindowProc;
   wc.hInstance = GetModuleHandle(NULL);
   wc.lpszClassName = "ErrorDialogBK";
   RegisterClass(&wc);

   // Retrieve desktop size
   RECT rcDesktop = {0};
   GetWindowRect(GetDesktopWindow(), &rcDesktop);

   // Create Background Window
   HWND hBKWindow = CreateWindow("ErrorDialogBK", "",
      WS_VISIBLE | WS_POPUP | WS_DISABLED,
      rcDesktop.left, rcDesktop.top, rcDesktop.right, rcDesktop.bottom,
      NULL, NULL, wc.hInstance, NULL);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多