Blog. Just Blog

Работа с Desktop Window Manager на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Работа с Desktop Window Manager на Ассемблере
Работа с Desktop Window Manager на Ассемблере

Начиная с Windows Vista, в составе системы появился Desktop Window Manager, он же Диспетчер рабочего стола. Этот компонент обеспечивает визуальные эффекты и возможности интерфейса Windows Aero, например, такие как полупрозрачные заголовки окон, Aero Peek, Flip3D и живые миниатюры окон на таскбаре при наведении на него мышкой. Для взаимодействия с Desktop Window Manager разработчикам программ предоставляется целый набор функций API, с некоторыми из этих функций мы сегодня научимся работать.

Чтобы начать работу с Desktop Window Manager, надо сперва проверить, на какой операционной системе запущено приложение, затем убедиться, что DWM доступен. Все функции импортируются из библиотеки dwmapi.dll. Чтобы проверить, включен ли в системе DWM, достаточно воспользоваться функцией DwmIsCompositionEnabled. Включить или выключить можно функцией DwmEnableComposition. Обратите внимание, что она доступна только до Windows 7, на более старших системах Диспетчер рабочего стола активен всегда, остановить его нельзя, а вызов DwmEnableComposition с любыми параметрами всегда будет возвращать успешный результат. Давайте посмотрим, что можно сделать при помощи Desktop Window Manager.

Окно с эффектом Blur
Окно с эффектом Blur

Начнем с эффекта размытия. Несмотря на то, что визуально он немного похож на эффект прозрачности, это, скорее эффект "мутного стекла". Он применяется к любому видимому окну при помощи функции DwmEnableBlurBehindWindow. В FASM предварительно надо описать структуру параметров и значения флагов для работы с этой функцией:
  1. struct DWM_BLURBEHIND
  2.   dwFlags  dd ?
  3.   fEnable  dd ?
  4.   hRgnBlur dd ?
  5.   fTransitionOnMaximized dd ?
  6. ends
  7.  
  8. DWM_BB_ENABLE                = 0x00000001
  9. DWM_BB_BLURREGION            = 0x00000002
  10. DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004
Вызов очень простой. На этапе инициализации или создания окна к нему применяется эффект размытия:
  1.         ; Включить эффект размытия
  2.         mov     [bb.dwFlags],DWM_BB_ENABLE
  3.         mov     [bb.fEnable],TRUE
  4.         mov     [bb.fTransitionOnMaximized],FALSE
  5.         mov     [bb.hRgnBlur],0
  6.         invoke  DwmEnableBlurBehindWindow,[hwnddlg],bb
Важное замечание. Чтобы эффект сработал, окно должно быть черного цвета, иначе получится полная ерунда. Для этого обратимся к одной из предыдущих статей. Здесь я этот материал дублировать не буду, полностью рабочий пример смотрите в прилагаемых исходниках.

Окно с эффектом "стекла"
Окно с эффектом "стекла"

Интересное дополнение к эффекту размытия - задание боковых отступов окна, на которые эффект будет распространяться. Отступы могут быть как одинаковые, так и разные с любой стороны окна. Это делается при помощи функции DwmExtendFrameIntoClientArea. Определяем структуру:
  1. struct MARGINS
  2.   cxLeftWidth    dd ?
  3.   cxRightWidth   dd ?
  4.   cyTopHeight    dd ?
  5.   cyBottomHeight dd ?
  6. ends
Но обычные отступы даже с размытием, на мой взгляд, смотрятся как-то не очень. Зато если задать хоть один отрицательный отступ, то окно станет полностью "стеклянным". Вот это действительно выглядит симпатично.
  1.         ; Включить эффект размытия
  2.         mov     [bb.dwFlags],DWM_BB_ENABLE
  3.         mov     [bb.fEnable],TRUE
  4.         mov     [bb.fTransitionOnMaximized],FALSE
  5.         mov     [bb.hRgnBlur],0
  6.         invoke  DwmEnableBlurBehindWindow,[hwnddlg],bb
  7.  
  8.         ; Установить отрицательный отступ для "стеклянного" окна
  9.         mov     [margins.cyBottomHeight],-1
  10.         invoke  DwmExtendFrameIntoClientArea,[hwnddlg],margins
Не забываем про установку черного фона окна перед тем, как применять все эти эффекты.

Консольное окно с эффектом Blur
Консольное окно с эффектом Blur

Эффект размытия можно применять даже к консольным окнам. Что хорошо, тут даже не придется изгаляться с цветом окна - консолька по умолчанию и так черного цвета.
  1.         ; Получить хэндл консольного окна
  2.         invoke  GetConsoleWindow
  3.         ; Включить эффект размытия
  4.         mov     [bb.dwFlags],DWM_BB_ENABLE
  5.         mov     [bb.fEnable],TRUE
  6.         mov     [bb.hRgnBlur],NULL
  7.         invoke  DwmEnableBlurBehindWindow,eax,bb
Следующий трюк - установка атрибутов, определяющих поведение окон в системе. Атрибутов достаточно много, некоторые из них мы разберем.
  1. DWMWA_NCRENDERING_ENABLED         = 1
  2. DWMWA_NCRENDERING_POLICY          = 2
  3. DWMWA_TRANSITIONS_FORCEDISABLED   = 3
  4. DWMWA_ALLOW_NCPAINT               = 4
  5. DWMWA_CAPTION_BUTTON_BOUNDS       = 5
  6. DWMWA_NONCLIENT_RTL_LAYOUT        = 6
  7. DWMWA_FORCE_ICONIC_REPRESENTATION = 7
  8. DWMWA_FLIP3D_POLICY               = 8
  9. DWMWA_EXTENDED_FRAME_BOUNDS       = 9
  10. DWMWA_HAS_ICONIC_BITMAP           = 10
  11. DWMWA_DISALLOW_PEEK               = 11
  12. DWMWA_EXCLUDED_FROM_PEEK          = 12
  13. DWMWA_CLOAK                       = 13
  14. DWMWA_CLOAKED                     = 14
  15. DWMWA_FREEZE_REPRESENTATION       = 15
  16. DWMWA_LAST                        = 16
Изменять атрибуты окна можно при помощи функции DwmSetWindowAttribute, а получать установленные атрибуты, соответственно, функцией DwmGetWindowAttribute.

Окно исключено из Aero Peek
Окно исключено из Aero Peek

Например, чтобы исключить окно из Aero Peek, достаточно вызвать следующий код:
  1.     mov     [attrValue],1
  2.     invoke  DwmSetWindowAttribute,[hwnddlg],DWMWA_EXCLUDED_FROM_PEEK,attrValue,4
Если теперь нажать комбинацию Win+Space или навести курсор на кнопку "показать рабочий стол", то от всех окон останутся только контуры, а наше окно будет отображаться как ни в чем не бывало. Такое поведение окон является нестандартным для системы, поэтому использовать его надо только при реальной необходимости.

Окно исключено из Flip3D
Окно исключено из Flip3D

Установка следующего флага "выбьет" окно из обработки Flip3D (трехмерный переключатель окон, вызываемый комбинацией Win+Tab) и расположит поверх "колоды" листаемых окон.
  1. DWMFLIP3D_EXCLUDEBELOW = 1
  2. DWMFLIP3D_EXCLUDEABOVE = 2
  1.         mov     [attrValue],DWMFLIP3D_EXCLUDEABOVE
  2.         invoke  DwmSetWindowAttribute,[hwnddlg],DWMWA_FLIP3D_POLICY,attrValue,4
По результатам тестирования, при установке параметра DWMFLIP3D_EXCLUDEABOVE, после выбора любого окна через Flip3D, окну нашего приложения принудительно присваивается атрибут "поверх всех окон". С параметром DWMFLIP3D_EXCLUDEBELOW положение окна не меняется.

Трансляция рабочего стола на окно приложения
Трансляция рабочего стола на окно приложения

Самая интересная, на мой взгляд, функция Desktop Window Manager - возможность транслировать в режиме реального времени содержимое любого окна в другое. Например, вы можете в своем окне отобразить "живую" миниатюру рабочего стола. Любые изменения, сделанные на рабочем столе, будут сразу же отображены в вашем приложении. Как всегда, начинаем с описания необходимых структур и констант:
  1. ; Структура для работы с превьюшками
  2. struct DWM_THUMBNAIL_PROPERTIES
  3.   dwFlags       dd ?
  4.   rcDestination RECT
  5.   rcSource      RECT
  6.   opacity       db ?
  7.   fVisible      dd ?
  8.   fSourceClientAreaOnly dd ?
  9. ends
  10.  
  11. DWM_TNP_RECTDESTINATION      = 0x00000001
  12. DWM_TNP_RECTSOURCE           = 0x00000002
  13. DWM_TNP_OPACITY              = 0x00000004
  14. DWM_TNP_VISIBLE              = 0x00000008
  15. DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010
Теперь надо связать нужное окно с окном нашего приложения. Делается это при помощи двух функций: DwmRegisterThumbnail и DwmUpdateThumbnailProperties
  1.         ; Получить хэндл рабочего стола
  2.         invoke  FindWindow,szProgman,0
  3.  
  4.         ; Ну или какой-нибудь известный хэндл окна другого приложения
  5.         ; mov     eax,0x00030802
  6.  
  7.         ; Связать наше окно с превьюшкой исходного окна
  8.         invoke  DwmRegisterThumbnail,[hwnddlg],eax,hThumb
  9.         mov     eax,[hThumb]
  10.  
  11.         ; Отобразить "живую" превьюшку исходного окна на нашем окне
  12.         mov     [props.dwFlags],\
  13.                 DWM_TNP_VISIBLE+DWM_TNP_OPACITY+DWM_TNP_RECTDESTINATION
  14.         mov     [props.fSourceClientAreaOnly],FALSE
  15.         mov     [props.fVisible],TRUE
  16.         mov     [props.opacity],200
  17.         invoke  GetClientRect,[hwnddlg],props.rcDestination
  18.         invoke  DwmUpdateThumbnailProperties,[hThumb],props
После связки окон никаких действий с нашей стороны больше не требуется. Все изменения, происходящие на основном окне, незамедлительно будут транслироваться в окно с превьюшкой. Для разрыва связки окон используется функция DwmUnregisterThumbnail.

Пользовательский thumbnail для приложения
Пользовательский thumbnail для приложения

Последняя функция Desktop Window Manager, о которой хотелось бы сегодня рассказать, это работа с превьюшкой окна приложения на панели задач. Как вы знаете, если навести курсор на панель задач, то там появятся миниатюры окон. Так вот, вместо уменьшенного изображения окна, туда можно поместить любое другое изображение. Начинаем с константы:
  1. WM_SENDICONICTHUMBNAILBITMAP = 0x0323
При создании окна ему надо установить атрибуты, сообщающие системе, что окно использует собственную превьюшку.
  1. ; Установить атрибуты окна
  2.         mov     [attrValue],1
  3.         invoke  DwmSetWindowAttribute,[hwnddlg],\
  4.                 DWMWA_HAS_ICONIC_BITMAP,attrValue,4
  5.         invoke  DwmSetWindowAttribute,[hwnddlg],\
  6.                 DWMWA_FORCE_ICONIC_REPRESENTATION,attrValue,4
Теперь самое главное - взаимодействие системы с окном нашего приложения. Когда пользователь наводит курсор на панель задач, окну отправляется системное сообщение WM_SENDICONICTHUMBNAILBITMAP. В параметре lParam сообщения, в старшем и младшем WORD'е передается размер изображения, которую система хотела бы получить в качестве превьюшки. С помощью функции DwmSetIconicThumbnail наше приложение может установить собственное изображение.
  1.         ; Установить превьюшку
  2.         cmp     [msg],WM_SENDICONICTHUMBNAILBITMAP
  3.         je      .thumb
  4.         ...
  5.         ...
  6.         ...
  7.  
  8.   .thumb:
  9.         ; Размеры запрашиваемого изображения для превьюшки
  10.         mov     eax,[lparam]
  11.         and     eax,0FFFFh
  12.         ; EAX = Высота
  13.         mov     eax,[lparam]
  14.         shr     eax,16
  15.         ; EAX = Ширина
  16.  
  17.         ; Установить собственную превьюшку
  18.         invoke  GetModuleHandle,0
  19.         invoke  LoadImage,eax,1,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION
  20.         invoke  DwmSetIconicThumbnail,[hwnddlg],eax,0
Изображение может быть загружено с диска или, как в этом примере, получено из ресурсов файла. При необходимости оно должно быть подогнано под запрашиваемый размер. Если изображение хотя бы по одной из координат окажется больше запрошенного размера, то оно не будет отображаться. Важно, что изображение обязательно должно быть с глубиной цвета 32 бит, иначе оно также не будет отображаться на превьюшке.

В приложении примеры программ с исходными текстами, реализующие все описанные в статье эффекты и функции.

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

Desktop.Window.Manager.Demo.zip (53,574 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 3730 | Комментариев: 6

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (07.07.2018 в 20:36):
Да мне как-то пофиг чо там налепили в Windows 10 и почему под этой недосистемой не работает. Пример написан и работает под Windows 7, остальное мне не интересно.
Илья (07.07.2018 в 20:30):
Здравствуйте, пример не работает под win10. Не могли бы вы обновить статью?; Желательно добавив пример custom title-bar.
ManHunter (25.02.2018 в 15:27):
Самое время перейти на нормальный антивирус.
казявка (21.10.2017 в 05:10):
из скачанного архива антивирус сразу же послал в карантин 4 файла :
http://funkyimg.com/i/2ywNx.png
Андрей (02.03.2017 в 18:20):
Спасибо за статью.

Оффтоп. Добавь в окна эффект мутных окон-)
brute (02.03.2017 в 10:02):
выглядит круто! Надо будет на PB повторить..

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0046 сек.) / Память: 4.5 Mb
Наверх