Задача. Окно приложения стиля временного окна с кнопкой минимизации и с фоном цвета рабочего стола Windows занимает весь экран. При попытке запуска второго экземпляра на передний план переместить окно первого экземпляра и завершить работу.
Анализ задания. (Полный текст приложения приведен ниже, в листинге 1.2.)
Для поиска других экземпляров приложения воспользуемся функцией FindWindow:
HWND hwnd = FindWindow(szMainClass, szTitle);
Она возвращает дескриптор окна класса szMainClass с заголовком szTitle. Если такого окна нет, то это первый экземпляр приложения и дескриптору hwnd присваивается NULL. Иначе, возвращается дескриптор найденного окна.
Функция FindWindow проверяет только совпадение имени класса и заголовка. То есть, если работает экземпляр другого приложения с окном класса с таким же именем szMainClass и заголовком szTitle, то функция вернет дескриптор окна другого приложения.
Если "предыдущий экземпляр приложения" обнаружен, выводим сообщение:
MessageBox(hwnd,
"Можно запускать только одну копию приложения!!!\n\n"
"Перемещаю на передний план первый экземпляр",
szTitle, МВ_ОК | MB_CONSTOP);
До перемещения окна на передний план проверяем состояние этого окна и, если оно свернуто, восстанавливаем его предыдущее состояние:
if (IsIconic(hwnd)) ShowWindow(hwnd, SW_RESTORE);
Перемещаем окно первого экземпляра приложения на передний план:
SetForegroundWindow(hwnd);
Затем второй экземпляр приложения завершает работу.
Если предыдущий экземпляр приложения не найден, регистрируем класс окна:
if (!RegClass(WndProc, szMainClass, COLOR_DESKTOP))
return FALSE;
Цвет фона окна приложения определяем по табл. 1.4 – COLOR_DESKTOP.
Для создания максимально распахнутого окна приложения определяем ширину и высоту экрана в пикселях:
int w=GetSystemMetrics(SM_CXSCREEN);
int h=GetSystemMetrics(SM_CYSCREEN);
Создаем окно:
hwnd = CreateWindow(szMainClass, szTitle,
WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE,
0, 0, w, h, 0, 0, hInstance, NULL);
Стиль временного окна с кнопкой минимизации и заголовком определяем по табл. 1.5 – WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE.
Далее активизируем цикл обработки и диспетчеризации сообщений:
while(GetMessage(&msg, 0, 0, 0))
DispatchMessage(&msg);
Это приложение не предусматривает обработки сообщений с клавиатуры. Поэтому в цикле отсутствует вызов функции трансляции клавиатурных сообщений.
Любые действия над окном передают функции окна:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: {PostQuitMessage(0); return 0;}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Такая функция окна ранее уже была рассмотрена.
Листинг 1.2. Запрет запуска второго экземпляра приложения.
#include <windows.h>
//Объявления функций
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInstance;
TCHAR szMainClass[] = TEXT("MainClass");
TCHAR szTitle[]= TEXT("Пример 1.2");
//Главная функция приложения
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
hInstance=hInst;
HWND hwnd = FindWindow(szMainClass, szTitle);
if (hwnd)
{
MessageBox(hwnd,
TEXT("Можно запускать только один экземпляр приложения\nПеремещаю на передний план первый экземпляр"),
szTitle, MB_OK | MB_ICONSTOP);
//Если окно свернуто, восстанавливаем
if (IsIconic(hwnd))
ShowWindow(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);
return 0;
}
if (!RegClass(WndProc, szMainClass, COLOR_DESKTOP))
return FALSE;
//До создания окна узнаем габариты экрана в пикселях
int w = GetSystemMetrics(SM_CXSCREEN)-1; //Ширина
int h = GetSystemMetrics(SM_CYSCREEN)-1; //Высота
hwnd = CreateWindow(szMainClass, szTitle, WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE, 0, 0, w, h, 0, 0, hInstance, NULL);
if (!hwnd) return FALSE;
while(GetMessage(&msg, 0,0, 0))
DispatchMessage(&msg);
return msg.wParam;
}
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASS wc;
wc.style = wc.cbClsExtra = wc.cbWndExtra = 0;
wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(brBackground + 1);
wc.lpszMenuName = (LPCTSTR)NULL;
wc.lpszClassName = szName;
return (RegisterClass(&wc)!= 0);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
{ PostQuitMessage(0); return 0; }
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}