- •История Windows
- •Windows 1.0
- •Windows 1.3
- •Windows 2.0
- •Windows 3.0
- •Windows 3.1
- •Windows for Workgroups версии 3.11
- •Windows NT
- •Windows 95
- •Windows NT Workstation 4.0 и Windows NT Server 4.0
- •Windows NT 4.0 Server Enterprise Edition
- •Windows 98
- •Windows 98 Second Edition (SE)
- •Windows 2000
- •Windows 98 Millenium Edition (ME)
- •Windows XP
- •Общая архитектура WINDOWS приложения.
- •Каркас приложения
- •Регистрация класса окна
- •Создание окна.
- •Отображение окна.
- •Цикл обработки очереди сообщений.
- •WndProc
- •Обработка сообщений типового приложения.
- •Контрольные вопросы
- •Сообщения
- •Типы сообщений
- •Обработка клавиатурных сообщений
- •Обработка сообщений от мыши
- •Сообщения таймера
- •Контрольные вопросы
- •Организация ввода
- •Разупорядоченный ввод
- •Разделение потоками виртуальных очередей ввода
- •Локальное состояние ввода
- •Ввод с клавиатуры и фокус
- •Управление курсором мыши
- •Контрольные вопросы
- •Окна
- •Окна Windows
- •Иерархия окон
- •Оконная процедура, стандартные оконные процедуры
- •Стиль класса окна
- •Стили окон, окна основных стилей
- •Перекрывающиеся окна
- •Временные окна
- •Дочерние окна
- •Сообщения управления окнами
- •Окна с полосами прокрутки
- •Системные метрики
- •Определение размера окна
- •Определение расположения окна
- •Контрольные вопросы
- •Графический интерфейс устройств(GDI).
- •Создание (получение) контекста устройств.
- •Сохранение контекста устройства.
- •Прямые (отрезки) и кривые
- •Закрашенные области
- •Битовые шаблоны (растровые шаблоны, растровые образы)
- •Текст и шрифты
- •Режимы масштабирования и преобразования
- •Метафайл
- •Регионы
- •Путь
- •Палитры
- •Контрольные вопросы
- •Объекты ядра
- •Что такое объект ядра
- •Учет пользователей объектов ядра
- •Защита
- •Таблица описателей объектов ядра
- •Создание объекта ядра
- •Закрытие объекта ядра
- •Синхронизация объектов
- •Именованные объекты
- •Дублирование описателей объектов
- •Изменение флагов описателя
- •Синхронизация потоков
- •Критическая секция
- •Мьютексы
- •Семафоры
- •События
- •Ожидаемые таймеры
- •Контрольные вопросы
- •Ресурсы Windows приложения
- •Файлы ресурсов приложения
- •Значки (пиктограммы)
- •Курсоры
- •Битовые образы
- •Символьные строки
- •Ресурсы, определяемые пользователем
- •Таблица акселераторов
- •Меню
- •Диалоговые окна
- •Контрольные вопросы
- •Элементы управления
- •Дочерние окна управления
- •Создание дочерних окон
- •Сообщения дочерних окон родительскому окну
- •Сообщения родительского окна дочерним окнам
- •Дочерние окна и фокус ввода
- •Дочерние окна управления и цвет
- •Кнопки различных стилей (класс BUTTON)
- •Нажимаемые кнопки
- •Флажки-переключатели
- •Переключатели
- •Окна групп
- •Кнопки, определяемые пользователем
- •Статические поля (класс static)
- •Текстовые редакторы (класс edit)
- •Списки разных стилей (класс listbox)
- •Комбинированные списки (класс combobox)
- •Полосы прокрутки (класс scrollbar)
- •Контрольные вопросы
- •Расширенные элементы управления
- •Основы общих элементов управления
- •Инициализация библиотеки элементов общего пользования
- •Создание элементов управления общего пользования
- •Посылка сообщений общим элементам управления
- •Уведомляющие сообщения от общих элементов управления
- •Контрольные вопросы
- •Стандартные диалоговые окна.
- •Окна сообщений
- •Диалоговые окна общего пользования
- •Контрольные вопросы
- •Динамически подключаемые библиотеки
- •Создание DLL
- •Проецирование DLL на адресное пространство процесса
- •Функция входа/выхода
- •Функция DllMain и стандартная библиотека С
- •Функция LibEntry
- •Функция LibMain
- •Функция WEP
- •Экспорт функций и переменных из DLL
- •Импорт функций и переменных из DLL
- •Заголовочный файл DLL
- •Разделы в ЕХЕ- и DLL-файлах
- •Контрольные вопросы
- •Файлы, проецируемые в память
- •Контрольные вопросы
- •Классы, определяющие архитектуру приложения
- •Классы приложения и поддержки потоков
- •Классы приложения и потоков
- •Классы фреймов окон
- •Получение информации о приложении
- •Соглашения об именах MFC
- •Включаемые файлы
- •Функция WinMain
- •Класс CWinApp
- •Класс CWnd
- •Класс CFrameWnd
- •Создание главного окна SDI-приложения
- •Примечание
- •Создание главного окна SDI-приложения
- •Создание дочерних окон
- •Ограничение размеров окна
- •Ограничение доступа к окну
- •Создание многодокументных приложений
- •Класс CMDIChildWnd
- •MDI — пример приложения
- •Категории сообщений
- •Карта сообщений
- •Компоненты карты сообщений
- •Класс CCmdTarget
- •Стандартный маршрут команды
- •Команды обновления и класс CCmdlll
- •Функции для работы с сообщениями
- •Основные положения
- •Класс CDocTemplate
- •Класс CSingleDocTemplate
- •Роль фреймов в архитектуре "документ/представление"
- •Документ и его представления
- •Документы
- •Класс CDocument
- •Класс CArchive
- •Представления
- •Класс CView
- •Панели элементов управления
- •Класс CStatusBar
- •Класс CStatusBarCtrl
- •Класс CDialogBar
- •ControlBars — пример приложения
- •НЕКОТОРЫЕ КЛАССЫ MFC
- •Класс CObject - основной класс MFC
- •Конструкторы класса
- •Оператор присваивания
- •Диагностика
- •Проверка целостности объектов класса
- •Получение дампа объекта класса
- •Сохранение и восстановление состояния объекта
- •Метод IsSerializable
- •Виртуальный метод Serialize
- •Информация о классе
- •Виртуальный метод GetRuntimeClass
- •Метод IsKindOf
- •Класс CPoint - точка на плоскости
- •Класс CSize - относительные координаты
- •Класс CString - текстовые строки
- •Конструктор класса
- •Коллекции
- •Массивы - шаблон CArray
- •Списки - шаблон CList
- •Словари - шаблон CMap
- •Класс CTime - дата и время
- •Файловая система - класс CFile
- •Открытие и создание файлов
- •Идентификатор открытого файла
- •Закрытие файлов
- •Чтение и запись файлов
- •Метод Flush
- •Операции с файлами
- •Блокировка
- •Позиционирование
- •Характеристики открытого файла
- •Файловая система - классы CMemFile и CStdioFile
- •Модификация класса CMemFile
- •Файловая система - класс CStdioFile
- •Запись и восстановление объектов
- •Запись в архивный файл
- •Чтение из архивного файла
- •Исключения - класс CException
- •Класс CException
- •Класс CMemoryException
- •Класс CFileException
- •Приложение Except
- •Класс CArchiveException
- •Класс CNotSupportedException
- •Класс CResourceException
- •Класс CUserException
Создание главного окна SDI-приложения
В рассмотренной ранее программе First мы образовали класс нашего окна из базового CWnd. Это допустимый, но очень неэффективный путь. Пришло время познакомить вас с одним из возможных подходов для создания главного окна SDI-приложения.1
Прежде всего обратим внимание на базовый класс нашего главного окна:
class CMainFrame : public CFrameWnd
Процесс создания окна состоит из трех шагов. Прежде всего необходимо создать объект "главное окно":
CMainFrame *pMainWnd = new CMainFrame;
Следующий шаг состоит в вызове специальной функции, которая создает окно Windows и присоединяет его к нашему объекту:
pMainWnd->LoadFrame (IDR_MA IN FRAME) ;
И, наконец, следует отобразить окно на экране, чтобы пользователь мог с ним взаимодействовать:
pMainWnd->SetWindowPos (NULL, ex, су, 6*сх, 2*су, SWP_NOZORDER | SWP_SHOWWINDOW) ;
Рассмотрим сначала процесс создания окна Windows, или, используя терминологию MFC, фрейма окна.
Из двух функций, реализованных в классе CFrameWnd, мы остановили свой выбор на виртуальной функции CFrameWnd::LoadFrame, которая берет на себя задачу регистрации оконного класса, используя для этого предопределенный шаблон, и извлекает из файла ресурсов, задаваемого идентификатором, остальные необходимые для создания окна Windows параметры:
virtual BOOL CFrameWnd::LoadFrame( UINT nIDResource,
DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, CWnd *pParentWnd = NULL, CCreateContext *pContext = NULL)
Функция возвращает значение TRUE, если создание фрейма прошло успешно, и FALSE в противном случае. Она имеет следующие параметры: nIDResource — идентификатор разделяемых ресурсов, ассоциированных с фреймом, который определяет меню, таблицу акселераторов, пиктограмму и строку, помещаемую в заголовок окна; pParentWnd — указатель на родительское окно данного фрейма (необязательный параметр); pContext — указатель на структуру CCreateContex, которая определяет объекты, связанные
данным фреймом; dwDefaultStyle — стиль фрейма (необязательный параметр), дополнительно к стандартным могут быть использованы следующие стили:
FWS_ADDTOTITLE FWS_PREFIXTITLE FWS_SNAPTOBAR
в конец заголовка окна будет добавлена дополнительная текстоваястрока перед заголовком окна будет помещено имя документа позволяет подогнать размеры окна под размеры панели элементовуправления
Основное назначение этой функции — максимальное упрощение процесса создания фрейма окна.1 CFrameWnd::Create, функция загружает ресурс меню и вызывает функцию CWnd::CreateEx, которая регистрирует имя оконного класса, заполняя структуру WNDCLASS, и вызывает виртуальную функцию
PreCreateWindow. В процессе выполнения функции Windows посылает в окно следующие сообщения: WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALKSIZE и WM_CREATE. Если при создании окна был определен стиль WSJVISIBLE, то в окно дополнительно посылаются все сообщения, необходимые для активизации и отображения окна на экране. Таким образом, переопределяя функцию PreCreateWindow и обработчик любого из представленных сообщений Windows, можно изменять параметры оконного класса и собственно окна, как до, так и после создания окна Windows.
Рассмотрим, как этот механизм реализован в нашей программе. Начнем с функции CMainFrame::PreCreate Window.
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { cs.lpszName = "Главное окно приложения \"Стили\""; return CFrameWnd::PreCreateWindow(cs);
Единственный параметр, передаваемый в эту функцию, — ссылка на структуру CREATESTRUCT, которая определяет параметры инициализации, посылаемые в оконную процедуру, и содержит следующие поля:
typedef struct tagCREATESTRUCT{ LPVOID IpCreateParams;
HANDLE hlnctance; KMENU hMenu;
HWND hwndParent; int cy;
int ex; int y; int x;
LONG style; LPCSTR IpszName; LPCSTR IpszClass;
DWORD dwExStyle; ) CREATESTRUCT;
Назначение полей этой структуры: IpCreateParams — указатель на данные, используемые при создании окна; hlnstance — дескриптор модуля, который владеет окном; hMenu — идентификатор меню, используемого окном; hwndParent — дескриптор окна-родителя, если этот параметр равен NULL, то новое окно является окном верхнего уровня; су, сх, у, х — целые числа, задающие соответственно ширину и высоту окна, а также его положение относительно своего владельца; IpszName — символьная строка, задающая имя окна; IpszClass — символьная строка, содержащая имя класса, которому принадлежит окно; dwExStyle — определяет атрибуты расширенного стиля окна.
Мы использовали эту функцию, чтобы не заниматься процедурой регистрации класса окна, возложив ее выполнение на библиотеку, поскольку принятые по умолчанию установки нас вполне устраивают. Единственное, что нас не устраивает, это заголовок окна, который мы и переопределили:
cs.lpszName = "Главное окно приложения \"Стили\"";
Это один из возможных способов присвоения имени окну.1
После того как окно Windows создано и присоединено к объекту фрейма окна, в ответ на сообщение WM_CREATE вызывается обработчик сообщения OnCreate (механизм вызова был нами подробно описан при обсуждении механизма работы с сообщениями в библиотеке MFC):
int CMainFrame: : OnCreate (LPCREATESTRUCT IpCreateStruct) { if (CFrameWnd: : OnCreate (IpCreateStruct) == -1) return -1; return 0;
Эта функция — одно из возможных мест, где создаются иприсоединяются кокну произвольные элементы пользовательского интерфейса. Для правильного завершения процесса создания окна не забывайте вызывать перед какими-либо своими действиями обработчик базового класса СFrame Wnd:: On Create.
После того как фрейм создан, его необходимо вывести на экран. Библиотека предоставляет несколько функций для реализации этого процесса. Для отображения нашего главного окна мы остановились на одной из них — функцииCWnd::SetWindowPos:
BOOL CWnd::SetWindowPos( const CWnd *pWndlnsertAfter, int x, inty, int ex, int cy, UINT nFlags)
Вызов этой функции позволяет изменить как размеры, так и расположение дочерних и всплывающих окон относительно экрана и других окон. Она имеет следующие параметры: pWndlnsertAfter — указывает на объект CWnd, после которого будет расположено окно, вместо этого указателя можно использовать одно из следующих предопределенных значений, задающих расположение окна относительно других окон:
Примечание
Windows располагает окна на экране согласно их положению в так называемом Z-порядке, который определяет позицию окна в стеке перекрывающихся окон. Стек окна ориентирован вдоль воображаемой оси (Z-оси) внутрь экрана. Окно, расположенное на вершине стека, перекрывает все другие окна, а расположенное внизу — перекрывается всеми другими окнами. Приложение не может активизировать окно без того, чтобы не перенести его на самый верх Z-порядка. Кроме того, расположение окна относительно экрана и других окон может из-
меняться без каких-либо
Мы использовали эту функцию для указания размеров и расположения окна, а также для того, чтобы сделать его видимым.1
Отложим пока обсуждение вопросов создания и разрушения объекта класса CStylesApp до тех пор, пока не рассмотрим, как создаются дочерние окна.
Создание дочерних окон
Теперь, после создания основного окна приложения, можно переходить к созданию некоторого дополнительного пространства для отображения информации или для получения команд от пользователя. Каждому "ребенку", как в свое время и основному окну, можно приписать конкретный стиль таким образом, чтобы приспособить его внешний вид и назначение к стоящим перед ним целям. В приложении Styles мы разбили создаваемые окна на два набора. Окна первого располагаются на экране независимо от положения основного окна — все они имеют стиль WS_POPUP, а для окон из второго набора установлен стиль WS_CHILD и, следовательно, они не могут покинуть пределы рабочей области основного окна.
Для того чтобы понять принципы построения и работу рассматриваемой программы, вернемся к обработчику сообщения WM_CREATE. Повторим ту часть программы, на которую следует обратить внимание:
extern char szNameWnd [ 128 ] ;
// Создание пяти дочерних окон for (int. i = 0; i < 5; i + +)
{
apChildWnd[i] = new CChildWnd;
apChildWnd[i] ->Create (NULL, NULL, WS_VISIBLE, CRect(0, 0, 0, 0), this, (UINT) i) ; }
//Установка нового курсора для класса дочерних окон : :SetClassLong (apChildWnd [ 0 ] - >GetSafeHwnd () , GCL_HCURSOR, (LONG) AfxGetApp () ->LoadStandardCursor (IDC_IBEAM) ) ;
//Создание четырех всплывающих окон for(i = 0; i < 4;
apPopupWnd [ i ] |
= new CPopupWnd; apPopupWnd[i]->Create (NULL, NULL, 0, |
rectDefault, |
this); |
1Существуютидругиеспособырешенияэтойзадачи. Ихмыопишемниже.
2Посколькулюбоепорожденноеокнопрограммистыназывают"дочерним", точастовозникает некоторая путаница. Вы
должны совершенно четко отличать технический терминWS_CHILD отболееширокогоразговорногопонятия"дочерний
//Указание номера окна в поле данных ассоциированных с окном : : SetWindowLong (apPopupWnd [ i ] ->GetSaf eHwnd ( ) , GWL_USERDATA, i) ;
//Формирование нового заголовка окна sprintf (szNameWnd, "Окно %d", i)
;apPopupWnd [ i ] ->SetWindowText (szNameWnd) ;
}
//Создание перекрывающегося окна apPopupWnd [4] = new CPopupWnd;
apPopupWnd [4] ->Create (NULL, NULL, 0, rectDef ault) ; : : SetWindowLon2g (apPopupWnd [ i ] ->GetSaf eHwnd ( ) , GWL_USERDATA, 4 ) ;
sprintf (szNameWnd, "Окно %d", i) ; apPopupWnd [4 ] ->SetWindowText (szNameWnd) ;
//Установка нового курсора для класса всплывающих окон : : SetClassLong (apPopupWnd [0] ->GetSaf eHwnd () , GCL_HCURSOR, (LONG) AfxGetApp () ->LoadStandardCursor (IDC_UPARROW) ) ;
//Создание и установка нового цвета фона для всплывающих окон HBRUSH hNewBrush = : : CreateSolidBrush (RGB (255, 255, 220)); : : SetClassLong (apPopupWnd [3] ->GetSaf eHwnd ( ) , GCL_HBRBACKGROUND, (LONG) hNewBrush) ;
//Отображение всплывающих окон for(i = 0 ; i < 5;
apPopupWnd [i] ->ShowWindow (SW_SHOWNORMAL) ; apPopupWnd [ i ] ->UpdateWindow ( )
;
При ближайшем рассмотрении это не более, чем создание десяти окон, принадлежащих двум новым классам. Объекты одного класса позволяют создавать дочерние окна:
class CChildWnd : public CWnd i
а объекты второго — всплывающие и/или перекрывающиеся окна (хотя с тем же успехом можно создавать и дочерние):
class CPopupWnd : public CFrameWnd
Такое разбиение не продиктовано необходимостью и произведено лишь для наглядности. Дело в том, что, как мы упоминали, на базе класса CWnd можно создавать только дочерние окна (имеющие стиль WS_CHILD). Его мы и решили использовать для этих целей. На базе же класса CFrameWnd могут быть созданы окна любого из трех имеющихся типов. Поэтому для создания всплывающих окон именно он был использован в качестве базового.
В основном процесс создания окон обоих типов стандартен: создаются объекты классов, после чего вызывается некоторая функция для создания окна Windows. С целью рассмотрения как можно большего числа предоставляемых библиотекой возможностей мы включили в текст программы дополнительные строки. Но обо всем по порядку. Начнем с дочерних окон, имеющих установленный бит стиля WS_CHILD (процесс создания объекта класса ничем не отличается от уже рассмотренных, и мы больше не будем останавливаться на этом вопросе). Итак, вызов функции CWnd::Create:
apChildWnd[i]->Create(NULL, NULL, WS_VISIBLE, CRect(0, 0, 0, 0), this, (UINT)i);
Подчеркнем некоторые моменты. Во-первых, не определен класс Windows, к которому относится окно,
— эту задачу мы переложили на плечи библиотеки. Во-вторых, установив бит стиля WSJV1SIBLE, мы, тем самым, задали, чтобы окно сразу же после создания было выведено на экран. В-третьих, окно мы превратили в точку и поместили его в левый верхний угол экрана. В-четвертых, окно имеет "родителя" — пятый параметр определен как this, И, наконец, в качестве последнего параметра мы передаем номер создаваемого окна.
Как и при создании главного окна мы переопределяем функцию
BOOL CChildWnd::PreCreateWindow(CREATESTRUCT& cs) { cs.style != adwStyles[nCount];
sprintf(szNameWnd, "Окно %d", nCount); cs.lpszName = szNameWnd;
return CWnd::PreCreateWindow(cs);
и обработчик сообщения WM_CREATE
int CChildWnd::OnCreate(LPCREATESTRUCT IpCreateStruct) { if (CWnd:rOnCreate(IpCreateStruct) == -I) return -1;
MoveWindow(nCount++ * 118, 24, 116, 96); return 0;
Первая заполняет поля style и IpszName структуры CREATESTRUCT соответственно значениями стиля и имени конкретного окна, а вторая — устанавливает размер и положение вновь созданного окна (напомним, что мы задали окну нулевые размеры). Со структурой CREATESTRUCT мы уже познакомились, поэтому рассмотрим изящную функцию CWnd::MoveWindow, которая реализована в двух вариантах:
void CWnd::MoveWindow( intx,
int у,
int nWidth, int nHeight,
BOOL bRepaint = TRUE);
и
void CWnd::MoveWindow( LPCRECT IpRect, BOOL bRepaint = TRUE)
С помощью любой из этих функций можно одновременно изменить размер и положение окна, задаваемые в параметрах х, у, nWidth, nHeight или IpRect.1 Последний параметр этой функции определяет, будет ли окно перерисовываться после перемещения. Если этот параметр равен TRUE (по умолчанию), то объект "окно" получает сообщение Windows WM_PAINT. Кроме того, эта функция посылает еще и сообщение WM_GETMINMAXINFO, которое вы также можете обработать.
Как мы уже отметили, задача регистрации оконного класса была поручена библиотеке. Нам лишь остается "подправить" некоторые поля в соответствии с собственными нуждами. Один из возможных путей при этом состоит в использовании функций API SetClassLong и SetWindowLong. Возможно, вы захотите их использовать в своих программах, поэтому рассмотрим их подробнее:
DWORD SetClassLong( HWND hWnd, int nlndex,
LONG dwNewLong) -
эта функция устанавливает в структуре WNDCLASS, описывающей оконный класс для hWnd, новое значение dwNewLong в поле, определяемом параметром nlndex, который может принимать одно из следующих значений:
GCL_CBCLSEXTRA устанавливает размер (в байтах) дополнительной памяти,
предназначенной для использования всеми окнами, создаваемыми на базе этого класса; размер памяти, уже ассоциированной с классом, при этом не изменяется
GCL_CBWNDEXTRA устанавливает размер (в байтах) дополнительной памяти,
предназначенной дляиспользованияотдельнокаждым окном, создаваемыми на базе этого класса; размер памяти, уже ассоциированной с окном, при этом не изменяется
GCLJHBRBACKGROUND устанавливает дескриптор кисти для фона, ассоциированного с этим классом
GCL_HCURSOR |
устанавливает дескриптор курсора, ассоциированного с |
этим классом |
|
GCL_HICON устанавливает дескриптор пиктограммы, ассоциированной
с этим классом; это значение используется только в Windows 95 и не определено в Windows NT
GCL_HMODULE |
устанавливает дескриптор модуля, который зарегистриро- |
вал этот класс |
|
GCL_MENUNAME |
устанавливает адрес строки меню, которая идентифици- |
рует ресурс меню, ассоциированного с этим классом |
|
GCL_STYLE устанавливает биты стиля оконного класса |
|
GCL_WNDPROC |
устанавливает адрес оконной процедуры, ассоциирован- |
ной с классом |
|
При успешном выполнении функция возвращает значение указанного слова из структуры класса окна или нулевое значение при ошибке. Дополнительную информацию об ошибке можно получить, вызвав функцию API GetLastError.
Мы воспользовались этой функцией для того, чтобы установить новые значения для курсора и цвета фона.
Обратную задачу — получение информации из структуры класса окна — выполняет функция
DWORD GetClassLong(
HWND hWnd, int nlndex)
Для работы с дополнительной памятью в структуре окна API предоставляет также две функции:
DWORD SetWindowLong(
HWND hWnd, int nlndex,
LONG dwNewLong)
и
DWORD GetWindowLong(
HWND hWnd, int nlndex)
По своему принципу действия они аналогичны только что рассмотренным, но работают с дополнительной памятью в структуре окна. Параметр nlndex при этом может принимать следующие
значения:
GWL_EXSTYLE устанавливает новый расширенный стиль окна
GWL_STYLE устанавливает новый стиль окна
GWL_WNDPROC устанавливает новый адрес оконной процедуры
GWL_HINSTANCE устанавливает новый дескриптор приложения
GWLJD |
устанавливает новыйидентификатор окна |
GWL_USERDATA устанавливает 32-разрядное значение, ассоциированное с конкретным окном и предназначенное дляиспользованияприложением, которым это окно создано
Если дескриптор hWnd определяет блок диалога, то доступными являются следующие значения:
DWL_DLGPROC устанавливает новыйадрес процедурыблокадиалога
DWL_MSGRESULT устанавливает значение, возвращаемое при обработке сообщенияв процедуреблока диалога
DWL_USER устанавливает новую дополнительную информацию для приложения, такую как идентификатор или указатель
Для функции GetWindowLong кроме перечисленных определено еще одно доступное значение:
GWL_HWNDPARENT возвращает дескриптор родительского окна или NULL, если егонет
Мы использовали эти функции для записи в дополнительную память номера созданного окна. Другими словами, у первого окна в этом поле будет нуль, у второго — 1, у третьего — 2 и т. д. Позже, во время изображения окон на экране, программа воспользуется этими значениями для идентификации окон.
Перед тем как закончить обсуждение вопроса об изменении характеристик оконных классов и собственно окон, осталось отметить способ получения дескриптора окна Windows. Для этой цели в классе CWnd предусмотрена специальная функция
HWND CWnd::GetSafeWnd(),
которая позволяет получить дескриптор окна Windows, хранящийся в члене класса CWnd::m_hWnd, или NULL, если к объекту не присоединено никакое окно.
Но вернемся к нашей программе. Нам осталось разобраться в создании всплывающих окон. Обратите внимание на два несколько отличающихся вызова функции CFrameWnd::Create\
apPopupWndti]->Create(NULL, NULL, 0, rectDefault, this);
И
apPopupWnd[4]->Create(NULL, NULL, 0, rectDefauit);
и связанное с этим отличие в поведении всплывающих окон 3 и 4. Для четвертого окна мы не указали родителя, и поэтому оно ведет себя достаточно независимо от нашего главного окна.
Второй момент, на который хотелось бы обратить ваше внимание, связан с еще одним способом изменения стилей созданных окон. Обратимся к тексту:
int CPopupWnd::OnCreate(LPCREATESTRUCT IpCreateStruct) ( ModifyStyle((DWORD)-1, adwStyles[nCount]);
Как видите, для установки стиля окна мы воспользоватись функцией класса CWnd - ModifyStyle
BOOL CWnd::ModifyStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
Эта функция позволяет удалить (dwRemove) или установить (dwAdd) определенные атрибуты стиля окна. Если установлен параметр nFlags, то вызывается функция API ;:SetWindowPos с этим параметром, являющимся комбинацией одного или нескольких значений: SWP NOMOVE, SWP_NOACTIVATE, SWP NOSIZE и SWP_NOZORDER.
Для изменения флагов расширенного стиля можно использовать функцию:
BOOL CWnd::ModifyStyleEx( DWORD dwRemove,
DWORD dwAdd, UINT nFlags = 0)
