Blog. Just Blog

Получение и изменение обоев рабочего стола на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Тема обоев рабочего стола Windows уже поднималась тут несколько раз, но это были, в основном, какие-то готовые программные решения. Настало время заглянуть "под капот" системы и посмотреть, как оно устроено. А лучшего инструмента, чем Ассемблер, для этих целей сложно придумать.

Начнем с получения информации об установленных обоях рабочего стола. Тут ничего сложного, достаточно вызвать функцию SystemParametersInfo с параметром SPI_GETDESKWALLPAPER.
  1.         SPI_GETDESKWALLPAPER = 0x0073
  2.  
  3.         invoke  SystemParametersInfo,SPI_GETDESKWALLPAPER,\
  4.                 MAX_PATH,szPath,0
  5.         ; szPath -> строка пути к файлу обоев
После выполнения этого кода в переменную szPath будет записана строка с расположением файла обоев на диске. Больше никакой информации типа положения изображения получить нельзя. В результате экспериментов выяснилось, что при смене обоев через системное меню "Персонализация", выбранный файл с изображением копируется в папку с пользовательскими темами, а при программной установке остается на месте. Особой практической пользы в этом знании нет, просто интересный факт.

Теперь переходим к смене обоев рабочего стола. В интернетах для этих целей обычно рекомендуют использовать упомянутую выше функцию SystemParametersInfo с параметром SPI_SETDESKWALLPAPER. Код получается минимальный, все очень просто реализуется, выглядит на первый взгляд стильно, модно, молодежно.
  1. ; Путь к файлу с новыми обоями рабочего стола
  2. szPath  db 'c:\windows\wallpaper.bmp',0
  3.  
  4.         SPI_SETDESKWALLPAPER  = 20
  5.         SPIF_SENDWININICHANGE = 2
  6.         SPIF_UPDATEINIFILE    = 1
  7.  
  8.         invoke  SystemParametersInfo,SPI_SETDESKWALLPAPER,\
  9.                 0,szPath,SPIF_UPDATEINIFILE+SPIF_SENDWININICHANGE
Минусы этого способа перекрывают все плюсы. Нет возможности настраивать режим отображения обоев. Новые обои отображаются в том же положении, в котором были установлены текущие, если старое и новое изображения имеют разные пропорции, то результат будет печальным. А главное, что в некоторых случаях невозможно использовать файлы графических форматов кроме BMP, хотя через меню "Персонализация" они устанавливаются без вопросов.

Давайте сделаем все по-правильному, то есть с использованием технологии COM и системного интерфейса IActiveDesktop. FASM про все это колдунство вообще не в курсе, так что начинаем как обычно, то есть с описания структур, интерфейсов и GUID'ов.
  1. ; GUID {75048700-EF1F-11D0-9888-006097DEACF9}
  2. CLSID_ActiveDesktop dd 075048700h
  3.                     dw 0EF1Fh
  4.                     dw 011D0h
  5.                     db 098h, 088h, 000h, 060h, 097h, 0DEh, 0ACh, 0F9h
  6.  
  7. ; GUID {F490EB00-1240-11D1-9888-006097DEACF9}
  8. IID_IActiveDesktop dd 0F490EB00h
  9.                    dw 01240h
  10.                    dw 011D1h
  11.                    db 098h, 088h, 000h, 060h, 097h, 0DEh, 0ACh, 0F9h
  12.  
  13. ; IID_IActiveDesktop Interface
  14. struct IActiveDesktop
  15.     ; IUnknown
  16.     QueryInterface          dd ?   ; 000h
  17.     AddRef                  dd ?   ; 004h
  18.     Release                 dd ?   ; 008h
  19.     ; IActiveDesktop
  20.     ApplyChanges            dd ?   ; 00Ch
  21.     GetWallpaper            dd ?   ; 010h
  22.     SetWallpaper            dd ?   ; 014h
  23.     GetWallpaperOptions     dd ?   ; 018h
  24.     SetWallpaperOptions     dd ?   ; 01Ch
  25.     GetPattern              dd ?   ; 020h
  26.     SetPattern              dd ?   ; 024h
  27.     GetDesktopItemOptions   dd ?   ; 028h
  28.     SetDesktopItemOptions   dd ?   ; 02Ch
  29.     AddDesktopItem          dd ?   ; 030h
  30.     AddDesktopItemWithUI    dd ?   ; 034h
  31.     ModifyDesktopItem       dd ?   ; 038h
  32.     RemoveDesktopItem       dd ?   ; 03Ch
  33.     GetDesktopItemCount     dd ?   ; 040h
  34.     GetDesktopItem          dd ?   ; 044h
  35.     GetDesktopItemByID      dd ?   ; 048h
  36.     GenerateDesktopItemHtml dd ?   ; 04Ch
  37.     AddUrl                  dd ?   ; 050h
  38.     GetDesktopItemBySource  dd ?   ; 054h
  39. ends
  40.  
  41. ; Настройки отображения обоев
  42. struct WALLPAPEROPT
  43.     dwSize  dd ?
  44.     dwStyle dd ?
  45. ends
  46.  
  47. CLSCTX_INPROC_SERVER    = 1
  48. S_OK                    = 0
  49.  
  50. WPSTYLE_CENTER     = 0
  51. WPSTYLE_TILE       = 1
  52. WPSTYLE_STRETCH    = 2
  53. WPSTYLE_KEEPASPECT = 3
  54. WPSTYLE_CROPTOFIT  = 4
  55. WPSTYLE_SPAN       = 5
  56.  
  57. AD_APPLY_SAVE    = 1
  58. AD_APPLY_HTMLGEN = 2
  59. AD_APPLY_REFRESH = 4
  60. AD_APPLY_FORCE   = 8
  61. AD_APPLY_BUFFERED_REFRESH = 0x00000010
  62. AD_APPLY_DYNAMICREFRESH   = 0x00000020
  63. AD_APPLY_ALL = AD_APPLY_SAVE+AD_APPLY_HTMLGEN+AD_APPLY_REFRESH
Получить путь к файлу обоев можно при помощи метода GetWallpaper, а стиль отображения при помощи метода GetWallpaperOptions. В первом случае будет получена строка с именем файла, во втором - заполненная структура WALLPAPEROPT, в которой поле dwStyle отвечает за установленный стиль.
  1.         invoke  CoInitialize,0
  2.  
  3.         ; Создать объект
  4.         invoke  CoCreateInstance,CLSID_ActiveDesktop,NULL,\
  5.                 CLSCTX_INPROC_SERVER,\
  6.                 IID_IActiveDesktop,pIActDesk
  7.         cmp     eax,S_OK
  8.         jne     loc_exit
  9.  
  10.         ; Получить путь к файлу обоев
  11.         mov     eax, [pIActDesk]
  12.         mov     eax, [eax]
  13.         stdcall dword [eax+IActiveDesktop.GetWallpaper],\
  14.                 [pIActDesk],szPath,MAX_PATH,0
  15.  
  16.         ; Получить параметры отображения
  17.         mov     [wpOpt.dwSize],sizeof.WALLPAPEROPT
  18.         mov     eax, [pIActDesk]
  19.         mov     eax, [eax]
  20.         stdcall dword [eax+IActiveDesktop.GetWallpaperOptions],\
  21.                 [pIActDesk],wpOpt,0
  22.  
  23.         ; Прибраться за собой
  24.         mov     eax, [pIActDesk]
  25.         mov     eax, [eax]
  26.         stdcall dword [eax+IActiveDesktop.Release],[pIActDesk]
  27.  
  28.         ; szPath -> строка пути к файлу обоев
  29.         ; wpOpt.dwStyle -> стиль отображения обоев
  30.  
  31. loc_exit:
  32.         ; Удалить объект
  33.         invoke  CoUninitialize
За изменение обоев рабочего стола отвечает метод SetWallpaper. Он принимает в качестве параметра юникодную строку с полным именем графического файла. Чтобы поменять стиль отображения надо заполнить структуру WALLPAPEROPT и вызвать метод SetWallpaperOptions, причем стиль можно менять независимо от самих обоев. Чтобы зафиксировать внесенные изменения, последним действием надо вызвать метод ApplyChanges.
  1.         invoke  CoInitialize,0
  2.  
  3.         ; Создать объект
  4.         invoke  CoCreateInstance,CLSID_ActiveDesktop,NULL,\
  5.                 CLSCTX_INPROC_SERVER,\
  6.                 IID_IActiveDesktop,pIActDesk
  7.         cmp     eax,S_OK
  8.         jne     loc_exit
  9.  
  10.         ; Установить новые обои рабочего стола
  11.         mov     eax, [pIActDesk]
  12.         mov     eax, [eax]
  13.         stdcall dword [eax+IActiveDesktop.SetWallpaper],\
  14.                 [pIActDesk],szPath,0
  15.  
  16.         ; Установить параметры отображения
  17.         mov     [wpOpt.dwSize],sizeof.WALLPAPEROPT
  18.         mov     [wpOpt.dwStyle],WPSTYLE_CENTER
  19.  
  20.         mov     eax, [pIActDesk]
  21.         mov     eax, [eax]
  22.         stdcall dword [eax+IActiveDesktop.SetWallpaperOptions],\
  23.                 [pIActDesk],wpOpt,0
  24.  
  25.         ; Применить изменения
  26.         mov     eax, [pIActDesk]
  27.         mov     eax, [eax]
  28.         stdcall dword [eax+IActiveDesktop.ApplyChanges],[pIActDesk],\
  29.                 AD_APPLY_ALL
  30.  
  31.         ; Прибраться за собой
  32.         mov     eax, [pIActDesk]
  33.         mov     eax, [eax]
  34.         stdcall dword [eax+IActiveDesktop.Release],[pIActDesk]
  35.  
  36. loc_exit:
  37.         ; Удалить объект
  38.         invoke  CoUninitialize
В приложении примеры программ с исходными текстами, которые получают и меняют обои рабочего стола различными способами. Самих файлов, упомянутых в исходниках, не прилагается, с этим разберетесь как-нибудь самостоятельно.

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

Get.Set.Desktop.Wallpaper.Demo.zip (6,316 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (19.01.2023 в 14:58):
Да я никуда не тороплюсь. Работает и ладно.
Grey (19.01.2023 в 14:53):
На 32 битах до пенсии не просидишь). Консерватизм думаю связан с неудобством восприятия таких длинных чисел. Да и разработчики компиляторов и дебагеров, если не на 64 то 128 битах задумаются о замене hex-представления на более высокие порядки.

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

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

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