Blog. Just Blog

Как программно свернуть все окна

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Есть разные способы программно свернуть все открытые окна. Простой и топорный вариант решения - эмуляция нажатия клавиш Win+M, которые и выполняют команду "Свернуть все окна". Делается это через последовательность вызовов keybd_event.
  1.         ; Эмуляция нажатия клавиш Win+M
  2.         invoke  keybd_event,VK_LWIN,0,0,NULL
  3.         invoke  Sleep,1
  4.         invoke  keybd_event,'M',0,0,NULL
  5.         invoke  Sleep,1
  6.         invoke  keybd_event,VK_LWIN,0,KEYEVENTF_KEYUP,NULL
Для обратного действия надо сэмулировать нажатие комбинации Win+Shift+M:
  1.         ; Эмуляция нажатия клавиш Win+Shift+M
  2.         invoke  keybd_event,VK_LWIN,0,0,NULL
  3.         invoke  Sleep,1
  4.         invoke  keybd_event,VK_LSHIFT,0,0,NULL
  5.         invoke  Sleep,1
  6.         invoke  keybd_event,'M',0,0,NULL
  7.         invoke  Sleep,1
  8.         invoke  keybd_event,VK_LSHIFT,0,KEYEVENTF_KEYUP,NULL
  9.         invoke  Sleep,1
  10.         invoke  keybd_event,VK_LWIN,0,KEYEVENTF_KEYUP,NULL
Таким же образом эмулируется нажатие комбинации Win+D - "Показать рабочий стол". Решение, в принципе, рабочее, но целиком полагаться на программную эмуляцию клавиатуры нельзя. Нажатие клавиш может перехватить или переопределить другое приложение, может быть заполнена системная очередь ввода, да мало ли чего.

Еще одно решение основано на эмуляции сообщений контекстного меню панели задач. Окну панели задач через SendMessage отправляется команда, как будто пользователь открыл контекстное меню и в нем выбрал пункт "Показать рабочий стол" или противоположный ему "Показать все окна" (аналог комбинации клавиш Win+D).
  1.         push    NULL
  2.         call    @f
  3.         db      'Shell_TrayWnd',0
  4. @@:
  5.         invoke  FindWindow
  6.         invoke  SendMessage,eax,WM_COMMAND,0x197,0
В том или ином виде на разных сайтах и форумах этот пример часто приводят как решение задачи по сворачиванию окон. Но, как говорится, есть нюансы. Во-первых, абсолютно везде бездумно копируется неправильный код команды 0x19F (аналог команды Win+M - "Свернуть все окна"), во-вторых, при использовании альтернативной оболочки типа Aston в системе может вообще не оказаться окна Shell_TrayWnd, а в-третьих, нет никакой гарантии, что в какой-нибудь следующей версии Windows команда меню не изменит свой код с 0x197 на другой. Так что этот способ можно считать условно рабочим, да и то с большой натяжкой.

Правильным решением здесь будет обращение напрямую к оболочке Windows, чтобы она выполнила указанные действия. Именно так я поступил при написании некоторых своих программ. Оболочка представляет собой COM-объект Shell, который в свою очередь имеет много объектов для выполнения различных задач. Нас интересует объект IShellDispatch, так как в его интерфейсе есть методы для сворачивания и разворачивания всех окон, аналогичные нажатию Win+M и Win+Shift+M. Для доступа к COM-объектам первым делом надо обозначить их GUID:
  1. ; GUID {13709620-C279-11CE-A409-444553540000}
  2. CLSID_Shell        dd 013709620h
  3.                    dw 0C279h
  4.                    dw 011CEh
  5.                    db 0A4h, 09Eh, 044h, 045h, 053h, 054h, 000h, 000h
  6.  
  7. ; GUID {D8F015C0-C278-11CE-A409-444553540000}
  8. IID_IShellDispatch dd 0D8F015C0h
  9.                    dw 0C278h
  10.                    dw 011CEh
  11.                    db 0A4h, 09Eh, 044h, 045h, 053h, 054h, 000h, 000h
Теперь опишем интерфейс IShellDispatch, удобнее всего это делать в виде структуры, так будет меньше путаницы с индексами вызываемых методов. По какой-то непонятной логике на сайте MSDN названия методов идут в алфавитном порядке, а не так, как они фактически представлены в интерфейсе, так что в официальную документацию можно заглядывать только за описанием параметров этих методов.
  1. ; IID_IShellDispatch Interface
  2. struct IShellDispatch
  3.     QueryInterface          dd ?
  4.     AddRef                  dd ?
  5.     Release                 dd ?
  6.  
  7.     GetTypeInfoCount        dd ?
  8.     GetTypeInfo             dd ?
  9.     GetIDsOfNames           dd ?
  10.     _Invoke                 dd ?
  11.  
  12.     get_Application         dd ?
  13.     get_Parent              dd ?
  14.     NameSpace               dd ?
  15.     BrowseForFolder         dd ?
  16.     Windows                 dd ?
  17.     Open                    dd ?
  18.     Explore                 dd ?
  19.     MinimizeAll             dd ?
  20.     UndoMinimizeALL         dd ?
  21.     FileRun                 dd ?
  22.     CascadeWindows          dd ?
  23.     TileVertically          dd ?
  24.     TileHorizontally        dd ?
  25.     ShutdownWindows         dd ?
  26.     Suspend                 dd ?
  27.     EjectPC                 dd ?
  28.     SetTime                 dd ?
  29.     TrayProperties          dd ?
  30.     Help                    dd ?
  31.     FindFiles               dd ?
  32.     FindComputer            dd ?
  33.     RefreshMenu             dd ?
  34.     ControlPanelItem        dd ?
  35. ends
Все исходные данные у нас есть, можно приступать к программированию. Создаем объект Shell с интерфейсом IShellDispatch, затем вызываем метод MinimizeAll, соответствующий комбинации клавиш Win+M.
  1.         ; Инициализировать COM-объект
  2.         invoke  CoInitialize,NULL
  3.         ; Создать объект
  4.         invoke  CoCreateInstance,CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,\
  5.                 IID_IShellDispatch,pIShDisp
  6.  
  7.         ; Вызвать метод интерфейса MinimizeAll
  8.         mov     eax,[pIShDisp]
  9.         mov     eax,[eax]
  10.         stdcall dword [eax+IShellDispatch.MinimizeAll],[pIShDisp]
  11.  
  12.         mov     eax,[pIShDisp]
  13.         mov     eax,[eax]
  14.         stdcall dword [eax+IShellDispatch.Release],[pIShDisp]
  15.  
  16.         ; Удалить объект
  17.         invoke  CoUninitialize
При выполнении этого кода все открытые окна будут мгновенно свернуты. Для обратного действия надо вызвать метод UndoMinimizeALL, аналогичный нажатию клавиш Win+Shift+M. Тут следует понимать, что действует он в точности как и клавиатурная комбинация, то есть при наличии хоть одного открытого окна ничего не произойдет.

Теперь для полного комплекта давайте программно реализуем операцию "Показать рабочий стол", которая вызывается комбинацией клавиш Win+D. Ее ошибочно приравнивают к команде "Свернуть все окна", но фактически это не так, хотя она выполняет похожее действие. За показ рабочего стола отвечает метод ToggleDesktop из интерфейса IShellDispatch4, который является расширением для IShellDispatch3, который является расширением для IShellDispatch2, который, как вы уже догадались, является расширением для уже знакомого нам объекта IShellDispatch. Объект IShellDispatch4 имеет другой GUID, его надо прописать вместо указанного выше.
  1. ; GUID {EFD84B2D-4BCF-4298-BE25-EB542A59FBDA}
  2. IID_IShellDispatch4 dd 0EFD84B2Dh
  3.                     dw 04BCFh
  4.                     dw 04298h
  5.                     db 0BEh, 025h, 0EBh, 054h, 02Ah, 059h, 0FBh, 0DAh
Структура со списком доступных методов также будет расширена. Чтобы не мелочиться, я сразу прописал тут все методы до IShellDispatch6 включительно. Для вызова методов IShellDispatch5 и дальше, достаточно заменить в описании GUID на нужный.
  1. ; IID_IShellDispatch Interface
  2. struct IShellDispatch
  3.     QueryInterface          dd ?
  4.     AddRef                  dd ?
  5.     Release                 dd ?
  6.  
  7.     GetTypeInfoCount        dd ?
  8.     GetTypeInfo             dd ?
  9.     GetIDsOfNames           dd ?
  10.     _Invoke                 dd ?
  11.  
  12.     ; IShellDispatch
  13.     ; {D8F015C0-C278-11CE-A49E-444553540000}
  14.     get_Application         dd ?
  15.     get_Parent              dd ?
  16.     NameSpace               dd ?
  17.     BrowseForFolder         dd ?
  18.     Windows                 dd ?
  19.     Open                    dd ?
  20.     Explore                 dd ?
  21.     MinimizeAll             dd ?
  22.     UndoMinimizeALL         dd ?
  23.     FileRun                 dd ?
  24.     CascadeWindows          dd ?
  25.     TileVertically          dd ?
  26.     TileHorizontally        dd ?
  27.     ShutdownWindows         dd ?
  28.     Suspend                 dd ?
  29.     EjectPC                 dd ?
  30.     SetTime                 dd ?
  31.     TrayProperties          dd ?
  32.     Help                    dd ?
  33.     FindFiles               dd ?
  34.     FindComputer            dd ?
  35.     RefreshMenu             dd ?
  36.     ControlPanelItem        dd ?
  37.  
  38.     ; IShellDispatch2
  39.     ; {A4C6892C-3BA9-11D2-9DEA-00C04FB16162}
  40.     IsRestricted            dd ?
  41.     ShellExecute            dd ?
  42.     FindPrinter             dd ?
  43.     GetSystemInformation    dd ?
  44.     ServiceStart            dd ?
  45.     ServiceStop             dd ?
  46.     IsServiceRunning        dd ?
  47.     CanStartStopService     dd ?
  48.     ShowBrowserBar          dd ?
  49.  
  50.     ; IShellDispatch3
  51.     ; {177160CA-BB5A-411C-841D-BD38FACDEAA0}
  52.     AddToRecent             dd ?
  53.  
  54.     ; IShellDispatch4
  55.     ; {EFD84B2D-4BCF-4298-BE25-EB542A59FBDA}
  56.     WindowsSecurity         dd ?
  57.     ToggleDesktop           dd ?
  58.     ExplorerPolicy          dd ?
  59.     GetSetting              dd ?
  60.  
  61.     ; IShellDispatch5
  62.     ; {866738B9-6CF2-4DE8-8767-F794EBE74F4E}
  63.     WindowSwitcher          dd ?
  64.  
  65.     ; IShellDispatch6
  66.     ; {286E6F1B-7113-4355-9562-96B7E9D64C54}
  67.     SearchCommand           dd ?
  68. ends
Основной код практически не изменится, только поменяется название GUID и вызывать мы будем метод ToggleDesktop. Обратного действия для него нет, он является переключателем, то есть при первом вызове убирает все окна и показывает десктоп, а при повторном вызове возвращает все окна на место.
  1.         ; Инициализировать COM-объект
  2.         invoke  CoInitialize,NULL
  3.         ; Создать объект
  4.         invoke  CoCreateInstance,CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,\
  5.                 IID_IShellDispatch4,pIShDisp
  6.  
  7.         ; Вызвать метод интерфейса ToggleDesktop
  8.         mov     eax, [pIShDisp]
  9.         mov     eax, [eax]
  10.         stdcall dword [eax+IShellDispatch.ToggleDesktop],[pIShDisp]
  11.  
  12.         mov     eax, [pIShDisp]
  13.         mov     eax, [eax]
  14.         stdcall dword [eax+IShellDispatch.Release],[pIShDisp]
  15.  
  16.         ; Удалить объект
  17.         invoke  CoUninitialize
Теперь, когда вы освоили работу с объектом Shell, вы можете задействовать и другие методы, например, работу с системными службами, упорядочивание окон на экране и т.д. Описание конкретных методов, как я уже говорил, смотрите на сайте MSDN.

В приложении примеры программ с исходными текстами, которые демонстрируют все описанные в статье действия по сворачиванию и разворачиванию окон.

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

Minimize.Maximize.Demo.zip (8,432 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (25.09.2020 в 12:21):
Ну а если задуматься, то при компиляции исходников получится ровно такой же файл, на который этот же недоантивирус встанет в стойку.

Что же касается просьбы не добавлять исполняемые файлы в примеры, то это сделано не просто так. Лично мне, например, гораздо удобнее, если в каком-нибудь решении, которое я ищу, сразу будет исполняемый файл. Можно посмотреть и убедиться, что он решает задачу именно так, как мне надо. Дальше. Языков программирования сотни, знать их все со всеми диалектами нереально. И очень часто нужные мне решения встречаются реализованными на языках, на которых я совсем не пишу и синтаксис которых вызывает у меня затруднения и необходимость тратить дополнительное время на поиски. Это могут быть какие-то структуры, интерфейсы, объекты, специфические языковые конструкции и тому подобное. Что ж мне, держать на компе 100500 сред разработки на все случаи жизни, да еще и разбираться в каждой? Мне проще будет дизассемблировать готовый файл и посмотреть, как тот или иной кусок исходника компилятор собрал в машинный код и затем перевести его в ассемблерный вариант. Так что нет, у меня всегда будет исходник и готовый файл. А антивирус лучше все-таки поменять на нормальный.
NeshAliNehrin (25.09.2020 в 11:48):
Чёртовы параноики. Вся моя тяга к самообразованию и доверие к исходникам уважаемого Manhunter'a натыкается на препятствие. Kaspersky Free упорно блокирует загрузку Minimize.Maximize.Demo.zip
Я, конечно, вырублю антивирус, скачаю архив и уберу экзешник, чтобы ознакомиться с листингом, но предпочёл-бы откомпилировать сырцы в фасме самостоятельно, без оглядки на ложные срабатывания по подозрениям.
Своё нытьё заканчиваю просьбой запаковывать текст без исполняемой программы.
ManHunter (05.09.2019 в 17:08):
toor, добавил в статью инфу о Shell_TrayWnd, почитай, пригодится. Архив с исходниками обновлен.
ManHunter (05.09.2019 в 16:17):
toor, это плохое решение. Некоторые приложения не реагируют на такой вызов и оставляют свои окна на месте. Навскидку: TheBat!, IDA, может еще какие-то.
toor (05.09.2019 в 12:44):
еще вариант

procedure MinimizeAll;
var
  Wnd: HWND;
begin
   Wnd := FindWindow('Shell_TrayWnd', nil);
   if Wnd <> 0 then
      SendMessage(Wnd, WM_COMMAND, $019F, 0);
end;

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

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

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