因此,以标准方式,使用漂亮的 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);
}