Функции обратного вызова веб-служб Windows
Обратные вызовы позволяют приложению вызывать функцию, определенную на другом уровне или уровне. Приложение регистрирует аргумент функции в качестве обработчика, который будет вызываться асинхронно позже по мере необходимости. Обратный вызов вызывается, если функция завершается асинхронно, указывая на успешность или ошибку функции. Обратный вызов не вызывается, если операция завершается синхронно.
API веб-служб Windows включает следующие функции обратного вызова:
Использование таймера.
Во многих программах требуется следить за временем или выполнять какие-либо периодические действия. Программы MS-DOS для работы с таймером перехватывали аппаратное прерывание таймера, встраивая свой собственный обработчик для прерывания INT 8h. Обычные приложения Windows не могут самостоятельно обрабатывать прерывания таймера, поэтому для работы с ним нужно использовать другие способы.
Операционная система Windows позволяет для каждого приложения создать несколько виртуальных таймеров. Все эти таймеры работают по прерываниям одного физического таймера.
Так как работа Windows основана на передаче сообщений, логично было бы предположить, что и работа виртуального таймера также основана на передаче сообщений. И в самом деле, приложение может заказать для любого своего окна несколько таймеров, которые будут периодически посылать в функцию окна сообщение с кодом WM_TIMER.
Есть и другой способ, также основанный на передаче сообщений. При использовании этого способа сообщения WM_TIMER посылаются не функции окна, а специальной функции, описанной с ключевым словом _export. Эта функция напоминает функцию окна и, так же как и функция окна, вызывается не из приложения, а из Windows. Функции, которые вызываются из Windows, имеют специальный пролог и эпилог и называются функциями обратного вызова (callback function). Функция окна и функция, специально предназначенная для обработки сообщений таймера, являются примерами функций обратного вызова.
К сожалению, точность виртуального таймера оставляет желать лучшего. Сообщения таймера проходят через очередь приложения, к тому же другое приложение может блокировать на некоторое время работу вашего приложения. Поэтому сообщения от таймера приходят в общем случае нерегулярно. Кроме того, несмотря на возможность указания интервалов времени в миллисекундах, реальная дискретность таймера определяется периодом прерываний, посылаемых таймером. Этот период (то есть длительность одного такта таймера) можно узнать с помощью функции GetTimerResolution:
DWORD WINAPI GetTimerResolution(void);
Нерегулярность прихода сообщений таймера не вызывает особых проблем, если речь не идет о работе в режиме реального времени. Системы реального времени, основанные на Windows, должны использовать для устройств ввода/вывода, критичных к скорости реакции системы, специальные драйверы. Строго говоря, операционная система Windows не предназначена для работы в режиме реального времени. Windows ориентирована на работу с человеком, когда небольшие задержки событий во времени не имеют никакого значения.
Создание и уничтожение таймера
Для создания виртуального таймера приложение должно использовать функцию SetTimer:
UINT WINAPI SetTimer(HWND hwnd, UINT idTimer,UINT uTimeout, TIMERPROC tmprc);
Первый параметр функции (hwnd) должен содержать идентификатор окна, функция которого будет получать сообщения от таймера, или NULL. В последнем случае с создаваемым таймером не связывается никакое окно и сообщения от таймера будут приходить в специально созданную для этого функцию.
Второй параметр (idTimer) определяет идентификатор таймера (он не должен быть равен нулю). Идентификатор используется только в том случае, если первый параметр функции SetTimer содержит идентификатор окна. Так как для одного окна можно создать несколько таймеров, для того чтобы различать сообщения, приходящие от разных таймеров, приложение при создании должно снабдить каждый таймер собственным идентификатором.
Если первый параметр указан как NULL, второй параметр функции игнорируется, так как для таймера задана специальная функция, получающая сообщения только от этого таймера.
Третий параметр (uTimeout) определяет период следования сообщений от таймера в миллисекундах. Учтите, что физический таймер тикает приблизительно 18,21 раза в секунду (точное значение составляет 1000/54,925). Поэтому, даже если вы укажете, что таймер должен тикать каждую миллисекунду, сообщения будут приходить с интервалом не менее 55 миллисекунд.
Последний параметр (tmprc) определяет адрес функции, которая будет получать сообщения WM_TIMER (мы будем называть эту функцию функцией таймера). Этот параметр необходимо обязательно указать, если первый параметр функции SetTimer равен NULL.
Тип TIMERPROC описан в файле windows.h следующим образом:
typedef void (CALLBACK* TIMERPROC)(HWND hwnd, UINT msg, UINT idTimer, DWORD dwTime);
Сравните это с описанием типа WNDPROC, который используется для знакомой вам функции окна:
typedef LRESULT (CALLBACK* WNDPROC) (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
Как видно из описания, функция таймера не возвращает никакого значения, имеет другие (по сравнению с функцией окна) параметры, но описана с тем же ключевым словом CALLBACK:
#define CALLBACK _far _pascal
Возвращаемое функцией SetTimer значение является идентификатором созданного таймера (если в качестве первого параметра функции было указано значение NULL). В любом случае функция SetTimer возвращает нулевое значение, если она не смогла создать таймер. В Windows версии 3.0 максимальное количество созданных во всей системе таймеров было 16. Для Windows версии 3.1 это ограничение снято.
Тем не менее, если приложение больше не нуждается в услугах таймера, оно должно уничтожить таймер, вызвав функцию KillTimer:
BOOL WINAPI KillTimer (HWND hwnd, UINT idTimer);
Первый параметр функции (hwnd) определяет идентификатор окна, указанный при создании таймера функцией SetTimer.
Второй параметр (idTimer) — идентификатор уничтожаемого таймера. Это должен быть либо тот идентификатор, который вы указали при создании таймера (если таймер создавался для окна), либо значение, полученное при создании таймера от функции SetTimer (для таймера, имеющего собственную функцию обработки сообщений).
Функция KillTimer возвращает значение TRUE при успешном уничтожении таймера или FALSE, если она не смогла найти таймер с указанным идентификатором.
Сообщение WM_TIMER
Параметр wParam сообщения WM_TIMER содержит идентификатор таймера, который был указан или получен от функции SetTimer при создании таймера.
С помощью параметра lParam можно определить адрес функции, которая обрабатывает сообщения таймера.
После обработки этого сообщения приложение должно возвратить нулевое значение.
Заметим, что сообщение WM_TIMER является низкоприоритетным. Это означает, что функция DispatchMessage посылает это сообщение приложению только в том случае, если в очереди приложения нет других сообщений. В этом отличие таймера Windows от аналогичных средств MS-DOS, реализованных с помощью перехвата прерывания INT 8h.
Выполнение программы MS-DOS прерывается синхронно с приходом аппаратного прерывания таймера и программа MS-DOS, перехватившая это прерывание, немедленно оповещается о нем. Выполнение приложения Windows тоже, разумеется, прерывается по аппаратному прерыванию таймера, но оповещение об этом событии приходит не всегда, и как правило, позже, вместе с сообщением WM_TIMER.
Первый способ использования таймера
В этом разделе мы рассмотрим первый способ работы с таймером — подключение таймера к окну. В этом случае функция окна, к которому подключен таймер, будет получать сообщения от таймера с кодом WM_TIMER.
Этот способ самый простой. Вначале вам надо вызывать функцию SetTimer, указав ей в качестве параметров идентификатор окна, идентификатор таймера и период, с которым от таймера должны приходить сообщения:
#define FIRST_TIMER 1 int nTimerID; nTimerID = SetTimer(hwnd, FIRST_TIMER, 1000, NULL);
В данном примере создается таймер с идентификатором FIRST_TIMER, который будет посылать сообщения примерно раз в секунду.
Для уничтожения таймера, созданного этим способом, следует вызвать функцию KillTimer, указав параметры следующим образом:
KillTimer(hwnd, FIRST_TIMER);
Для изменения интервала посылки сообщений вам следует вначале уничтожить таймер, а потом создать новый, работающий с другим периодом времени:
KillTimer(hwnd, FIRST_TIMER); nTimerID = SetTimer(hwnd, FIRST_TIMER, 100, NULL);
Второй способ использования таймера
Второй способ работы с таймером заключается в использовании для таймера специальной функции, которая будет получать сообщения WM_TIMER. Эта функция является функцией обратного вызова, определяется с ключевым словом _export и, так же как и функция окна, имеет специальный пролог и эпилог:
void CALLBACK _export TimerProc(HWND hwnd, UINT msg, UINT idTimer, DWORD dwTime);
Как и для функции окна, для функции таймера можно выбрать любое имя. При создании таймера вам надо указать адрес функции таймера, а имя не имеет никакого значения.
Первый параметр функции таймера — идентификатор окна, с которым связан таймер. Если при создании таймера в качестве идентификатора было указано значение NULL, это же значение будет передано функции таймера.
Второй параметр представляет собой идентификатор сообщения WM_TIMER.
Третий параметр является идентификатором таймера, пославшего сообщение WM_TIMER.
И наконец, последний параметр — текущее время по системным часам компьютера. Это время выражается в количестве тиков таймера с момента запуска Windows. Вы можете узнать текущее системное время в любой момент, если воспользуетесь функцией GetCurrentTime или GetTickCount:
DWORD WINAPI GetCurrentTime(void); DWORD WINAPI GetTickCount(void);
Эти функции совершенно аналогичны, однако название функции GetTickCount более точно отражает выполняемое ей действие.
Если для создания приложения вы пользуетесь современными средствами разработки, такими, как Borland C++ версии 3.1, Microsoft С++ версии 7.0, Microsoft Visual C++, для определения функции обратного вызова достаточно использовать ключевое слово _export. В этом случае вы можете создать таймер, например, так:
nTimerID = SetTimer(hwnd, 0, 1000, (TIMERPROC)TimerProc);
Для удаления таймера в этом случае необходимо использовать идентификатор, возвращенный функцией SetTimer:
KillTimer(hwnd, nTimerID );
Если же используемые вами средства разработки не позволяют указать ключевое слово _export, для подключения функции таймера придется использовать более сложный способ.
Когда вы не можете ограничиться использованием ключевого слова _export, для работы с функциями обратного вызова нужно сделать специальный переходник (thunk), вызвав функцию MakeProcInstance:
FARPROC WINAPI MakeProcInstance(FARPROC lpProc, HINSTANCE hinst);
В качестве первого параметра функции (lpProc) необходимо передать адрес функции, для которой создается переходник, а в качестве второго (hinst) — идентификатор приложения hInstance, полученный функцией WinMain при запуске приложения.
Функция MakeProcInstance для указанной функции создает функцию-переходник, возвращая ее адрес, а также обеспечивает функции доступ к сегменту данных приложения, загружая соответствующим образом сегментные регистры.
Процедура создания таймера с использованием функции MakeProcInstance может выглядеть следующим образом:
TIMERPROC lpfnTimerProc; lpfnTimerProc = (TIMERPROC)MakeProcInstance( (FARPROC)TimerProc, hInstance); nTimerID = SetTimer(hwnd, 0, 1000, (TIMERPROC)lpfnTimerProc);
После уничтожения таймера следует уничтожить созданный функцией MakeProcInstance переходник, для чего следует вызвать функцию FreeProcInstance:
void WINAPI FreeProcInstance(FARPROC lpProc);
Этой функции необходимо передать адрес уничтожаемой функции-переходника:
FreeProcInstance(lpfnTimerProc);
Функции MakeProcInstance и FreeProcInstance можно использовать совместно с современными средствами разработки, понимающими ключевое слово _export. Это не приведет к неправильной работе приложения.
Старые средства разработки приложений Windows требуют, чтобы все функции обратного вызова, такие, как функции окон и функции таймеров, были описаны в файле определения модуля, имеющем расширение .def, при помощи оператора EXPORTS, например:
EXPORTS WndProc TimerProc
Транслятор Borland C++ версии 3.1 распознает ключевое слово _export и автоматически формирует нужный пролог и эпилог для функций обратного вызова. То же самое относится и к трансляторам Microsoft C++ версии 7.0 и Microsoft Visual C++. Поэтому в наших примерах функции MakeProcInstance и FreeProcInstance, а также оператор файла определения модуля EXPORTS не используются.
sp_lab2
2 ОБРАБОТКА СООБЩЕНИЙ WINDOWS. 2.1 Цель работы Изучить механизмы передачи сообщений в ОС windows. Получить практические навыки обработки сообщений от клавиатуры, мыши и таймера. 2.2 Теоретические сведения 2.2.1 Синхронизация событий клавиатуры Приложение «узнает» о нажатиях клавиш посредством сообщений, которые посылаются оконной функции. Когда пользователь нажимает и отпускает клавиши, драйвер клавиатуры передает информацию о нажатии клавиш в Windows. Windows сохраняет эту информацию (в виде сообщений) в системной очереди сообщений. Затем она передает сообщения клавиатуры, по одному за раз, в очередь сообщений программы, содержащей окно, имеющее фокус ввода (input focus). Программа, в свою очередь, отправляет сообщения соответствующей оконной функции с помощью функции DispatchMessage(). Если пользователь печатает на клавиатуре быстрее, чем программа может обрабатывать поступающую информацию, Windows сохраняет информацию о дополнительных нажатиях клавиш в системной очереди сообщений, поскольку одно из дополнительных нажатий может быть переключением фокуса ввода на другую программу. Затем информация о последующих нажатиях направляется в другую программу, таким образом Windows корректно синхронизирует события клавиатуры. Приложению не нужно отслеживать все нажатия клавиш, потому, что Windows извещает программу об эффекте, вызванном их нажатием. Например, когда пользователь выбирает пункт меню, Windows посылает программе сообщение, что выбран пункт меню, независимо от того, был ли он выбран с помощью мыши или клавиатуры. В окнах диалога и внутри окон верхнего уровня могут содержаться окна редактирования (edit) для ввода текста (это окна, в которых пользователь набирает строки символов). Windows управляет всей логикой окон редактирования и дает программе окончательное содержимое этих окон, после того, как пользователь завершит ввод текста. 2.2.2 Категории клавиатурных сообщений Сообщения, которые приложение получает от Windows о событиях от клавиатуры, различаются на аппаратные и символьные. Такое положение соответствует двум представлениям о клавиатуре. Во-первых, клавиатуру можно считать набором клавиш. В клавиатуре имеется только одна клавиша «A». Нажатие на эту клавишу является аппаратным событием, отпускание этой клавиши является аппаратным событием. Во-вторых, клавиатура также является устройством ввода, которое генерирует отображаемые символы.
Клавиша «A», в зависимости от состояния клавиш «Ctrl», «Shift» и «CapsLock», может стать источником нескольких символов. Обычно, этим сомволом является строчная «a». Если же нажата клавиша «Shift» или установлен режим «CapsLock», то этим символом является прописная «A». Если нажата клавиша «Ctrl», этим символом является «Ctrl+A». Для сочетаний двух аппаратных событий, которые генерируют отображаемые символы, Windows посылает программе оба аппаратных и одно символьное сообщение. Некоторые клавиши не генерируют символов. Это клавиши переключения, функциональные клавиши, клавиши управления курсором и специальные клавиши, такие как «Insert» и «Delete». Для таких клавиш Windows генерирует только аппаратные сообщения. 2.2.3 Аппаратные сообщения Когда пользователь нажимает клавишу, Windows помещает сообщение WM_KEYDOWN, либо сообщение WM_SYSKEYDOWN в очередь сообщений окна, имеющего фокус ввода. Когда клавиша отпускается, Windows помещает в очередь сообщение WM_KEYUP, либо сообщение WM_SYSKEYUP. Несистемные аппаратные сообщения: WM_KEYDOWN, WM_KEYUP Cистемные аппаратные сообщения: WM_SYSKEYDOWN, WM_SYSKEYUP Системные аппаратные сообщения WM_SYSKEYDOWN и WM_SYSKEYUP более важны для Windows, чем для приложений. Эти сообщения генерируются при нажатии клавиш в сочетании с клавишей «Alt» и вызывают опции меню программы или системного меню, или используются для системных функций, таких как смена активного приложения («Alt+Tab»). Программы обычно игнорируют сообщения WM_SYSKEYDOWN и WM_SYSKEYUP и передают их в функцию DefWindowProc(). Оконная функция, получает другие сообщения, которые являются результатом этих аппаратных сообщений клавиатуры (например, выбор меню). При необходимости включить в текст программы инструкции для обработки системных аппаратных сообщений клавиатуры следует после обработки этих сообщений передать их в функцию DefWindowProc(), чтобы Windows могла по-прежнему их использовать в обычных целях: Несистемные сообщения WM_KEYDOWN и WM_KEYUP обычно генерируются для клавиш, которые нажимаются и отпускаются без участия клавиши «Alt». Обычно сообщения о нажатии и отпускании появляются парами. Однако если пользователь оставит клавишу нажатой так, чтобы включился автоповтор, то Windows посылает оконной функции серию сообщений WM_KEYDOWN и одно сообщение WM_KEYUP, когда клавиша будет отпущена. Ниже приведен фрагмент оконной функции, который обрабатывает нажатие клавиш:
case WM_KEYDOWN: MessageBox(hWnd, «Message WM_KEYDOWN» , «Key» , MB_OK); break ; case WM_KEYUP: MessageBox(hWnd, «Message WM_KEYUP» , «Key» , MB_OK); break ; Для всех аппаратных сообщений клавиатуры параметр wParam содержит код виртуальной клавиши, соответствующей нажатой клавише. Код виртуальной клавиши не зависит от аппаратной реализации клавиатуры. Коды виртуальных клавиш имеют символьные обозначения, определенные в заголовочных файлах Windows, и имеют префикс VK_. Параметры wParam и lParam аппаратных сообщений клавиатуры ничего не сообщают о состоянии клавиш «Shift», «Ctrl», «Alt» и клавишпереключателей «CapsLock», «NumLock», «ScrollLock». Приложение может получить текущее состояние любой виртуальной клавиши с помощью функции GetKeyState(). Функция GetKeyState() не отражает состояние клавиатуры в реальном времени и возвращает состояние клавиши на момент, прихода сообщения. Функция GetKeyState() не позволяет получать информацию о клавиатуре независимо сообщений. Программе необходимо получить сообщение от клавиатуры до вызова функции GetKeyState(). Если старший бит возвращаемого значения равен 1 — клавиша нажата если равен 0 — клавиша отпущена. Если младший бит равен 1 — клавиша включена если равен 0 отключена. Информацию о текущем положении клавиши можно получить при помощи функции GetAsyncKeyState(). Ниже приведен фрагмент оконной функции, в котором обрабатываются нажатия комбинаций клавиш «Shift»+«Space» и «Ctrl»+«F1»: case WM_KEYDOWN: < int v_key = ( int ) wParam; // Код виртуальной клавиши switch (v_key) < // Нажатие клавиши Space (пробел) case VK_SPACE: // Состояние на момент события if (GetKeyState(VK_SHIFT)<0)< >MessageBox(hWnd, «» , «» , MB_OK); break ; // Нажатие клавиши F1 для определения case VK_F1: // Текущее состояние if (GetAsyncKeyState(VK_CONTROL) <0)< >MessageBox(hWnd, «» , «» , MB_OK); > break ; break ; >
проходит через ее окно, и при щелчке внутри окна, даже если окно не активно или не имеет фокуса ввода. Если мышь перемещается по рабочей области окна, оконная функция получает сообщение WM_MOUSEMOVE. Если кнопка мыши нажимается или отпускается внутри рабочей области окна, оконная функция получает следующие сообщения: Таблица 1 — Сообщения м ыши
| Нажатие | Отпускание | Двойное нажатие |
| (Double click) | ||
| WM_LBUTTONDOWN | WM_LBUTTONUP | WM_LBUTTONDBLCLK |
| WM_RBUTTONDOWN | WM_RBUTTONUP | WM_RBUTTONDBLCLK |
| WM_MBUTTONDOWN | WM_MBUTTONUP | WM_MBUTTONDBLCLK |
Для всех сообщений, связанных с рабочей областью, значение параметра lParam содержит координаты мыши относительно верхнего левого угла рабочей области окна. Младшее слово – это координата Х, а старшее – координата Y Координаты X и Y можно извлечь из параметра lParam с помощью макросов LOWORD и HIWORD. Значение параметра wParam показывает состояние кнопок мыши и клавиш «Shift», «Ctrl». Параметр wParam можно проверить с помощью битовых масок, определенных в заголовочных файлах:
| MK_LBUTTON | – левая кнопка нажата |
| MK_RBUTTON | – правая кнопка нажата |
| MK_MBUTTON | – средняя кнопка нажата |
| MK_SHIFT | – клавиша «Shift» нажата |
| MK_CONTROL | – клавиша «Ctrl» нажата |
В следующем фрагменте оконной функции показана обработка сообщения WM_MOUSEMOVE и состояния правой кнопки мыши. При движении мыши с нажатой правой кнопкой программа должна выводить пикселы в рабочей области окна непосредственно под курсором мыши.
| case WM_MOUSEMOVE: | // | Cостояние кнопок мыши |
| UINT key_state = wParam; | ||
| int x_pos = LOWORD(lParam); // | Горизонтальная позиция курсора | |
| int y_pos = HIWORD(lParam); // | Вертикальная позиция курсора | |
| if (key_state & MK_RBUTTON) | ||
| HDC hDC=GetDC(hWnd); | 0); | |
| SetPixel(hDC, x_pos, y_pos, | ||
| ReleaseDC(hWnd, hDC); | ||
Обработка комбинаций клавиш типа «клавиатура+мышь» показана в следующем примере. Фрагмент программы обрабатывает нажатия «Shift»+«Rclick» и «Ctrl»+«Rclick» case WM_RBUTTONDOWN: < UINT key_state = wParam; // Состояние кнопок мыши if (key_state & MK_SHIFT)< >MessageBox(hWnd, «
необходимо произвести захват мыши. Для захвата мыши используется функция SetCapture(). После вызова этой функции, Windows посылает все сообщения мыши в оконную функцию того окна, чей дескриптор окна был передан в функцию SetCapture(). Сообщения мыши в захваченном состоянии всегда остаются сообщениями рабочей области, даже если мышь оказывается за пределами рабочей области окна. Параметр lParam содержит положение мыши в координатах рабочей области. Эти координаты, могут стать отрицательными, если мышь окажется левее или выше рабочей области. Освободить мышь, (возвратить обработку мыши в нормальный режим), можно при помощи функции ReleaseCapture(). 2.2.8 Использование таймера Таймер в является устройством ввода информации, которое периодически извещает приложение о том, что истек заданный интервал времени. Приложение сообщает системе Windows интервал времени, а затем Windows периодически посылает приложению сообщения WM_TIMER, сигнализируя об истечении временного интервала. Инициализировать таймер программе можно при помощи вызова функции SetTimer(). Функция SetTimer содержит параметр, задающий интервал в миллисекундах – это значение определяет период, с которым Windows посылает программе сообщения WM_TIMER. Для остановки потока сообщений от таймера необходимо вызвать функцию KillTimer(). Вызов KillTimer() очищает очередь сообщений от всех необработанных сообщений WM_TIMER. Сообщения таймера ставятся в очередь сообщений приложения и обрабатываются как все остальные сообщения. Поэтому, если приложение задает интервал 1000 миллисекунд, то не гарантируется получение сообщения каждую секунду (интервал будет колебаться). Если приложение занято больше чем секунду, то оно вообще может не получить ни одного сообщения WM_TIMER в течение этого времени. Таймер можно использовать одним из двух способов, в зависимости от параметров функции SetTimer(). Первый способ использования таймера заставляет Windows посылать сообщения WM_TIMER обычной оконной функции приложения. Вызов функции SetTimer() в этом случае обычно имеет вид: SetTimer(hWnd, 1, 1000, NULL); • первый параметр – дескриптор окна, которое будет получать сообщения WM_TIMER. • второй параметр — идентификатор таймера, значение которого должно быть отлично от нуля. (в примере он установлен в 1). Если приложению необходимо несколько таймеров, для каждого из них следует использовать свой идентификатор. • третий параметр – 32-разрядное беззнаковое целое, которое задает
интервал в миллисекундах (значение 1000 задает генерацию сообщений WM_TIMER один раз в секунду). Поток сообщений WM_TIMER можно в любое время остановить (даже во время обработки сообщения WM_TIMER), вызвав функцию: KillTimer(hWnd, 1); Вторым параметром является тот же идентификатор таймера, который использовался при вызове функции SetTimer(). Приложение должно уничтожить все активные таймеры перед завершением программы. Когда оконная функция получает сообщение WM_TIMER значение wParam равно значению идентификатора таймера. Значение параметра wParam позволяет различать сообщения WM_TIMER от различных таймеров. Следующий фрагмент оконной функции устанавливает таймер при создании окна (сообщение WM_CREATE), после чего программа начинает получать события WM_TIMER с интервалом 1 секунда. При закрытии окна (сообщение WM_DESTROY) таймер уничтожается. #define TIMER_ONE 1 case WM_CREATE: SetTimer(hWnd, TIMER_ONE, 1000, NULL); break ; case WM_TIMER:< UINT timer_id = wParam; static char mas[]= "0" ; if (mas[0]>= ‘9’ ) < mas[0] = '0' ; >else < >mas[0]++; HDC hDC = GetDC(hWnd); TextOut(hDC, 20, 40, mas, strlen(mas)); ReleaseDC(hWnd, hDC); break ; > case WM_DESTROY: KillTimer(hWnd, TIMER_ONE); PostQuitMessage(0); break ;
Второй способ использования таймера заставляет Windows пересылать сообщения другой функции этого же приложения. Функция, которая будет получать «таймерные» сообщения, называется функцией обратного вызова
(call-back). Это функция приложения, которую вызывает Windows. Приложение сообщает Windows адрес этой функции, а позже Windows вызывает ее с определенными параметрами. Функция обратного вызова должна определяться с идентификатором CALLBACK. В случае использования функции обратного вызова для таймера, входными параметрами являются те же параметры, что и параметры оконной ф. Общий вид функции таймера: void CALLBACK TimerProc(HWND hWnd, UINT iMsg, UINT iTimerID, DWORD dwTime) < // обработка сообщений WM_TIMER >∙ параметр hWnd – дескриптор окна, задаваемый при вызове функции SetTimer(). ∙ параметр iMsg всегда будет равен WM_TIMER, потому, что Windows будет посылать функции TimerProc только сообщения WM_TIMER. ∙ параметр iTimerID – идентификатор таймера. ∙ параметр dwTime – системное время. При использовании функции обратного вызова для обработки сообщений WM_TIMER, четвертый параметр функции SetTimer() заменяется адресом функции обратного вызова: SetTimer(hWnd, 1, 1000, (TIMERPROC)TimerProc); Пример использования функции обратного вызова для обработки сообщений от таймера. (Функцию TimerProc() можно разместить перед функцией WinMain()) void CALLBACK TimerProc(HWND hWnd, UINT iMsg, UINT iTimerID, DWORD dwTime)< static char mas[]= "0" ; if (mas[0]>= ‘9’ ) < mas[0] = '0' ; >else < >mas[0]++; > SetWindowText(hWnd, mas); #define TIMER_ONE 1 case WM_CREATE: SetTimer(hWnd, TIMER_ONE, 1000, (TIMERPROC)TimerProc); break ;
case WM_DESTROY: KillTimer(hWnd, TIMER_ONE); PostQuitMessage(0); break ; 2.3 Порядок выполнения работы На занятии выполните следующие учебные эксперименты: Написать программу которая создает стандартное окно windows. Текст программы приведен ниже. #include if (!hWnd) < // Окно не создано, отобразить предупреждение >MessageBox(NULL, «Create: error» , app_title, MB_OK|MB_ICONSTOP); return FALSE;
char class_name[] = «main_window» ; // Название класса окна
char app_title[] = «Simple window» ; // Заголовок главного окна
WNDCLASS wc; // Структура для информации о классе окна
HWND hWnd;
// Дескриптор главного окна приложения
MSG msg;
// Структура для хранения сообщения
// Заполнение структуры WNDCLASS для регистрации класса окна.
memset(&wc, 0, sizeof (wc));
// Заполнение структуры нулями
wc.lpszClassName = class_name;
// Имя класса окон
wc.lpfnWndProc = &WndProc;
// Адрес оконной функции
wc.style = CS_HREDRAW|CS_VREDRAW;
// Стиль класса окон
wc.hInstance = hInstance;
// Экземпляр приложения
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// Пиктограмма для окон
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// Курсор мыши для окон
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // Кисть для окон
wc.lpszMenuName = NULL;
// Ресурс меню окон
// Pегистрация класса окна
RegisterClass(&wc);
// Главное окно приложения
hWnd = CreateWindow(
//
Имя класса окон
class_name,
app_title,
//
Заголовок окна
WS_OVERLAPPEDWINDOW, //
Стиль окна
20,
//
X-координаты
20,
//
Y-координаты
500,
//
Ширина окна
400,
//
Высота окна
NULL,
//
Дескриптор родительского окна
NULL,
//
Дескриптор меню окна
hInstance,
//
Дескриптор экземпляра приложения
NULL);
//
Дополнительная информация
Характеристики окон
В этом обзоре рассматриваются функции окон, такие как типы окон, состояния, размер и положение.
- Типы окон
- Перекрывающиеся окна
- Всплывающие окна
- Дочерние окна
- Позиционирования
- Усечение
- Связь с родительским окном
- Сообщения
- Окна переднего плана и фона
- Собственные окна
- Z-порядок
- Активное окно
- Отключенные окна
- Видимость окна
- Свернутые, развернутые и восстановленные окна
- Размер и положение по умолчанию
- Размер отслеживания
- Системные команды
- Функции размера и положения
- Сообщения о размере и расположении
- Диалоговые окна зеркального отображения и окна сообщений
- Контексты зеркального отображения устройств, не связанные с окном
Типы окон
Этот раздел содержит следующие разделы, описывающие типы окон.
- Перекрывающиеся окна
- Всплывающие окна
- Дочерние окна
- Многоуровневые окна
- Окна только для сообщений
Перекрывающиеся окна
Перекрывающееся окно — это окно верхнего уровня (не дочернее окно), которое имеет строку заголовка, границу и клиентную область; он служит окном main приложения. Он также может иметь меню окна, кнопки свернуть и развернуть, а также полосы прокрутки. Перекрывающееся окно, используемое в качестве окна main, обычно включает все эти компоненты.
Задав стиль WS_OVERLAPPED или WS_OVERLAPPEDWINDOW в функции CreateWindowEx , приложение создает перекрывающееся окно. Если вы используете стиль WS_OVERLAPPED , окно имеет строку заголовка и границу. Если вы используете стиль WS_OVERLAPPEDWINDOW , окно имеет заголовок окна, границу размера, меню окна, а также кнопки свернуть и развернуть.
Всплывающие окна
Всплывающее окно — это особый тип перекрывающихся окон, используемый для диалоговых окон, окон сообщений и других временных окон, которые отображаются за пределами окна main приложения. Заголовки являются необязательными для всплывающих окон; В противном случае всплывающие окна совпадают с перекрывающимися окнами стиля WS_OVERLAPPED .
Чтобы создать всплывающее окно, укажите стиль WS_POPUP в createWindowEx. Чтобы включить строку заголовка, укажите стиль WS_CAPTION . Используйте стиль WS_POPUPWINDOW для создания всплывающего окна с границей и меню окна. Стиль WS_CAPTION должен сочетаться со стилем WS_POPUPWINDOW , чтобы сделать меню окна видимым.
Дочерние окна
Дочернее окно имеет стиль WS_CHILD и ограничивается клиентской областью родительского окна. Приложение обычно использует дочерние окна для разделения клиентской области родительского окна на функциональные области. Чтобы создать дочернее окно, укажите стиль WS_CHILD в функции CreateWindowEx .
Дочернее окно должно иметь родительское окно. Родительским окном может быть перекрывающееся окно, всплывающее окно или даже другое дочернее окно. Родительское окно указывается при вызове CreateWindowEx. Если указать стиль WS_CHILD в CreateWindowEx , но не указать родительское окно, система не создаст окно.
В дочернем окне есть клиентская область, но нет других функций, если они не запрашиваются явным образом. Приложение может запросить заголовок окна, меню окна, кнопки свернуть и развернуть, границу и полосы прокрутки для дочернего окна, но в дочернем окне не может быть меню. Если приложение указывает дескриптор меню при регистрации класса дочернего окна или создает дочернее окно, дескриптор меню игнорируется. Если стиль границы не указан, система создает окно без границ. Приложение может использовать дочерние окна без границ, чтобы разделить клиентскую область родительского окна, сохраняя при этом невидимые для пользователя деления.
В этом разделе рассматриваются следующие аспекты дочерних окон:
- Позиционирования
- Усечение
- Связь с родительским окном
- Сообщения
Позиционирования
Система всегда размещает дочернее окно относительно левого верхнего угла клиентской области родительского окна. Никакая часть дочернего окна никогда не отображается за пределами его родительского окна. Если приложение создает дочернее окно, которое больше родительского окна, или размещает дочернее окно таким образом, чтобы некоторые или все дочерние окна выходят за границы родительского окна, система обрезает дочернее окно; то есть часть за пределами клиентской области родительского окна не отображается. Действия, влияющие на родительское окно, также могут повлиять на дочернее окно, как показано ниже.
Родительское окно Дочернее окно Уничтожаются Удаляется перед уничтожением родительского окна. Скрытый Скрытые перед скрытием родительского окна. Дочернее окно отображается только в том случае, если отображается родительское окно. Переехал Перемещается вместе с клиентской областью родительского окна. Дочернее окно отвечает за рисование клиентской области после перемещения. Показано Отображается после отображения родительского окна. Усечение
Система не автоматически обрезает дочернее окно из клиентской области родительского окна. Это означает, что родительское окно выполняет рисование поверх дочернего окна, если оно выполняет рисование в том же расположении, что и дочернее окно. Однако система обрезает дочернее окно из клиентской области родительского окна, если родительское окно имеет стиль WS_CLIPCHILDREN . Если дочернее окно обрезано, родительское окно не может нарисовать его.
Дочернее окно может перекрывать другие дочерние окна в той же клиентской области. Дочернее окно, которое использует то же родительское окно, что и одно или несколько других дочерних окон, называется одноуровневым окном. Одноуровневые окна могут рисовать в клиентской области друг друга, если только одно из дочерних окон не имеет стиля WS_CLIPSIBLINGS . Если дочернее окно имеет этот стиль, любая часть его одноуровневого окна, расположенная в дочернем окне, обрезается.
Если окно имеет стиль WS_CLIPCHILDREN или WS_CLIPSIBLINGS , происходит небольшое снижение производительности. Каждое окно занимает системные ресурсы, поэтому приложение не должно использовать дочерние окна без разбора. Для обеспечения оптимальной производительности приложение, которому необходимо логически разделить main окно, должно сделать это в процедуре окна main, а не с помощью дочерних окон.
Связь с родительским окном
Приложение может изменить родительское окно существующего дочернего окна, вызвав функцию SetParent . В этом случае система удаляет дочернее окно из клиентской области старого родительского окна и перемещает его в клиентскую область нового родительского окна. Если SetParent указывает дескриптор NULL , окно рабочего стола становится новым родительским окном. В этом случае дочернее окно отрисовывается на рабочем столе за пределами любого другого окна. Функция GetParent извлекает дескриптор родительского окна дочернего окна.
Родительское окно возвращает часть клиентской области дочернему окну, а дочернее окно получает все входные данные из этой области. Класс окна не обязательно должен быть одинаковым для каждого из дочерних окон родительского окна. Это означает, что приложение может заполнить родительское окно дочерними окнами, которые выглядят по-разному и выполняют различные задачи. Например, диалоговое окно может содержать множество типов элементов управления, каждый из которых является дочерним окном, которое принимает различные типы данных от пользователя.
Дочернее окно имеет только одно родительское окно, но родительское может иметь любое количество дочерних окон. Каждое дочернее окно, в свою очередь, может иметь дочерние окна. В этой цепочке окон каждое дочернее окно называется потомком исходного родительского окна. Приложение использует функцию IsChild , чтобы определить, является ли данное окно дочерним окном или окном-потомком данного родительского окна.
Функция EnumChildWindows перечисляет дочерние окна родительского окна. Затем EnumChildWindows передает дескриптор каждому дочернему окну в определяемую приложением функцию обратного вызова. Также перечисляются дочерние окна заданного родительского окна.
Сообщения
Система передает входные сообщения дочернего окна непосредственно в дочернее окно; сообщения не передаются через родительское окно. Единственное исключение — если дочернее окно было отключено функцией EnableWindow . В этом случае система передает все входные сообщения, которые ушли бы в дочернее окно, в родительское окно. Это позволяет родительскому окну проверять входные сообщения и при необходимости включать дочернее окно.
Дочернее окно может иметь уникальный целочисленный идентификатор. Идентификаторы дочерних окон важны при работе с окнами управления. Приложение направляет действие элемента управления, отправляя ему сообщения. Приложение использует идентификатор дочернего окна элемента управления для направления сообщений в элемент управления . Кроме того, элемент управления отправляет уведомления в родительское окно. Сообщение уведомления содержит идентификатор дочернего окна элемента управления, который родительский элемент использует для определения того, какой элемент управления отправил сообщение. Приложение задает идентификатор дочернего окна для других типов дочерних окон, задавая для параметра hMenu функции CreateWindowEx значение, а не дескриптор меню.
Многоуровневые окна
Многослойное окно может значительно повысить производительность и визуальные эффекты для окна, которое имеет сложную форму, анимирует его форму или хочет использовать эффекты альфа-смешения. Система автоматически создает и перерисовывает многоуровневые окна и окна базовых приложений. В результате многослойные окна отрисовываются плавно, без мерцания, типичного для сложных оконных областей. Кроме того, многослойные окна могут быть частично полупрозрачными, то есть альфа-смешанными.
Чтобы создать многоуровневое окно, укажите стиль расширенного окна WS_EX_LAYERED при вызове функции CreateWindowEx или вызовите функцию SetWindowLong , чтобы задать WS_EX_LAYERED после создания окна. После вызова CreateWindowEx многоуровневые окна не станут видимыми, пока для этого окна не будет вызвана функция SetLayeredWindowAttributes или UpdateLayeredWindow .
Начиная с Windows 8, WS_EX_LAYERED можно использовать с дочерними окнами и окнами верхнего уровня. Предыдущие версии Windows поддерживают WS_EX_LAYERED только для окон верхнего уровня.
Чтобы задать уровень непрозрачности или ключ цвета прозрачности для заданного многоуровневого окна, вызовите SetLayeredWindowAttributes. После вызова система по-прежнему может попросить окно закрасить при отображении окна или изменении его размера. Тем не менее, так как система хранит изображение многоуровневого окна, система не будет просить окно рисовать, если его части отображаются в результате относительного перемещения окна на рабочем столе. Устаревшим приложениям не нужно реструктурировать свой код рисования, если они хотят добавить эффекты прозрачности или прозрачности для окна, так как система перенаправляет рисование окон с именем SetLayeredWindowAttributes в память вне экрана и повторно компилирует его для достижения желаемого эффекта.
Для более быстрой и эффективной анимации или, если требуется альфа-канал для каждого пикселя, вызовите UpdateLayeredWindow. UpdateLayeredWindow следует использовать в основном в том случае, если приложение должно напрямую предоставлять форму и содержимое многоуровневого окна, не используя механизм перенаправления, который система предоставляет через SetLayeredWindowAttributes. Кроме того, использование UpdateLayeredWindow напрямую использует память более эффективно, так как системе не требуется дополнительная память, необходимая для хранения образа перенаправленного окна. Для максимальной эффективности анимации окон вызовите UpdateLayeredWindow , чтобы изменить положение и размер многоуровневого окна. Обратите внимание, что после вызова SetLayeredWindowAttributes последующие вызовыUpdateLayeredWindow завершатся ошибкой, пока бит стиля слоев не будет очищен и не будет снова задан.
Проверка попадания многослойного окна основана на форме и прозрачности окна. Это означает, что области окна с цветовой клавишей или альфа-значение которых равно нулю, будут пропускать сообщения мыши. Однако если многослойное окно имеет WS_EX_TRANSPARENT расширенный стиль окна, форма многослойного окна будет игнорироваться, а события мыши будут передаваться в другие окна под многослойным окном.
Message-Only Windows
Окно только для сообщений позволяет отправлять и получать сообщения. Он невидим, не имеет z-порядка, не может быть перечислен и не получает широковещательные сообщения. Окно просто отправляет сообщения.
Чтобы создать окно только для сообщений, укажите константу HWND_MESSAGE или дескриптор существующего окна только для сообщений в параметре hWndParent функции CreateWindowEx . Вы также можете изменить существующее окно на окно только для сообщений, указав HWND_MESSAGE в параметре hWndNewParent функции SetParent .
Чтобы найти окна только для сообщений, укажите HWND_MESSAGE в параметре hwndParent функции FindWindowEx . Кроме того, FindWindowEx выполняет поиск окон только для сообщений, а также окон верхнего уровня, если параметры hwndParent и hwndChildAfter имеют значение NULL.
Связи окон
Существует множество способов связи окна с пользователем или другим окном. Окно может быть собственным окном, окном переднего плана или фоновым окном. Окно также имеет Z-порядок относительно других окон. Дополнительные сведения см. в следующих разделах:
- Окна переднего плана и фона
- Принадлежащие windows
- Z-order
Окна переднего плана и фона
Каждый процесс может иметь несколько потоков выполнения, и каждый поток может создавать окна. Поток, создавший окно, с которым в данный момент работает пользователь, называется потоком переднего плана, а окно — окном переднего плана. Все остальные потоки являются фоновыми потоками, а окна, созданные фоновыми потоками, называются фоновыми окнами.
Каждый поток имеет уровень приоритета, который определяет количество времени ЦП, которое поток получает. Хотя приложение может задать уровень приоритета своих потоков, обычно поток переднего плана имеет несколько более высокий уровень приоритета, чем фоновые потоки. Так как он имеет более высокий приоритет, поток переднего плана получает больше времени ЦП, чем фоновые потоки. Поток переднего плана имеет обычный базовый приоритет 9; фоновый поток имеет обычный базовый приоритет 7.
Пользователь задает окно переднего плана, щелкнув окно или используя сочетание клавиш ALT+TAB или ALT+ESC. Чтобы получить дескриптор в окне переднего плана, используйте функцию GetForegroundWindow . Чтобы проверка, является ли окно приложения окном переднего плана, сравните дескриптор, возвращенный Командлетом GetForegroundWindow, с дескриптором окна приложения.
Приложение задает окно переднего плана с помощью функции SetForegroundWindow .
Система ограничивает, какие процессы могут задавать окно переднего плана. Процесс может задать окно переднего плана только в следующих случаях:
- Выполняются все следующие условия:
- Процесс, вызывающий SetForegroundWindow, принадлежит классическому приложению, а не приложению UWP или приложению Магазина Windows, предназначенному для Windows 8 или 8.1.
- Процесс переднего плана не отключал вызовы SetForegroundWindow предыдущим вызовом функции LockSetForegroundWindow .
- Истекло время ожидания блокировки переднего плана (см . SPI_GETFOREGROUNDLOCKTIMEOUT в SystemParametersInfo).
- Меню не активны.
- Вызывающий процесс является процессом переднего плана.
- Вызывающий процесс был запущен процессом переднего плана.
- В настоящее время отсутствует окно переднего плана и, следовательно, процесс переднего плана.
- Вызывающий процесс получил последнее входное событие.
- Выполняется отладка процесса переднего плана или вызывающего процесса.
Процесс может быть лишен права на настройку окна переднего плана, даже если он соответствует этим условиям.
Процесс, который может задать окно переднего плана, может позволить другому процессу задать окно переднего плана путем вызова функции AllowSetForegroundWindow или путем вызова функции BroadcastSystemMessage с флагом BSF_ALLOWSFW . Процесс переднего плана может отключить вызовы SetForegroundWindow , вызвав функцию LockSetForegroundWindow .
Принадлежащие windows
Перекрывающееся или всплывающее окно может принадлежать другому перекрывающимся или всплывающему окну. Владение устанавливает несколько ограничений на окно.
- Принадлежащего окну всегда находится выше владельца в Z-порядке.
- Система автоматически уничтожает принадлежащего окну при уничтожении его владельца.
- Собственное окно скрывается, когда его владелец свернут.
Только перекрывающееся или всплывающее окно может быть окном-владельцем; дочернее окно не может быть окном-владельцем. Приложение создает собственное окно, указывая дескриптор окна владельца в качестве параметра hwndParentcreateWindowEx при создании окна со стилем WS_OVERLAPPED или WS_POPUP . Параметр hwndParent должен идентифицировать перекрывающееся или всплывающее окно. Если hwndParent определяет дочернее окно, система назначает права владения родительскому окну верхнего уровня дочернего окна. После создания собственного окна приложение не может передать права владения окном другому окну.
Диалоговые окна и окна сообщений являются собственными окнами по умолчанию. Приложение указывает окно владельца при вызове функции, которая создает диалоговое окно или окно сообщения.
Приложение может использовать функцию GetWindow с флагом GW_OWNER , чтобы получить дескриптор владельцу окна.
Z-порядок
Z-порядок окна указывает положение окна в стеке перекрывающихся окон. Этот стек окон ориентирован вдоль воображаемой оси, оси Z, простирающейся наружу от экрана. Окно, находящееся в верхней части z-порядка, перекрывает все остальные окна. Окно в нижней части z-порядка перекрывается всеми остальными окнами.
Система поддерживает z-порядок в одном списке. Он добавляет окна в Z-порядок в зависимости от того, являются ли они самыми верхними окнами, окнами верхнего уровня или дочерними окнами. Самое верхнее окно перекрывает все остальные окна, не являющиеся самыми верхними, независимо от того, является ли это активным окном или окном переднего плана. Самое верхнее окно имеет стиль WS_EX_TOPMOST . Все самые верхние окна отображаются в z-порядке перед любыми окнами, не являющиеся самыми верхними. Дочернее окно группируется с родительским окном в Z-порядке.
Когда приложение создает окно, система помещает его в начало z-порядка для окон того же типа. Вы можете использовать функцию BringWindowToTop , чтобы переместить окно в верхнюю часть z-порядка для окон того же типа. Вы можете изменить порядок z-порядка с помощью функций SetWindowPos и DeferWindowPos .
Пользователь изменяет z-порядок, активируя другое окно. Система размещает активное окно в верхней части z-порядка для окон того же типа. Когда окно попадает в верхнюю часть z-порядка, то и его дочерние окна. Функцию GetTopWindow можно использовать для поиска во всех дочерних окнах родительского окна и возврата дескриптора дочернему окну, который является самым высоким в Z-порядке. Функция GetNextWindow извлекает дескриптор следующего или предыдущего окна в z-порядке.
Отображение состояния окна
В любой момент времени окно может быть активным или неактивным; скрытые или видимые; и свернутые, развернутые или восстановленные. Эти качества в совокупности называются состоянием отображения окна. В следующих разделах рассматривается состояние отображения окна.
- Активное окно
- Отключенные окна
- Видимость окна
- Свернутые, развернутые и восстановленные окна
Активное окно
Активное окно — это окно верхнего уровня приложения, с которым в данный момент работает пользователь. Чтобы пользователь легко идентифицировать активное окно, система помещает его в верхнюю часть Z-порядка и изменяет цвет его заголовка и границы на определенные системой цвета активных окон. Только окно верхнего уровня может быть активным окном. Когда пользователь работает с дочерним окном, система активирует родительское окно верхнего уровня, связанное с дочерним окном.
Одновременно активируется только одно окно верхнего уровня в системе. Пользователь активирует окно верхнего уровня, щелкнув его (или одно из его дочерних окон) или используя сочетание клавиш ALT+ESC или ALT+TAB. Приложение активирует окно верхнего уровня, вызывая функцию SetActiveWindow . Другие функции могут привести к активации системы другого окна верхнего уровня, включая SetWindowPos, DeferWindowPos, SetWindowPlacement и DestroyWindow. Хотя приложение может активировать другое окно верхнего уровня в любое время, чтобы избежать путаницы пользователя, оно должно делать это только в ответ на действия пользователя. Приложение использует функцию GetActiveWindow для получения дескриптора в активное окно.
Когда активация изменяется из окна верхнего уровня одного приложения в окно верхнего уровня другого, система отправляет WM_ACTIVATEAPP сообщение обоим приложениям, уведомляя их об изменении. Когда активация меняется на другое окно верхнего уровня в том же приложении, система отправляет обоим окнам WM_ACTIVATE сообщение.
Отключенные окна
Окно можно отключить. Отключенное окно не получает ввода с клавиатуры или мыши от пользователя, но оно может получать сообщения из других окон, из других приложений и системы. Приложение обычно отключает окно, чтобы запретить пользователю использовать его. Например, приложение может отключить кнопку в диалоговом окне, чтобы запретить пользователю выбрать ее. Приложение может включить отключенное окно в любое время; Включение окна восстанавливает обычные входные данные.
По умолчанию окно включено при создании. Однако приложение может указать стиль WS_DISABLED , чтобы отключить новое окно. Приложение включает или отключает существующее окно с помощью функции EnableWindow . Система отправляет сообщение WM_ENABLE в окно, когда состояние включенной функции изменится. Приложение может определить, включено ли окно, с помощью функции IsWindowEnabled .
Когда дочернее окно отключено, система передает в родительское окно сообщения о входе с помощью мыши. Родительский объект использует сообщения, чтобы определить, следует ли включить дочернее окно. Дополнительные сведения см. в разделе Ввод с помощью мыши.
Только одно окно за раз может принимать ввод с клавиатуры; это окно, как говорят, имеет фокус клавиатуры. Если приложение отключает окно с фокусировкой клавиатуры с помощью функции EnableWindow , оно не только отключается, но и теряет фокус клавиатуры. Затем EnableWindow задает для фокуса клавиатуры значение NULL, что означает, что фокус отсутствует в окне. Если в дочернем окне или другом окне потомка есть фокус клавиатуры, то потомковое окно теряет фокус, когда родительское окно отключено. Дополнительные сведения см. в разделе Ввод с клавиатуры.
Видимость окна
Окно может быть видимым или скрытым. Система отображает видимое окно на экране. Он скрывает скрытое окно , не рисуя его. Если окно видимое, пользователь может производить ввод в окно и видеть вывод окна. Если окно скрыто, оно эффективно отключено. Скрытое окно может обрабатывать сообщения от системы или от других окон, но не может обрабатывать ввод от пользователя или отображать вывод. Приложение задает состояние видимости окна при создании окна. Позже приложение может изменить состояние видимости.
Окно отображается, когда для окна задан стиль WS_VISIBLE . По умолчанию функция CreateWindowEx создает скрытое окно, если приложение не задает стиль WS_VISIBLE . Как правило, приложение задает стиль WS_VISIBLE после создания окна, чтобы сведения о процессе создания были скрыты от пользователя. Например, приложение может скрывать новое окно, настраивая внешний вид окна. Если стиль WS_VISIBLE указан в createWindowEx, система отправляет сообщение WM_SHOWWINDOW в окно после создания окна, но перед его отображением.
Приложение может определить, отображается ли окно, с помощью функции IsWindowVisible . Приложение может отображать (делать видимым) или скрывать окно с помощью функции ShowWindow, SetWindowPos, DeferWindowPos, SetWindowPlacement или SetWindowLong . Эти функции показывают или скрывают окно, устанавливая или удаляя стиль WS_VISIBLE для окна. Они также отправляют сообщение WM_SHOWWINDOW в окно перед отображением или скрытием.
Если окно владельца свернуто, система автоматически скрывает связанные окна, принадлежащие ей. Аналогичным образом при восстановлении окна владельца система автоматически отображает связанные окна, принадлежащие ей. В обоих случаях система отправляет сообщение WM_SHOWWINDOW в собственные окна, прежде чем скрыть или показать их. Иногда приложению может потребоваться скрыть принадлежащие им окна, не сворачивая или не скрывая владельца. В этом случае приложение использует функцию ShowOwnedPopups . Эта функция задает или удаляет стиль WS_VISIBLE для всех принадлежащих окон и отправляет сообщение WM_SHOWWINDOW в принадлежащие окна перед их скрытием или отображением. Скрытие окна владельца не влияет на состояние видимости принадлежащих окон.
Когда отображается родительское окно, также отображаются связанные с ним дочерние окна. Аналогичным образом, когда родительское окно скрыто, его дочерние окна также скрыты. Минимизация родительского окна не влияет на состояние видимости дочерних окон; то есть дочерние окна свернуты вместе с родительским, но стиль WS_VISIBLE не изменяется.
Даже если окно имеет стиль WS_VISIBLE , пользователь может не видеть окно на экране; другие окна могут полностью перекрывать его или быть перемещены за пределы края экрана. Кроме того, к видимому дочернему окну применяются правила обрезки, установленные его отношением «родитель-потомок». Если родительское окно окна не отображается, оно также не будет видимым. Если родительское окно перемещается за край экрана, дочернее окно также перемещается, так как дочернее окно рисуется относительно левого верхнего угла родительского элемента. Например, пользователь может переместить родительское окно, содержащее дочернее окно, достаточно далеко от края экрана, чтобы пользователь не мог видеть дочернее окно, даже если дочернее окно и его родительское окно имеют стиль WS_VISIBLE .
Свернутые, развернутые и восстановленные окна
Развернутое окно — это окно со стилем WS_MAXIMIZE. По умолчанию система расширяет полноэкранное окно, и оно занимает весь экран или, если это дочернее окно, клиентскую область родительского окна. Хотя размер окна можно задать равным размеру развернутого окна, развернутое окно немного отличается. Система автоматически перемещает заголовок окна в верхнюю часть экрана или в верхнюю часть клиентской области родительского окна. Кроме того, система отключает границу размера окна и возможность позиционирования окна в строке заголовка (чтобы пользователь не может переместить окно, перетащив заголовок окна).
Свернутое окно — это окно со стилем WS_MINIMIZE. По умолчанию система уменьшает минимизированное окно до размеров кнопки панели задач и перемещает его на панель задач. Восстановленное окно — это окно, которое было возвращено к предыдущему размеру и положению, т. е. размеру, который он был до свернутого или развернутого.
Если приложение указывает стиль WS_MAXIMIZE или WS_MINIMIZE в функции CreateWindowEx , окно изначально разворачивается или свернуто. После создания окна приложение может использовать функцию CloseWindow , чтобы свернуть окно. Функция ArrangeIconicWindows упорядочивает значки на рабочем столе или упорядочивает свернутые дочерние окна родительского окна в родительском окне. Функция OpenIcon восстанавливает свернутое окно до предыдущего размера и положения.
Функция ShowWindow может свернуть, развернуть или восстановить окно. Он также может задавать состояния видимости и активации окна. Функция SetWindowPlacement включает те же функции, что и ShowWindow, но может переопределять свернутые, развернутые и восстановленные позиции окна по умолчанию.
Функции IsZoomed и IsIconic определяют, развернуто ли данное окно или свернуто соответственно. Функция GetWindowPlacement извлекает свернутые, развернутые и восстановленные позиции окна, а также определяет состояние отображения окна.
Когда система получает команду для развертывания или восстановления свернутого окна, она отправляет окну WM_QUERYOPEN сообщение. Если процедура окна возвращает значение FALSE, система игнорирует команду развернуть или восстановить.
Система автоматически устанавливает размер и положение развернутого окна в соответствии с заданными системой значениями по умолчанию для развернутого окна. Чтобы переопределить эти значения по умолчанию, приложение может вызвать функцию SetWindowPlacement или обработать WM_GETMINMAXINFO сообщение, полученное окном, когда система намерена развернуть окно. WM_GETMINMAXINFO содержит указатель на структуру MINMAXINFO , содержащую значения, которые система использует для установки максимального размера и положения. Замена этих значений переопределяет значения по умолчанию.
Размер и положение окна
Размер и положение окна выражаются в виде ограничивающего прямоугольника, заданного в координатах относительно экрана или родительского окна. Координаты окна верхнего уровня находятся относительно левого верхнего угла экрана; Координаты дочернего окна находятся относительно левого верхнего угла родительского окна. Приложение указывает начальный размер и положение окна при создании окна, но оно может изменить его размер и положение в любое время. Дополнительные сведения см. в разделе Заполненные фигуры.
В этом разделе рассматриваются следующие вопросы.
- Размер и положение по умолчанию
- Размер отслеживания
- Системные команды
- Функции размера и положения
- Размер и положение сообщений
Размер и положение по умолчанию
Приложение может позволить системе вычислить начальный размер или положение окна верхнего уровня, указав CW_USEDEFAULT в CreateWindowEx. Если приложение задает координаты окна в CW_USEDEFAULT и не создало других окон верхнего уровня, система задает положение нового окна относительно левого верхнего угла экрана; в противном случае он задает позицию относительно позиции окна верхнего уровня, созданного приложением в последнее время. Если для параметров ширины и высоты задано значение CW_USEDEFAULT, система вычисляет размер нового окна. Если приложение создало другие окна верхнего уровня, система основывает размер нового окна на основе размера последнего созданного окна верхнего уровня приложения. Указание CW_USEDEFAULT при создании дочернего или всплывающего окна приводит к тому, что система установит минимальный размер окна по умолчанию.
Размер отслеживания
Система поддерживает минимальный и максимальный размер отслеживания для окна стиля WS_THICKFRAME ; Окно с этим стилем имеет границу размера. Минимальный размер для отслеживания — это наименьший размер окна, который можно получить, перетащив границу размера окна. Точно так же максимальный размер отслеживаемого окна — это самый большой размер окна, который можно получить, перетащив границу размера.
Минимальный и максимальный размеры отслеживания окна задаются как системные значения по умолчанию, когда система создает окно. Приложение может обнаружить значения по умолчанию и переопределить их, обрабатывая сообщение WM_GETMINMAXINFO . Дополнительные сведения см. в разделе Сообщения о размере и расположении.
Системные команды
Приложение с меню окна может изменять размер и положение этого окна, отправляя системные команды. Системные команды создаются, когда пользователь выбирает команды в меню окна. Приложение может эмулировать действие пользователя, отправляя WM_SYSCOMMAND сообщение в окно. Следующие системные команды влияют на размер и положение окна.
Get-Help Описание SC_CLOSE Закрывает окно. Эта команда отправляет WM_CLOSE сообщение в окно. Окно выполняет все действия, необходимые для очистки и уничтожения себя. SC_MAXIMIZE Разворачивает окно. SC_MINIMIZE Сворачивает окно. SC_MOVE Перемещает окно. SC_RESTORE Восстанавливает свернутое или развернутое окно до предыдущего размера и положения. SC_SIZE Запускает команду size. Чтобы изменить размер окна, используйте мышь или клавиатуру. Функции размера и положения
После создания окна приложение может задать размер или положение окна, вызвав одну из нескольких различных функций, включая SetWindowPlacement, MoveWindow, SetWindowPos и DeferWindowPos. SetWindowPlacement задает свернутое положение окна, развернутое положение, восстановленный размер и положение, а также состояние отображения. Функции MoveWindow и SetWindowPos похожи; оба задают размер или положение одного окна приложения. Функция SetWindowPos включает набор флагов, влияющих на состояние отображения окна; MoveWindow не включает эти флаги. Используйте функции BeginDeferWindowPos, DeferWindowPos и EndDeferWindowPos , чтобы одновременно задать положение ряда окон, включая размер, положение, положение в z-порядке и состояние отображения.
Приложение может получить координаты ограничивающего прямоугольника окна с помощью функции GetWindowRect . GetWindowRect заполняет структуру RECT координатами верхнего левого и нижнего правого углов окна. Координаты находятся относительно левого верхнего угла экрана, даже для дочернего окна. Функция ScreenToClient или MapWindowPoints сопоставляет координаты экрана ограничивающего прямоугольника дочернего окна с координатами относительно клиентской области родительского окна.
Функция GetClientRect извлекает координаты клиентской области окна. GetClientRect заполняет структуру RECT координатами верхнего левого и нижнего правого углов клиентской области, но координаты находятся относительно самой клиентской области. Это означает, что координаты верхнего левого угла клиентской области всегда имеют значение (0,0), а координаты правого нижнего угла — это ширина и высота клиентской области.
Функция CascadeWindows каскадирует окна на рабочем столе или каскадирует дочерние окна указанного родительского окна. Функция TileWindows отображает окна на рабочем столе или дочерние окна указанного родительского окна.
Размер и положение сообщений
Система отправляет сообщение WM_GETMINMAXINFO в окно, размер или положение которого изменится. Например, сообщение отправляется, когда пользователь нажимает кнопку Переместить или Размер в меню окна или щелкает границу размера или строку заголовка. сообщение также отправляется, когда приложение вызывает SetWindowPos для перемещения или изменения размера окна. WM_GETMINMAXINFO содержит указатель на структуру MINMAXINFO , содержащую развернутый размер и положение окна по умолчанию, а также минимальные и максимальные размеры отслеживания по умолчанию. Приложение может переопределить значения по умолчанию, обрабатывая WM_GETMINMAXINFO и устанавливая соответствующие элементы MINMAXINFO. Для получения WM_GETMINMAXINFO окно должно иметь стиль WS_THICKFRAME или WS_CAPTION. Окно со стилем WS_THICKFRAME получает это сообщение во время создания окна, а также при его перемещении или размере.
Система отправляет WM_WINDOWPOSCHANGING сообщение в окно, размер которого, положение, положение в z-порядке или состояние отображения в этом окне изменится. Это сообщение содержит указатель на структуру WINDOWPOS , которая указывает новый размер окна, положение, положение в z-порядке и состояние отображения. Задавая элементы WINDOWPOS, приложение может повлиять на новый размер, положение и внешний вид окна.
После изменения размера, положения, положения окна в z-порядке или состояния отображения система отправляет WM_WINDOWPOSCHANGED сообщение в окно. Это сообщение содержит указатель на WINDOWPOS , который сообщает окну о новом размере, положении, позиции в z-порядке и состоянии отображения. Установка элементов структуры WINDOWPOS , передаваемой с помощью WM_WINDOWPOSCHANGED , не влияет на окно. Окно, которое должно обрабатывать WM_SIZE и WM_MOVE сообщений, должно передавать WM_WINDOWPOSCHANGED функции DefWindowProc ; В противном случае система не отправляет WM_SIZE и WM_MOVE сообщения в окно.
Система отправляет сообщение WM_NCCALCSIZE в окно при создании или изменении размера окна. Система использует сообщение для вычисления размера клиентской области окна и положения клиентской области относительно левого верхнего угла окна. Окно обычно передает это сообщение в процедуру окна по умолчанию; Однако это сообщение может быть полезно в приложениях, которые настраивают неклиентную область окна или сохраняют части клиентской области при размере окна. Дополнительные сведения см. в разделе Рисование и рисование.
Анимация окна
Вы можете создавать специальные эффекты при отображении или скрытии окон с помощью функции AnimateWindow . Если окно анимируется таким образом, система будет либо разворачиваться, скользить, либо исчезать окно в зависимости от флагов, указанных в вызове AnimateWindow.
По умолчанию система использует анимацию ролла. При таком эффекте окно открывается (отображается окно) или закрывается (скрывает окно). С помощью параметра dwFlags можно указать, будет ли окно разворачиваться по горизонтали, вертикали или по диагонали.
При указании флага AW_SLIDE система использует анимацию слайдов. При таком эффекте окно отображается для скольжения (с отображением окна) или выдвигается за пределы видимости (скрытие окна). С помощью параметра dwFlags можно указать, будет ли окно скользить по горизонтали, вертикали или по диагонали.
При указании флага AW_BLEND система использует альфа-смешанный затухание.
Вы также можете использовать флаг AW_CENTER , чтобы окно отображалось для сворачивания вовнутрь или расширения наружу.
Макет окна и зеркальное отображение
Макет окна определяет способ размещения текста и объектов интерфейса графических устройств Windows (GDI) в контексте окна или устройства (DC). Для некоторых языков, таких как английский, французский и немецкий, требуется макет слева направо (LTR). Для других языков, таких как арабский и иврит, требуется макет справа налево (RTL). Макет окна применяется к тексту, но также влияет на другие элементы GDI окна, включая растровые изображения, значки, расположение источника, кнопки, каскадные элементы управления деревом, а также увеличивается ли горизонтальная координата при переходе влево или вправо. Например, после того, как приложение настроит макет RTL, источник размещается в правом краю окна или устройства, а число, представляющее горизонтальную координату, увеличивается по мере перемещения влево. Однако макет окна влияет не на все объекты. Например, макет диалоговых окон, окон сообщений и контекстов устройств, не связанных с окном, таких как метафайл и принтер контроллеров домена, должен обрабатываться отдельно. Особенности этих компонентов упоминаются далее в этом разделе.
Оконные функции позволяют указать или изменить макет окна в версиях Windows на арабском и иврите. Обратите внимание, что изменение макета RTL (также называемого зеркальным отображением) не поддерживается для окон со стилем CS_OWNDC или для контроллера домена с GM_ADVANCED графическим режимом.
По умолчанию макет окна — слева направо (LTR). Чтобы задать макет окна RTL, вызовите CreateWindowEx со стилем WS_EX_LAYOUTRTL. Кроме того, по умолчанию дочернее окно (то есть созданное в стиле WS_CHILD и с допустимым родительским параметром hWnd в вызове CreateWindow или CreateWindowEx) имеет тот же макет, что и его родительский. Чтобы отключить наследование зеркального отображения для всех дочерних окон, укажите WS_EX_NOINHERITLAYOUT в вызове CreateWindowEx. Обратите внимание, что зеркальное отображение не наследуется собственными окнами (созданными без стиля WS_CHILD ) или созданными с родительским параметром hWnd в CreateWindowEx , для которого задано значение NULL. Чтобы отключить наследование зеркального отображения для отдельного окна, обработайте сообщение WM_NCCREATEс помощью команд GetWindowLong и SetWindowLong , чтобы отключить флаг WS_EX_LAYOUTRTL . Эта обработка является дополнением к любой другой обработке, необходимой. В следующем фрагменте кода показано, как это делается.
SetWindowLong (hWnd, GWL_EXSTYLE, GetWindowLong(hWnd,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL))Для макета по умолчанию можно задать RTL, вызвав SetProcessDefaultLayout(LAYOUT_RTL). Все окна, созданные после вызова, будут зеркально отображаться, но существующие окна не затрагиваются. Чтобы отключить зеркальное отображение по умолчанию, вызовите SetProcessDefaultLayout(0).
Примечание . SetProcessDefaultLayout зеркально отражает контроллеры домена только для зеркальных окон. Чтобы зеркало любой контроллер домена, вызовите SetLayout(hdc, LAYOUT_RTL). Дополнительные сведения см. в описании контекстов зеркального отображения устройств, не связанных с окнами, которые будут приведены далее в этой статье.
Точечные изображения и значки в зеркальном окне также зеркально отображаются по умолчанию. Однако не все из них должны быть зеркальными. Например, те, с текстом, бизнес-логотипом или аналоговыми часами не должны быть зеркальными. Чтобы отключить зеркальное отображение растровых изображений, вызовите SetLayout с битом LAYOUT_BITMAPORIENTATIONPRESERVED, заданным в dwLayout. Чтобы отключить зеркальное отображение в контроллере домена, вызовите SetLayout(hdc, 0).
Чтобы запросить текущий макет по умолчанию, вызовите Метод GetProcessDefaultLayout. После успешного возврата pdwDefaultLayout содержит LAYOUT_RTL или 0. Чтобы запросить параметры макета контекста устройства, вызовите GetLayout. После успешного возврата GetLayout возвращает значение DWORD , указывающее параметры макета по параметрам LAYOUT_RTL и LAYOUT_BITMAPORIENTATIONPRESERVED битам.
После создания окна измените макет с помощью функции SetWindowLong . Например, это необходимо, когда пользователь изменяет язык пользовательского интерфейса существующего окна с арабского или иврита на немецкий. Однако при изменении макета существующего окна необходимо сделать окно недействительным и обновить его, чтобы убедиться, что все содержимое окна рисуется на одном макете. Следующий пример кода является примером кода, который изменяет макет окна по мере необходимости:
// Using ANSI versions of GetWindowLong and SetWindowLong because Unicode // is not needed for these calls lExStyles = GetWindowLongA(hWnd, GWL_EXSTYLE); // Check whether new layout is opposite the current layout if (!!(pLState -> IsRTLLayout) != !!(lExStyles & WS_EX_LAYOUTRTL)) < // the following lines will update the window layout lExStyles ^= WS_EX_LAYOUTRTL; // toggle layout SetWindowLongA(hWnd, GWL_EXSTYLE, lExStyles); InvalidateRect(hWnd, NULL, TRUE); // to update layout in the client area >При зеркальном отображении следует думать в терминах «близкий» и «дальний», а не «левый» и «правый». Если это не сделать, это может привести к проблемам. Одна из распространенных методик программирования, которая вызывает проблемы в зеркальном окне, возникает при сопоставлении между координатами экрана и клиентскими координатами. Например, приложения часто используют код, аналогичный следующему, для размещения элемента управления в окне:
// DO NOT USE THIS IF APPLICATION MIRRORS THE WINDOW // get coordinates of the window in screen coordinates GetWindowRect(hControl, (LPRECT) &rControlRect); // map screen coordinates to client coordinates in dialog ScreenToClient(hDialog, (LPPOINT) &rControlRect.left); ScreenToClient(hDialog, (LPPOINT) &rControlRect.right);Это вызывает проблемы при зеркальном отображении, так как левый край прямоугольника становится правым краем зеркального окна и наоборот. Чтобы избежать этой проблемы, замените вызовы ScreenToClient вызовом MapWindowPoints следующим образом:
// USE THIS FOR MIRRORING GetWindowRect(hControl, (LPRECT) &rControlRect); MapWindowPoints(NULL, hDialog, (LPPOINT) &rControlRect, 2)Этот код работает потому, что на платформах, поддерживающих зеркальное отображение, MapWindowPoints изменяется для переключения координат левой и правой точек при зеркальном отображении клиентского окна. Дополнительные сведения см. в разделе Примечания статьи MapWindowPoints.
Другой распространенной практикой, которая может вызвать проблемы в зеркальных окнах, является размещение объектов в клиентском окне с использованием смещения в экранных координатах, а не клиентских координат. Например, следующий код использует разницу в координатах экрана в качестве позиции X в клиентских координатах для размещения элемента управления в диалоговом окне.
// OK if LTR layout and mapping mode of client is MM_TEXT, // but WRONG for a mirrored dialog RECT rdDialog; RECT rcControl; HWND hControl = GetDlgItem(hDlg, IDD_CONTROL); GetWindowRect(hDlg, &rcDialog); // gets rect in screen coordinates GetWindowRect(hControl, &rcControl); MoveWindow(hControl, rcControl.left - rcDialog.left, // uses x position in client coords rcControl.top - rcDialog.top, nWidth, nHeight, FALSE);Этот код подходит, если диалоговое окно имеет макет слева направо (LTR) и режим сопоставления клиента MM_TEXT, так как новая позиция x в клиентских координатах соответствует разнице левого края элемента управления и диалогового окна в координатах экрана. Однако в зеркальном диалоговом окне слева и справа используются обратные значения, поэтому вместо этого следует использовать MapWindowPoints следующим образом:
RECT rcDialog; RECT rcControl; HWND hControl - GetDlgItem(hDlg, IDD_CONTROL); GetWindowRect(hControl, &rcControl); // MapWindowPoints works correctly in both mirrored and non-mirrored windows. MapWindowPoints(NULL, hDlg, (LPPOINT) &rcControl, 2); // Now rcControl is in client coordinates. MoveWindow(hControl, rcControl.left, rcControl.top, nWidth, nHeight, FALSE)Диалоговые окна зеркального отображения и окна сообщений
Диалоговые окна и окна сообщений не наследуют макет, поэтому макет необходимо задать явным образом. Чтобы зеркало окно сообщения, вызовите MessageBox или MessageBoxEx с параметром MB_RTLREADING. Чтобы создать макет диалогового окна справа налево, используйте расширенный стиль WS_EX_LAYOUTRTL в структуре шаблона диалогового окна DLGTEMPLATEEX. Листы свойств — это особый случай диалоговых окон. Каждая вкладка рассматривается как отдельное диалоговое окно, поэтому необходимо включить стиль WS_EX_LAYOUTRTL в каждую вкладку, на которой требуется зеркальное отображение.
Контексты зеркального отображения устройств, не связанные с окном
Контроллеры домена, которые не связаны с окном, например метафайл или принтер, не наследуют макет, поэтому необходимо задать макет явным образом. Чтобы изменить макет контекста устройства, используйте функцию SetLayout .
Функция SetLayout редко используется с окнами. Как правило, окна получают связанный контроллер домена только при обработке сообщения WM_PAINT . Иногда программа создает контроллер домена для окна путем вызова GetDC. В любом случае начальный макет для контроллера домена задается с помощью BeginPaint или GetDC в соответствии с флагом WS_EX_LAYOUTRTL окна.
Если макет имеет значение RTL, GetMapMode вернет MM_ANISOTROPIC вместо MM_TEXT. Вызов SetMapMode с MM_TEXT будет работать правильно; Затрагивается только возвращаемое значение из GetMapMode . Аналогичным образом вызов SetLayout(hdc, LAYOUT_RTL) при MM_TEXT приводит к изменению режима сопоставления на MM_ANISOTROPIC.
Уничтожение окна
Как правило, приложение должно уничтожить все окна, которые оно создает. Для этого используется функция DestroyWindow . При уничтожении окна система скрывает окно, если оно отображается, а затем удаляет все внутренние данные, связанные с окном. Это делает недействительным дескриптор окна, который больше не может использоваться приложением.
Приложение уничтожает многие окна, которые оно создает вскоре после их создания. Например, приложение обычно уничтожает диалоговое окно, как только у него будет достаточно входных данных от пользователя для продолжения выполнения задачи. В конечном итоге приложение удаляет окно main приложения (перед завершением).
Перед уничтожением окна приложение должно сохранить или удалить все данные, связанные с окном, и освободить все системные ресурсы, выделенные для окна. Если приложение не освобождает ресурсы, система освободит все ресурсы, не освобожденные приложением.
Уничтожение окна не влияет на класс окон, из которого создается окно. Новые окна по-прежнему можно создавать с помощью этого класса, и все существующие окна этого класса продолжают работать. Уничтожение окна также разрушает его потомки. Функция DestroyWindow отправляет сообщение WM_DESTROY сначала в окно, а затем в его дочерние окна и потомки окон. Таким образом, все потомки окна разрушаемого окна также уничтожаются.
Окно с меню окна получает WM_CLOSE сообщение, когда пользователь нажимает кнопку Закрыть. Обрабатывая это сообщение, приложение может запрашивать у пользователя подтверждение перед уничтожением окна. Если пользователь подтверждает, что окно должно быть уничтожено, приложение может вызвать функцию DestroyWindow , чтобы уничтожить окно.
Если уничтожаемое окно является активным, то и активное, и состояние фокуса переносятся в другое окно. Окно, которое становится активным, является следующим окном, которое определяется сочетанием клавиш ALT+ESC. Затем новое активное окно определяет, какое окно получает фокус клавиатуры.
