Прототип к варианту 22 - Редактор системного меню
SysMenu — системные и контекстные меню
Программа SysMenu показывает, как изменить содержимое системного меню в приложении Visual Basic и как реализовать полноценную поддержку контекстных меню (по сравнению с частичной поддержкой, обеспечиваемой Visual Basic).
Впрочем, возникает одно затруднение: в обоих случаях необходимо воспользоваться субклассированием. Субклассирование не поддерживалось в Visual Basic 4.0 и потому требовало применения специальных элементов, разработанных независимыми формами. В Visual Basic 5.0 появилась возможность субклассирования окон функцией SetWindowLong. Однако, несмотря на все указания, приведенные в документации VB5, вам никогда не следует субклассировать окна, применяя эту методику в приложениях VB. Она будет работать, но вы столкнетесь с серьезными проблемами при отладке приложения, поскольку при временной остановке программы или выполнении команды Stop также перестанет работать программный код, в котором находится функция окна. Таким образом, эта методика может помешать нормальной работе системы. Субклассирование в приложениях всегда следует осуществлять с применением внутрипроцессных (in-process) компонентов DLL (которые можно написать на VB5). К книге прилагается полностью работоспособная демонстрационная версия субклассирующего элемента OLE DWSBC32D.OCX — один из двух элементов из пакета Desaware SpyWorks (другой написан на VB и содержит полный исходный текст программы). Элемент позволит вам запускать программы-примеры и научит пользоваться теми возможностями, которые предоставляет Субклассирование; но если вы захотите использовать субклассирование в своих приложениях, вам придется приобрести субклассирующий элемент с лицензией на распространение или написать его самостоятельно.
Использование SysMenu
Рабочее окно SysMenu показано на рис. 10.5. Как видите, в системном меню появилась новая команда. В текстовом поле (которое на рисунке частично скрыто раскрытым меню) можно ввести любой текст и нажать кнопку Add To System Menu. Новая команда вставляется в системное меню.
Контекстные меню рассматривались раньше в тексте главы. Если щелкнуть на форме правой кнопкой мыши, элементу, на котором был сделан щелчок, посылается сообщение WM_CONTEXTMENU. Элемент может обработать сообщение самостоятельно или разрешить его отправку форме-контейнеру. Большинство элементов не занимается самостоятельной обработкой сообщений, однако в Windows 95 и NT 4.0 текстовые элементы имеют собственные контекстные меню. Элемент DWSBC32D.OCX использует Субклассирование для перехвата сообщений WM_CONTEXTMENU формы и текстового поля, что позволяет создавать контекстные меню для элементов, не имеющих собственных меню, и переопределять контекстные меню для текстовых полей.
Описание проекта
Проект SysMenu состоит из трех файлов. В программе используется всего одна форма, SYSMENU. FRM. Файл MENULOOK.BAS содержит объявления констант, переменных и функций. APIGID32.BAS содержит объявления функций библиотеки динамической компоновки APIGID32.DLL, прилагаемой к книге. В листинге 10.4 приведен листинг файла SYSMENU.FRM. Содержимое MENULOOK.BAS было приведено в предыдущем разделе при описании проекта MenuLook.vbp.
Листинг 10.4. SYSMENU.FRM
Свойство Messages элемента SubClassl содержит список сообщений, перехватываемых элементом. В нашем примере это сообщения WM_SYSCOMMAND, WM_COMMAND и WM_CONTEXTMENU. Begin DwsbcLib.SubClass SubClassl
Переменная NewContextMenu содержит манипулятор нестандартного всплывающего меню. В нем содержатся команды с идентификаторами, начинающимися с &Н2000. Число выбрано произвольно — если идентификаторы меню превышают WMJJSER (&H400), они не помешают нормальной работе элемента.
Во время загрузки формы создается новое всплывающее меню, состоящее из трех команд. Чтобы подготовить элемент к субклассированию формы, параметру CtlParam присваивается frm-SysMenu (имя формы). При помощи свойства AddHwnd задаются дополнительные субклассируемые окна.
Наше конкретное приложение устроено так, что все субклассирование выполняется одним элементом DWSBC32D.OCX. Это означает, что процедура события WndMessage будет получать сообщения от всех субклассированных окон. При помощи свойства hwnd можно определить, какому элементу предназначено сообщение.
Сообщение WM_SYSCOMMAND посылается командами системного меню. Если номер сообщения (параметр wp) не совпадает с одним из добавленных нами, процедура завершает свою работу и сообщение обрабатывается стандартным образом. Если сообщение поступило от добавленной нами команды, выводится окно сообщения с информацией о его получении. Затем свойству nodef присваивается значение, говорящее Windows о том, что сообщение не должно обрабатываться дальше.
Сообщение WM_CONTEXTMENU посылается при запросе контекстного меню. При получении этого сообщения мы вызываем всплывающее меню функцией TrackPopupMenu. Сообщения от этого всплывающего меню направляются графическому полю. Это необходимо, поскольку эти сообщения могут помешать работе элементов в Visual Basic (и станут причиной фатальных исключений). Но даже при этом необходимо перехватывать и блокировать сообщения WM_CQMMAND, передаваемые графическому полю. Другие сообщения (например, WM_MENUSELECT) передаются элементу, пока всплывающее меню находится на экране. У некоторых элементов это может вызвать проблемы; чтобы этого не произошло, мы используем графическое поле.
Событие инициируется для каждого сообщения WM_SYSCOMMAND
Рекомендации для самостоятельной работы
В этом приложении продемонстрирован один из простейших вариантов применения субклассирования. Попробуйте поставить еще пару опытов.
Что произойдет, если задать свойству nodef значение TRUE, предотвращающее обработку по умолчанию для стандартных сообщений системного меню? Можно ли предотвратить закрытие окна? Можно ли изменить смысл этих стандартных сообщений?
В главе 6 было показано, как получить манипулятор любого окна в системе. Можно ли добавить команду в системное меню другого приложения и заставить его инициировать события в вашем приложении? (подсказка: да, элемент DWSBC32D.OCX позволяет это сделать, хотя субклассирование должно быть реализовано не на VB5).
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.