Как программно свернуть все окна
Есть разные способы программно свернуть все открытые окна. Простой и топорный вариант решения - эмуляция нажатия клавиш Win+M, которые и выполняют команду "Свернуть все окна". Делается это через последовательность вызовов keybd_event.Code (Assembler) : Убрать нумерацию
- ; Эмуляция нажатия клавиш Win+M
- invoke keybd_event,VK_LWIN,0,0,NULL
- invoke Sleep,1
- invoke keybd_event,'M',0,0,NULL
- invoke Sleep,1
- invoke keybd_event,VK_LWIN,0,KEYEVENTF_KEYUP,NULL
Code (Assembler) : Убрать нумерацию
- ; Эмуляция нажатия клавиш Win+Shift+M
- invoke keybd_event,VK_LWIN,0,0,NULL
- invoke Sleep,1
- invoke keybd_event,VK_LSHIFT,0,0,NULL
- invoke Sleep,1
- invoke keybd_event,'M',0,0,NULL
- invoke Sleep,1
- invoke keybd_event,VK_LSHIFT,0,KEYEVENTF_KEYUP,NULL
- invoke Sleep,1
- invoke keybd_event,VK_LWIN,0,KEYEVENTF_KEYUP,NULL
Еще одно решение основано на эмуляции сообщений контекстного меню панели задач. Окну панели задач через SendMessage отправляется команда, как будто пользователь открыл контекстное меню и в нем выбрал пункт "Показать рабочий стол" или противоположный ему "Показать все окна" (аналог комбинации клавиш Win+D).
Code (Assembler) : Убрать нумерацию
- push NULL
- call @f
- db 'Shell_TrayWnd',0
- @@:
- invoke FindWindow
- invoke SendMessage,eax,WM_COMMAND,0x197,0
Правильным решением здесь будет обращение напрямую к оболочке Windows, чтобы она выполнила указанные действия. Именно так я поступил при написании некоторых своих программ. Оболочка представляет собой COM-объект Shell, который в свою очередь имеет много объектов для выполнения различных задач. Нас интересует объект IShellDispatch, так как в его интерфейсе есть методы для сворачивания и разворачивания всех окон, аналогичные нажатию Win+M и Win+Shift+M. Для доступа к COM-объектам первым делом надо обозначить их GUID:
Code (Assembler) : Убрать нумерацию
- ; GUID {13709620-C279-11CE-A409-444553540000}
- CLSID_Shell dd 013709620h
- dw 0C279h
- dw 011CEh
- db 0A4h, 09Eh, 044h, 045h, 053h, 054h, 000h, 000h
- ; GUID {D8F015C0-C278-11CE-A409-444553540000}
- IID_IShellDispatch dd 0D8F015C0h
- dw 0C278h
- dw 011CEh
- db 0A4h, 09Eh, 044h, 045h, 053h, 054h, 000h, 000h
Code (Assembler) : Убрать нумерацию
- ; IID_IShellDispatch Interface
- struct IShellDispatch
- QueryInterface dd ?
- AddRef dd ?
- Release dd ?
- GetTypeInfoCount dd ?
- GetTypeInfo dd ?
- GetIDsOfNames dd ?
- _Invoke dd ?
- get_Application dd ?
- get_Parent dd ?
- NameSpace dd ?
- BrowseForFolder dd ?
- Windows dd ?
- Open dd ?
- Explore dd ?
- MinimizeAll dd ?
- UndoMinimizeALL dd ?
- FileRun dd ?
- CascadeWindows dd ?
- TileVertically dd ?
- TileHorizontally dd ?
- ShutdownWindows dd ?
- Suspend dd ?
- EjectPC dd ?
- SetTime dd ?
- TrayProperties dd ?
- Help dd ?
- FindFiles dd ?
- FindComputer dd ?
- RefreshMenu dd ?
- ControlPanelItem dd ?
- ends
Code (Assembler) : Убрать нумерацию
- ; Инициализировать COM-объект
- invoke CoInitialize,NULL
- ; Создать объект
- invoke CoCreateInstance,CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,\
- IID_IShellDispatch,pIShDisp
- ; Вызвать метод интерфейса MinimizeAll
- mov eax,[pIShDisp]
- mov eax,[eax]
- stdcall dword [eax+IShellDispatch.MinimizeAll],[pIShDisp]
- mov eax,[pIShDisp]
- mov eax,[eax]
- stdcall dword [eax+IShellDispatch.Release],[pIShDisp]
- ; Удалить объект
- invoke CoUninitialize
Теперь для полного комплекта давайте программно реализуем операцию "Показать рабочий стол", которая вызывается комбинацией клавиш Win+D. Ее ошибочно приравнивают к команде "Свернуть все окна", но фактически это не так, хотя она выполняет похожее действие. За показ рабочего стола отвечает метод ToggleDesktop из интерфейса IShellDispatch4, который является расширением для IShellDispatch3, который является расширением для IShellDispatch2, который, как вы уже догадались, является расширением для уже знакомого нам объекта IShellDispatch. Объект IShellDispatch4 имеет другой GUID, его надо прописать вместо указанного выше.
Code (Assembler) : Убрать нумерацию
- ; GUID {EFD84B2D-4BCF-4298-BE25-EB542A59FBDA}
- IID_IShellDispatch4 dd 0EFD84B2Dh
- dw 04BCFh
- dw 04298h
- db 0BEh, 025h, 0EBh, 054h, 02Ah, 059h, 0FBh, 0DAh
Code (Assembler) : Убрать нумерацию
- ; IID_IShellDispatch Interface
- struct IShellDispatch
- QueryInterface dd ?
- AddRef dd ?
- Release dd ?
- GetTypeInfoCount dd ?
- GetTypeInfo dd ?
- GetIDsOfNames dd ?
- _Invoke dd ?
- ; IShellDispatch
- ; {D8F015C0-C278-11CE-A49E-444553540000}
- get_Application dd ?
- get_Parent dd ?
- NameSpace dd ?
- BrowseForFolder dd ?
- Windows dd ?
- Open dd ?
- Explore dd ?
- MinimizeAll dd ?
- UndoMinimizeALL dd ?
- FileRun dd ?
- CascadeWindows dd ?
- TileVertically dd ?
- TileHorizontally dd ?
- ShutdownWindows dd ?
- Suspend dd ?
- EjectPC dd ?
- SetTime dd ?
- TrayProperties dd ?
- Help dd ?
- FindFiles dd ?
- FindComputer dd ?
- RefreshMenu dd ?
- ControlPanelItem dd ?
- ; IShellDispatch2
- ; {A4C6892C-3BA9-11D2-9DEA-00C04FB16162}
- IsRestricted dd ?
- ShellExecute dd ?
- FindPrinter dd ?
- GetSystemInformation dd ?
- ServiceStart dd ?
- ServiceStop dd ?
- IsServiceRunning dd ?
- CanStartStopService dd ?
- ShowBrowserBar dd ?
- ; IShellDispatch3
- ; {177160CA-BB5A-411C-841D-BD38FACDEAA0}
- AddToRecent dd ?
- ; IShellDispatch4
- ; {EFD84B2D-4BCF-4298-BE25-EB542A59FBDA}
- WindowsSecurity dd ?
- ToggleDesktop dd ?
- ExplorerPolicy dd ?
- GetSetting dd ?
- ; IShellDispatch5
- ; {866738B9-6CF2-4DE8-8767-F794EBE74F4E}
- WindowSwitcher dd ?
- ; IShellDispatch6
- ; {286E6F1B-7113-4355-9562-96B7E9D64C54}
- SearchCommand dd ?
- ends
Code (Assembler) : Убрать нумерацию
- ; Инициализировать COM-объект
- invoke CoInitialize,NULL
- ; Создать объект
- invoke CoCreateInstance,CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,\
- IID_IShellDispatch4,pIShDisp
- ; Вызвать метод интерфейса ToggleDesktop
- mov eax, [pIShDisp]
- mov eax, [eax]
- stdcall dword [eax+IShellDispatch.ToggleDesktop],[pIShDisp]
- mov eax, [pIShDisp]
- mov eax, [eax]
- stdcall dword [eax+IShellDispatch.Release],[pIShDisp]
- ; Удалить объект
- invoke CoUninitialize
В приложении примеры программ с исходными текстами, которые демонстрируют все описанные в статье действия по сворачиванию и разворачиванию окон.
Просмотров: 1834 | Комментариев: 5
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
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;
procedure MinimizeAll;
var
Wnd: HWND;
begin
Wnd := FindWindow('Shell_TrayWnd', nil);
if Wnd <> 0 then
SendMessage(Wnd, WM_COMMAND, $019F, 0);
end;
Добавить комментарий
Заполните форму для добавления комментария
Что же касается просьбы не добавлять исполняемые файлы в примеры, то это сделано не просто так. Лично мне, например, гораздо удобнее, если в каком-нибудь решении, которое я ищу, сразу будет исполняемый файл. Можно посмотреть и убедиться, что он решает задачу именно так, как мне надо. Дальше. Языков программирования сотни, знать их все со всеми диалектами нереально. И очень часто нужные мне решения встречаются реализованными на языках, на которых я совсем не пишу и синтаксис которых вызывает у меня затруднения и необходимость тратить дополнительное время на поиски. Это могут быть какие-то структуры, интерфейсы, объекты, специфические языковые конструкции и тому подобное. Что ж мне, держать на компе 100500 сред разработки на все случаи жизни, да еще и разбираться в каждой? Мне проще будет дизассемблировать готовый файл и посмотреть, как тот или иной кусок исходника компилятор собрал в машинный код и затем перевести его в ассемблерный вариант. Так что нет, у меня всегда будет исходник и готовый файл. А антивирус лучше все-таки поменять на нормальный.