需要一个相当"rude"的程序退出
Need a fairly "rude" program exit
环境为Windows 7。我们有一个程序(用c++编写,使用一个相当老的[2000年左右]版本的Qt),它需要监控同一台PC上的一个服务(用java编写)。该程序打开一个与服务的套接字连接,两者持续地聊天,没有任何特别的内容(套接字连接本身表示omnia praeclara)。
如果该服务通过关闭套接字或其他方式发出警报,我要求c++程序显示一条消息,然后停止并终止。如果这样做能尽可能地引人注目就好了(我知道,不是你的常规票价)。
我想学习的是如何让程序产生一个对话框或一些描述的窗口,占据整个屏幕,我可以在上面打印消息。同样可行的是,以UAC对话框的方式出现一个对话框(这有点使屏幕变暗并接管,迫使你处理它)。超时后(将在那里停留几分钟),它将毫不客气地终止程序。Kersplat !
我知道使用MessageBox(或QMessageBox)来显示少量的信息,用Ok按钮来确认,但这些既不是全屏也不是(想不出这个词,但它们不是"接管界面")。
我知道这是一个粗鲁和可怕的方式来处理程序退出…我有意让它成为。机器放置在用户可能已经离开的地方,并且需要出现某种形式的刺激,最终迫使他们寻求帮助。
我建议调用具有相当大的文本的FatalAppExit
,以便确定结果消息框的大小。
此消息框是系统模式的,位于除开始屏幕之外的所有内容的顶部。当然,你也可以创建一个最顶层的窗口(参见CreateWindowEx
的窗口样式)。但是FatalAppExit
是Windows提供的方法。
所以,这似乎不是真正可行的,在一个标准的方式,使用一个很好的API。似乎微软不喜欢模态对话框和暂停系统(有充分的理由)。我们需要这样做,所以我能想出的最好的办法是,基于我在这里的发现。创建第二个桌面,切换到该桌面并弹出消息框。我更喜欢没有交互性的对话(可能会在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);
}
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 创建LinkedList退出,返回代码为-11(SIGSEGV)
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 如何让LLDB在成功时退出,在失败时等待
- C++控制台应用程序阻止退出
- 程序在执行程序的其余部分之前退出
- 构造函数在退出函数时无法初始化一个参数
- 为什么异常不退出程序?
- 我不断收到 [错误] ID 返回 1 退出状态错误,但看不到问题所在
- 退出简单while循环时出现问题
- 使用vscode调试时,GDB意外退出
- pclose() 不会给我进程退出代码
- 为什么系统函数总是在C++中返回已转移的退出状态?
- C++从另一个函数退出函数
- C++ 中的编译错误:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- C++逗号分隔的输入数组代码过早退出
- Netbeans 10:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- 为什么 C++ 中的以下结构声明会导致退出 127?
- 编译问题:在函数"_start"中:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 需要一个相当"rude"的程序退出