Среда — Windows 7. У нас есть программа (написанная на C ++ и использующая довольно старую версию Qt [около 2000]), которая должна отслеживать сервис (написанный на java) на том же ПК. Программа открывает сокетное соединение с сервисом, и эти двое непрерывно общаются ни о чем конкретно (само сокетное соединение указывает на omnia praeclara).
Если эта служба выдает предупреждение, либо закрывая сокет, либо каким-либо другим способом, я требую, чтобы программа C ++ отобразила сообщение, а затем остановилась и завершилась. Было бы неплохо сделать это настолько навязчиво, насколько это возможно (я знаю, не ваш обычный тариф).
Я хотел бы узнать, как заставить программу вызывать диалоговое окно или окно некоторого описания, занимая весь экран, на котором я мог бы напечатать сообщение. Столь же жизнеспособным было бы создать диалог в стиле диалога UAC (который затемняет экран и захватывает его, заставляя вас иметь дело с ним). По истечении времени ожидания (оставит его включенным на несколько минут), программа бесцеремонно прекратит работу программы. Kersplat!
Я знаю об использовании MessageBox (или QMessageBox) для отображения небольших кусочков информации с кнопкой «ОК» для подтверждения, но они не являются ни полноэкранными, ни (не могут придумать слова, но они не «захватывают интерфейс») ,
Я знаю, что это грубый и ужасный способ справиться с выходом из программы … Я намеренно намереваюсь это сделать. Машины находятся в месте, где пользователь мог отойти, и должна присутствовать какая-то форма раздражителя, которая в конечном итоге заставит их позвать на помощь.
Я бы предложил позвонить FatalAppExit
с довольно большим текстом, чтобы увеличить размер окна сообщения.
Это окно сообщения является модальным для системы, поверх всего, кроме начального экрана. Вы можете, конечно, вместо этого создать самое верхнее окно (см. Стили окон в CreateWindowEx
). Но FatalAppExit
это средство, которое Windows обеспечивает для этой вещи.
Таким образом, кажется, что это не совсем выполнимо стандартным способом, используя хороший API. Кажется, MS не любит модальные диалоги и приостановка системы (по уважительной причине). Нам нужно, хотя, поэтому лучшее, что я мог придумать, было следующее, основываясь на том, что я нашел Вот. Создайте второй рабочий стол, переключитесь на него и откройте окно сообщения. Я бы предпочел диалог без интерактивности (тайм-аут после, о, скажем, 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);
}