Blog. Just Blog

Управление отображением программы на панели задач

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

Наиболее простой в реализации способ, который чаще всего рекомендуют использовать, основан на изменении родительского окна. Если у главного окна приложения нет родительского окна, то оно отображается на панели задач. Если в качестве родительского окна указан рабочий стол, то программа убирается из панели задач. На этапе инициализации окна ему присваивается нулевое значение в качестве хэндла родительского окна.
  1. .wminitdialog:
  2.         ; Если окно уже имеет родителя, то сбросить значение
  3.         invoke  GetWindowLong,[hwnddlg],GWL_HWNDPARENT
  4.         or      eax,eax
  5.         jz      @f
  6.         invoke  SetWindowLong,[hwnddlg],GWL_HWNDPARENT,0
  7. @@:
Затем при наступлении нужных событий программа или отображается на панели задач, или скрывается.
  1. .taskbar_show:
  2.         ; Добавить программу на панели задач
  3.         invoke  SetWindowLong,[hwnddlg],GWL_HWNDPARENT,0
  4.         ...
  5. .taskbar_hide:
  6.         ; Убрать программу с панели задач
  7.         invoke  GetDesktopWindow
  8.         invoke  SetWindowLong,[hwnddlg],GWL_HWNDPARENT,eax
  9.         ...
Если нужно с самого начала просто убрать программу из панели задач, то при инициализации окна вместо обнуления родительского хэндла на эту роль сразу назначается рабочий стол.

Важно! Хотя этот способ с технической точки зрения вполне легален, использовать его крайне не рекомендуется. Дело в том, что при назначении окон разных процессов другому процессу, системе очень сложно обрабатывать все внутренние сообщения, связи между потоками и подобные вещи. Некоторые межпроцессовые сообщения могут быть вовсе заблокированы, а попытки манипуляции с окном могут привести к аварийному завершению. Это как раз тот случай, когда кажется, будто что-то работает как вам хочется, но при этом не факт, что оно работает правильно.

Немного более корректный способ - создание невидимого message-only окна. Оно будет использоваться вместо рабочего стола.
  1. szClass    db '#32770',0
  2. HWND_MESSAGE = -3
  3.         ...
  4.         ...
  5.         ; Создать невидимое message-only окно
  6.         invoke  CreateWindowEx,0,szClass,0,0,0,0,0,0,HWND_MESSAGE,0,0,0
  7.         mov     [hWndParent],eax
Дальше все то же самое. Если программу надо убрать с панели задач, то в качестве родительского окна устанавливается хэндл созданного ранее невидимого окна, если надо показать на панели управления, то родительский хэндл обнуляется.
  1. .taskbar_show:
  2.         ; Добавить программу на панели задач
  3.         invoke  SetWindowLong,[hwnddlg],GWL_HWNDPARENT,0
  4.         ...
  5. .taskbar_hide:
  6.         ; Убрать программу с панели задач
  7.         invoke  SetWindowLong,[hwnddlg],GWL_HWNDPARENT,[hWndParent]
  8.         ...
Лучше всего применять более сложный, но более правильный способ. Он заключается в использовании COM-объектов. Немного идентификаторов, интерфейсов и констант, которые будут использоваться в коде.
  1. ; GUID {56FDF344-FD6D-11D0-958A-006097C9A090}
  2. CLSID_TaskbarList dd 056FDF344h
  3.                   dw 0FD6Dh
  4.                   dw 011D0h
  5.                   db 095h, 08Ah, 000h, 060h, 097h, 0C9h, 0A0h, 090h
  6.  
  7. ; GUID {56FDF342-FD6D-11D0-958A-006097C9A090}
  8. IID_ITaskbarList dd 056FDF342h
  9.                  dw 0FD6Dh
  10.                  dw 011D0h
  11.                  db 095h, 08Ah, 000h, 060h, 097h, 0C9h, 0A0h, 090h
  12.  
  13. ; IID_ITaskbarList Interface
  14. struct ITaskBarList
  15.     QueryInterface      dd ?
  16.     AddRef              dd ?
  17.     Release             dd ?
  18.  
  19.     HrInit              dd ?
  20.     AddTab              dd ?
  21.     DeleteTab           dd ?
  22.     ActivateTab         dd ?
  23.     SetActiveAlt        dd ?
  24. ends
  25.  
  26. CLSCTX_INPROC_SERVER    = 1
  27. S_OK                    = 0
С помощью методов интерфейса ITaskBarList можно удалять или добавлять на панель задач любое окно, достаточно только знать его хэндл. На этапе создания окна инициализируется объект панели задач:
  1. .wminitdialog:
  2.         ; Инициализировать COM-объект
  3.         invoke  CoInitialize,NULL
  4.         ; Создать объект
  5.         invoke  CoCreateInstance,CLSID_TaskbarList,NULL,\
  6.                 CLSCTX_INPROC_SERVER,\
  7.                 IID_ITaskbarList,pITbDisp
  8.  
  9.         ; Инициализировать объект панели задач
  10.         mov     eax, [pITbDisp]
  11.         mov     eax, [eax]
  12.         stdcall dword [eax+ITaskBarList.HrInit],[pITbDisp]
Переключение отображения выполняется также по мере надобности или сразу на этапе создания окна, в зависимости от поставленной задачи.
  1. .taskbar_show:
  2.         ; Добавить программу на панели задач
  3.         mov     eax, [pITbDisp]
  4.         mov     eax, [eax]
  5.         stdcall dword [eax+ITaskBarList.AddTab],[pITbDisp],[hwnddlg]
  6.  
  7.         ; Активировать добавленный элемент панели задач
  8.         mov     eax, [pITbDisp]
  9.         mov     eax, [eax]
  10.         stdcall dword [eax+ITaskBarList.ActivateTab],[pITbDisp],[hwnddlg]
  11.         ...
  12. .taskbar_hide:
  13.         ; Убрать программу с панели задач
  14.         mov     eax, [pITbDisp]
  15.         mov     eax, [eax]
  16.         stdcall dword [eax+ITaskBarList.DeleteTab],[pITbDisp],[hwnddlg]
  17.         ...
Большой плюс этого способа в том, что с его помощью можно скрывать или отображать любые окна любых приложений, даже с самыми невероятными комбинациями стилей, которые в принципе не отображаются на панели задач. Родительское окно также не затрагивается, что тоже хорошо в том случае, если надо отобразить на панели задач какое-нибудь окно, не являющееся главным окном приложения.

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

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

Hide.Show.on.TaskBar.Demo.zip (9,588 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (11.09.2020 в 14:20):
Добавил в статью, спасибо. Архив тоже обновлен.
Scolgena (11.09.2020 в 13:20):
можно добавить, что если совсем не нужно отображать на панели задач, можно самому создать себе парента, типа HWND hWndParent = CreateWindowExW(0, L"#32770", 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0)
dd1 (08.09.2020 в 20:55):
ЦитатаЭту последовательность можно записать хоть отдельными байтами, хоть двордами, хоть еще как, лишь бы получился правильный набор данных. Но, как говорится, так уж тут заведено.

Тоже подумал об этом, поэтому и стало любопытно.

Спасибо за ответ.
ManHunter (08.09.2020 в 20:05):
dd1, таким образом в Ассемблере описываются GUID'ы, конкретно в этом случае это GUID {56FDF344-FD6D-11D0-958A-006097C9A090}. Что ж касается формы записи, то честно признаюсь, я не знаю, почему в Ассемблере исторически сложилась именно такая структура. Эту последовательность можно записать хоть отдельными байтами, хоть двордами, хоть еще как, лишь бы получился правильный набор данных. Но, как говорится, так уж тут заведено.

Кто-то выкручивается макросами, чтобы преобразовать GUID из строки в байты. Меня настолько вымораживает каждый раз переводить строку в эту нелогичную конструкцию, что я даже нарисовал себе мелкую софтинку для этой операции. https://www.upload.ee/files/12...uid.zip.html
dd1 (08.09.2020 в 19:13):
ManHunter, если не трудно, просвятите пожалуйста.

У вас в FASM-коде есть такое место:

section '.data' data readable writeable

IID_ITaskbarList dd 056FDF342h
                 dw 0FD6Dh
                 dw 011D0h
                 db 095h, 08Ah, 000h, 060h, 097h, 0C9h, 0A0h, 090h
     
Оно вроде, и понятно что это, но в то же время не совсем. Получается что-то среднее между массивом переменного размера и структурой, но у массива все ячейки одного размера и понятно как можно перейти от ячейки к ячейке и скопировать данные. У структуры есть назв. структуры и название ее полей - тоже как бы все понятно. А в такой конструкции как можно оперативно перемещаться и копировать данные разной длины (dd dw db)? И, вообще, это же было придумано для какого-то удобства? Заранее спасибо. 

P.S. Кстати, ИДА определяет это как структуру и присваевает даже свои названия полям с разной длиной.
ManHunter (08.09.2020 в 12:21):
0101, не совсем литературный раздел, но все касаемо Ассемблера я складывал сюда: http://www.manhunter.ru/assemb...er_fasm.html
0101 (08.09.2020 в 05:20):
вообще, имхо, книжка "The Old New Thing" весьма интересна, несмотря на возраст и английский язык (в переводе есть только отдельные главы). Может (сам давно собираюсь) сделать на сайте раздел "must have" литературы? Там будет пару десятков книжек на пару сотен Мб.
ManHunter (07.09.2020 в 12:54):
Правильное замечание. Добавил в статью предупреждение. Спасибо!
DRON (07.09.2020 в 12:33):
Объяснение, почему первый способ лучше не использовать:
https://devblogs.microsoft.com...2-00/?p=4683

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

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

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