Цель работы
Скачать 468.63 Kb.
|
Цель работы: Реализовать windows-приложение, реализующее следующую реакцию на действия пользователя в главном окне: при клике на левую кнопку мыши создается дочернее окно приложения по отношению к главному, которое отображается в месте клика мыши и в рабочей области которого отображаются координаты клика мыши относительно главного окна; при клике на правую кнопку мыши дочернее окно перемещается в противоположный квадрант главного окна относительно клика мыши. 2. Ход работы: 1) Определить главные составляющие приложения, необходимые для его функционирования в соответствии с заданием. Главные составляющие: Оконная функция WinMain, необходимая для регистрации класса окна, создания главного окна программы и запуска цикла обработки сообщений; Функции окна WndPopup и WndProc, необходимые для обработки сообщений; Функция RegClass необходимая для регистрация WNDCLASS; Структура контекста устройства приложения HDC; Структура PAINTSTRUCT содержащая информацию для приложения Структура RECT определяющая координаты углов треугольника 2) Определить все возникающие и требующие обработки сообщения Windows в приложении, определить идентификаторы данных сообщений. Для выполнения поставленной задачи необходимо обработать следующие сообщения: Сообщение перемещения окна. Идентификатор WM_MOVE; сообщение изменения размеров окна. Идентификатор WM_SIZE; сообщение нажатия левой кнопки мыши. Идентификатор WM_LBUTTONDOWN; сообщение нажатия правой кнопки мыши. Идентификатор WM_RBUTTONDOWN; сообщение закрытия окна. Идентификатор WM_DESTROY; сообщение окрашивания окна. Идентификатор WM_PAINT. 3) Реализовать приложение с использованием WinAPI на языке С с учетом предыдущих этапов проектирования. Исходный код программы: #include BOOL RegClass(WNDPROC, LPCTSTR, UINT); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK WndPopup(HWND, UINT, WPARAM, LPARAM); HINSTANCE hInstance; char szMainName[] = "MainClass"; char szPopupClass[] = "PopupClass"; char szTitle[] = "Laboratornaya1"; static HWND hwnds; char posMouse[20]; int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND hwnd; hInst = hInstance; if (!RegClass(WndProc, szMainName, COLOR_DESKTOP)) return FALSE; if (!RegClass(WndPopup, szPopupClass, COLOR_BTNFACE)) return FALSE; hwnd = CreateWindow(szMainName, szTitle, WS_OVERLAPPEDWINDOW|WS_VISIBLE, 0, 0, 1400, 700, 0, 0, hInstance, NULL); if (!hwnd) return FALSE; while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } int RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = wc.cbWndExtra = 0; wc.lpfnWndProc = Proc; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_INFORMATION); wc.hCursor = LoadCursor(NULL, IDC_CROSS); wc.hbrBackground = (HBRUSH)(brBackground); wc.lpszMenuName = (LPCTSTR)NULL; wc.lpszClassName = szName; return RegisterClass(&wc); } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static short left, top, Width, Height; static short cxClient, cyClient; RECT rc; switch(msg) { case WM_MOVE: { GetWindowRect(hwnd, &rc); if (IsWindow(hwnds)) MoveWindow(hwnds, (rc.left + rc.right)/2, (rc.top + rc.bottom)/2, Width, Height, TRUE); return 0; } case WM_SIZE: { GetWindowRect(hwnd, &rc); cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); Width = cxClient/2; Height = cyClient/2; if (IsWindow(hwnds)) MoveWindow(hwnds, (rc.left + rc.right)/2, (rc.top + rc.bottom)/2, Width, Height, TRUE); return 0; } case WM_LBUTTONDOWN: { GetWindowRect(hwnd, &rc); cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); _itoa(cxClient, posMouse, 10); strcat(posMouse, " "); char y[10]; _itoa(cyClient, y, 10); strcat(posMouse, y); if (hwnds != NULL) return 0; hwnds = CreateWindow(szPopupClass, "ChildWindow", WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, (rc.left + rc.right)/2, (rc.top + rc.bottom)/2, Width, Height, hwnd, 0, hInstance, NULL); break; } case WM_RBUTTONDOWN: { GetWindowRect(hwnd, &rc); cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); if (cxClient < (rc.left + rc.right)/2) { if (cyClient < (rc.top + rc.bottom)/2) MoveWindow(hwnds, (rc.left + rc.right)/2, (rc.top + rc.bottom)/2, Width, Height, TRUE); else MoveWindow(hwnds, (rc.left + rc.right)/2, rc.top + 15, Width, Height, TRUE); } else if (cxClient >= (rc.left + rc.right)/2) { if (cyClient < (rc.top + rc.bottom)/2) MoveWindow(hwnds, rc.left + 5, (rc.top + rc.bottom)/2, Width, Height, TRUE); else MoveWindow(hwnds, rc.left + 5, rc.top + 15, Width, Height, TRUE); } return 0; } case WM_DESTROY: { PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } LRESULT CALLBACK WndPopup(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rc; switch(msg) { case WM_PAINT : { hDC = BeginPaint(hwnds, &ps); GetClientRect(hwnds, &rc); SetTextColor(hDC, RGB(255, 0, 0)); SetBkColor(hDC, RGB(255, 255, 255)); SetTextColor(hDC, TA_CENTER); TextOut(hDC, (rc.left + rc.right)/2, (rc.top + rc.bottom)/2, posMouse, strlen(posMouse)); EndPaint (hwnd, &ps); return 0; } case WM_DESTROY: { hwnds = NULL; break;} } return DefWindowProc(hwnd, msg, wParam, lParam); } Выполнение программы отображено на рисунках 1 и 2. Рисунок 1 – Главное окно программы Рисунок 2 – Появление окна с координатами клика мыши Контрольные вопросы Структура Windows-приложения: основные структурные части и их назначение. Структура Windows-приложения состоит из оконной функции WinMain() и функции окна WndProc(). Функция WinMain() нужна для регистрации класса окна, создания главного окна приложения и создания цикла обработки сообщений Функция окна WndProc() нужна для связывания сообщений с соответствующими функциями обработки сообщений и непосредственно вызова этих функций обработки сообщения. Оконная функция Windows-приложения: синтаксис, состав, механизм взаимодействия приложения с операционной системой. Синтаксис: int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) Внутри функции WinMain() необходимо провести следующее: Зарегистрировать класс окна с помощью функции RegClass(). Создать окно приложения с помощью функции CreateWindow(). Создать цикл обработки сообщений while, получающий сообщения с помощью функции GetMessage() и проводящий обработку сообщений с помощью функций TranslateMessage() и DispatchMessage(). Сам цикл отображен на рисунке. Рисунок 3 – Цикл обработки сообщений Функция окна Windows-приложения: синтаксис, параметры функции обратного вызова, механизм взаимодействия приложения с пользователем. Синтаксис: LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) Параметры функции окна WndProc(): Дескриптор окна адресата hwnd, обрабатывающее сообщениеж Передаваемое сообщение msg; Первый параметр сообщения wParam; Второй параметр сообщения lParam. Функция окна вызывается непосредственно самой ОС. Тип возвращаемого значения функции окна жестко заданы в отличие от имени функции окна, которое может быть выбрано произвольно. Имя функции окна должно быть зарегистрировано в Windows. Это происходит при регистрации структры окна. Функция окна получает сообщение и соответственно реагирует на него. Каждое окно определяет свою собственную функцию, которая принимает поступившие сообщения и проводит соответствующую обработку. Для непосредственной обработки сообщений используется оператор switch, с помощью ветвей которого устанавливается, какое сообщение было принято, и вызывается соответствующая функция обработки поступившего сообщения. Все сообщения, которые не связаны с собственными функциями обработки сообщений, должны быть переданы функции DefWindowsProc(). Понятие адресного пространства Windows-приложения, структура адресного пространства, понятие процесса и потока. Процесс – экземпляр выполняемой программы. Процесс состоит из двух компонентов: объект ядра; адресного пространства. Каждому процессу выделяется собственное виртуальное адресное пространство. Для 32-разрядных процессов его размер составляет 4 Гб. Соответственно 32-битный указатель может быть любым числом от 0x00000000 до OxFFFFFFFF. Всего, таким образом, указатель может принимать 4 294 967 296 значений, что как раз и перекрывает четырех гигабайтовый диапазон. Для 64-разрядных процессов размер адресного пространства равен 1б экзабайтам, поскольку 64-битный указатель может быть любым числом от 0x00000000 00000000 до OxFFFFFFFF FFFFFFFF и принимать 18446 744 073 709 551 616 значений, охватывая диапазон в 16 экзабайтов. Виртуальное адресное пространство каждого процесса разбивается на такие разделы как: раздел для выявления нулевых указателей: раздел для совместимости с программами DOS и 16-разрядной Windows; раздел для кода и данных пользовательского режима; закрытый раздел размером 64 кб; раздел для файлов проецируемых в память; раздел для кода и данных режима ядра. Поток – базовая единица выполнения в Windows. Каждый процесс состоит из одного или нескольких потоков. |