Заметки по WinAPI

  • регистрация класса окна

    • у каждого окна есть оконная процедура, которая обрабатывает сообщения
    • все окна в пределах одного класса имеют одну общую оконную процедуру
    • и прежде чем создавать окно некоторого класса процесс обязан зарегистрировать этот лкасс
    • за регистрацию класса отвечает функция
    • ATOM WINAPI RegisterClassEx( const WNDCLASSEX *lpwcx );
    • struct WNDCLASSEX { UINT cbSize; // размер структуры UINT style; // стиль класса WNDPROC lpfnWndProc; // указатель на оконную процедуру int cbClsExtra; // кол-во байт которые надо аллоцировать для window-class structure (доп память, доступная всем окнам класса) int cbWndExtra; // кол-во байт которые надо аллоцировать для window-instace(доп память, своя у каждого окна) HINSTANCE hInstance; // хэндл к сущности содержащей оконную процедуру HICON hIcon; // хэндл к иконке HCURSOR hCursor; // хэндл к курсору HBRUSH hbrBackground; // хэндл к кисточке или значение цвета (ВАЖНО не удалять кисточку до закрытия приложения) LPCTSTR lpszMenuName; // имя ресурса-меню LPCTSTR lpszClassName; // строчка или ATOM (созданный предыдущим вызовом RegisterClassEx) HICON hIconSm; // хэндл для маленькой иконки }
    • BOOL WINAPI UnregisterClass( LPCTSTR lpClassName, // имя класса или ATOM HINSTANCE hInstance ) // хэндл к модулю, создавшему класс
      • ВАЖНО: до вызова этой функции надо уничтожить все окна этого класса
    • ПРИМЕЧАНИЕ: классы зарегистрированные в DLL не анрегистрируются при выгрузке DLL из приложения
    • стили класса окна
      • там могут параметры типа CS_CLASSDC, что означает один DC на все окна этого класса (обратное - CS_OWNDC)
      • CS_DBLCLKS - отсылать сообщение о двойных кликах
      • CS_DROPSHADOW - эффект "тени" у окон этого класса
      • CS_GLOBALCLASS - зарегистрировать как глобальный класс
      • CS_(V)HREDRAW - перерисовка при смещении/растяжении по горизонтали(вертикали)
    • оконная процедура
      • LRESULT CALLBACK MainWndProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam) // second message parameter
  • типы классов: локальные, глобальные, системные

    • глобальные классы приложения
      • классы зарегестрированные в Exe или Dll и доступные ВСЕМ модулям этого процесса.
      • задается стилем CS_GLOBALCLASS
    • локальные классы приложения
      • регистрируется чтобы только .DLL и .EXE зарегистрировавшие его могли им пользоваться
      • обычно такие делают в одном экземпляре
      • для пояснение, зарегистрировав в DllMain локальный класс окна, для того, чтобы его вызвать, неолбходимо в параметре hInstance передать описатель .dll файла
    • системные классы
      • зарегистрированы системой, большинство из них доступны для использования всеми процессами
      • процессы не могут Unregister их
      • доступные пользователю классы
        • Button, ComboBox, Edit, ListBox, MDIClient, ScrollBar, Static
      • каждый процесс получает свою копию системных классов
      • система регистрирует их для процесса при первом вызове GDI функции из какого-либо потока процесса
    • совсем уж глобальные классы
      • через реестр можно добавить свою dll, регистрирующую класс окна, в список тех, которые подгружаются в КАЖДОМ процессе.
  • создание окон

    • HWND WINAPI CreateWindowEx(
      _In_      DWORD dwExStyle,        // расширенный стиль окна (позже)
      _In_opt_  LPCTSTR lpClassName,    // имя зарегистрированного ранее класса, ATOM или имя системного класса
      _In_opt_  LPCTSTR lpWindowName,    // имя окна, будет отображаться в titleBar
      _In_      DWORD dwStyle,            // стиль окна
      _In_      int x,                    // координаты окна (верхний левый угол)
      _In_      int y,                    // для значений по умолчанию используйте CW_USEDEFAULT
      _In_      int nWidth,                // ширина и высота окна
      _In_      int nHeight,            // CW_USEDEFAULT имеет смысл только для overlapped окон
      _In_opt_  HWND hWndParent,        // хэндл родительское окно
      _In_opt_  HMENU hMenu,            // хэндл меню
      _In_opt_  HINSTANCE hInstance,    // хэндл модуля, с которым будет ассоциироваться данное окно
      _In_opt_  LPVOID lpParam            // указатель на значение, которое будет передано окну через CREATESTRUCT
      
      );
    • притом отправляются сообщения (в таком порядке)
      • WM_NCCREATE
        • создание неклиентской части
        • должно вернуть TRUE
      • WM_CREATE
        • создано окно, еще не показано
        • должно вернуть 0
      • у обоих
        • wParam not used
        • lParam - казатель на CREATESTRUCT - структура хранящая все данные из CreateWindowEx
  • стили окна

    • стили
      • WS_CHILD(WINDOW) - дочернее ли окно
      • WS_BORDER - отобаржать ли гранциы окна
      • WS_CLIPCHILDREN - не перерисовывать детей при перерисовке родителя
      • MAXIMIZE, OVERLAPPED, SYSMENU, SIZEBOX etc...
    • расширенные стили
      • WS_EX_ACCEPTFILES возможность принимать фалйы drag & drop'ом
      • WS_EX_OVERLAPPEDWINDOW - создает overlapped окно
      • WS_EX_LAYERED - создает layered окно
      • WS_EX_TOPMOST - окно с повышенным приоритетом в z-order
      • различные работы с границами (отображать кграницу окна, клиентской зоны и т.д.)
      • скроллбары, окна-палитры, контекстная подсказка в заглоловке, работу с панелью задач (WS_EX_APPWNIDOW)
  • типы окон

    • top-level окно
      • окно, у которого нет родителей (или родитель - рабочий стол)
    • overlapped
      • top-level окно, создается сразу с заголовком, границами и клиентской чстью. Также может иметь скроллы, меню, minimize-maximize кнопки
      • обычно используется для главного окна приложения
    • popup
      • подвид overlapped окон, отличие - у него может не быть заголовка
      • обычно используется для диалогов, сообщений и других временных окон
    • child
      • обязательно имеет лишь клиентскую область, и при создании ОБЯЗАТЕЛЬНО указывать окно-родителя
        • родителем может быть popup, overlapped или child окно
      • может имтеь заголовок, меню,
      • обитает в клиентской зоне родительского окна
    • layered
      • понтовые визуальные эффекты игры с прозрачностью/затемненностью, удобын тем что при перерисовке он вваегда перерисовывает окна которые находятся под layered.
      • можно сделать top-level -> layered при помощи SetWindowLong или WS_EX_LAYERED (с Windows8 можно сделать layered child window )
      • SetLayeredWindowAttributes - настройка параметров
        • настройка, какие именно цвета будут прозрачными
          • для этого используется COLORREF // на самом деле это просто переопределенный DWORD
        • настройка самой прозрачности
    • message-only
      • используется только для получения/отправки сообщений, невидимо, не получает массово-расслыаемых сообщений (broadcast), просто перерабатывает сообщения
      • для создания такого окна надо в кач-ве hWndParent передать описатель HWND_MESSAGE или другое message-only окно
  • иерархия окон (child/parent owner/owned)

    • child/parent
      • пункт выше
    • owner/owned
      • иерархия появляется, когда не определен WS_CHILD, но указано дочернее окно
      • правила
        • owned окно всегда спереди своего owner'а
        • owned разрушается при разрушении owner'a
        • owned сворачивается при соворачивании owner'a
      • GetWindow( handle, GW_OWNER ) - функция для вытаскивания описателя owner'a
        • там также можно вытаскивать любые другие окнна в порядке Z-order
      • owner'ами могут быть только overlapped и pop-up окна
  • z-order

    • воображаемая ось, идушая от экрана к пользователю, чем выше координата окна на ней, тем больше других окон оно перекрывает
    • child'ы сгруппированы со своими родителями в этом порядке
    • на самом верху располгаются topmost окна, которые в z-order обязательно выше чем все сотальные типы окон (top-level например)
    • позиция окна меняется функциями
      • BringWindowToTop( handle )
  • изменеие положения и размеров окна

    • функция MoveWindow( HWND, x, y, w, h, repaint )
      • WM_WINDOWPOSCHANGING
        • wParam не используется
        • lParam - указатель на WINDOWPOS (новое положение)
      • WM_WINDOWPOSCHANGED
        • параметры см выше
      • WM_MOVE
        • wParam not used
        • lParam - левый верхний угол
      • WM_SIZE
        • wParam флаг, означающий как было изменен размер окна
        • lParam - размер клиентской части
        • тип запроса (минимайз/максимайз/рестор/для поп-апов)
      • WM_PAINT // если repaint - true
        • параметры не используются
  • background/foreground окна

    • foreground окно - окно с которым пользователем в данный момент работает (хреновое определение с msdn), поток, который это окно обрабатывает - foreground thread ( более простое обхяснение - САМОЕ ВЫСОКОЕ В Z-ORDER'е )
    • оно одно в каждый момент времени и достается при помощи GetForegroundWindow
    • его можно менять при помощи SetForegroundWindow, но это можно сделать лишь при одном из этих случаев (ограничения на ВЫЗЫВАЮЩИЙ процесс)
      • процесс щас foreground
      • процесс был запущен foreground процессом
      • процесс получил последний input event
      • нету foreground процесса в системе
      • foreground процесс в дебаггинге
      • foreground is not locked( LockSetForegroundWindow() )
      • foreground lock закончился
      • нету активных меню
    • если пользователь работает в дочернем окне, то foreground - окно родитель этого ребенка
    • если активация переключается между окнами РАЗНЫХ приложений
      • WM_ACTIVATEAPP
        • wParam
          • true если активируется, false если деактивируется
        • lParam
          • если wParam true, то это Id потока, чье окно дезактивируется
          • ---------- false------------------------------- активируется
    • если активация переключается между окнами ОДНОГО приложения
      • WM_ACTIVATE
        • wParam
          • указывает, окно деактивируется, активируется просто или кликом
        • lParam
          • хэндл другого окна (в зависимости от значения wParam оно дез или актив.)
  • focus

    • окно, которое перехватывает input с клавиатуры
    • тут для понимания необходимо помнить, что все виджеты - это системные окна
    • WM_KILLFOCUS
      • wParam - окно получившее фокус
      • lParam - не используется
    • WM_SETFOCUS
      • wParam - окно у которого отобрали фокус
      • lParam - не исп.
  • уничтожение окна

    • сначал WM_CLOSE (например при нажатии кнопки закрыть)
      • параметры не используются
      • тут можно показать всякие "вы уверены?"
    • затем вызвыают DestroyWindow
    • затем шлется WM_DESTROY
      • параметры не используются
      • отсылается когда окно убрано с экрана, сначала шлется родителю (когда придет очередь до убийства детей - пошлется и им)
      • родителю шлется еще до того, как дети будут уничтожаться
    • затем шлется WM_NCDESTROY
      • параметры не используются
      • шлется после того, как всех детей перебьют
      • тут уже можно высвобождать какую-либо память выделенная для этого окна и его детишек, все, кому она должна была потребоваться, уже убиты
  • скроллирование окон

    • WM_(H)VSCROLL
      • wParam - флаг, обозначающий, пользователь щас держит скроллбар, или только-только отпустить, сдвинут до конца, сдвинут на линию, сдвинут на страницу
      • lParam - если сообщение отослано некоторым контролом - хэндл контрола
    • int ScrollWindowEx(
        _In_   HWND hWnd,
        _In_   int dx,
        _In_   int dy
      
      , In const RECT *prcScroll, // позволяет скроллить часть клиентской области
        _In_   const RECT *prcClip,        // htubjy rjnjhsq gththbcjdsdfnmcz yt ,eltn
        _In_   HRGN hrgnUpdate,            // хэндл к региону, который должен быть помечен как невалидныей при скроллинге
        _Out_  LPRECT prcUpdate,        // результат
        _In_   UINT flags                // удаление или инвалидация области, скроллить ли дочерние окна, плавный скроллинг
      
      );