Как создать расширение оболочки Context menu
Обработчик Context menu позволяет добавить новые пункты в меню, появляющееся при нажатии правой кнопки мыши на файле или директории. Возможно создание не только отдельных новых пунктов, но и целых вложенных меню с множеством пунктов.
В библиотеке Shell Ace обработчик Context menu реализует следующие интерфейсы:
- IContextMenu
- IContextMenu2
- IContextMenu3
- IShellExtInit
Для создания проекта расширения необходимо добавить в проект модуль с обработчиком Context menu. Для этого выберите соответствующую иконку на вкладке Shell extension:
Появится окно с предложением ввести имя класса и выбрать дополнительные перекрываемые методы:
После нажатия на кнопку OK в проект будет добавлен модуль с каркасом обработчика. При включении опции Create sample помимо каркаса обработчика будут создан пример готового расширения оболочки, который можно использовать для изучения библиотеки.
В обработчике можно перекрывать следующие виртуальные процедуры и функции:
procedure Initialize;
Процедура инициализации обработчика, вызывается один раз при создании экземпляра обработчика.
Если создаваемое расширение не содержит пункта меню по умолчанию, то можно оптимизировать работу Windows, установив в этом методе значение свойства MayChangeDefaultMenu в значение False.
procedure Clear;
Процедура вызывается при завершении работы с текущим списком файлов, переданных в обработчик. Может вызываться дважды, см. ниже.
class function GetClassID: TCLSID;
Функция должна возвращать уникальный идентификатор обработчика. Библиотека Shell Ace изначально генерирует уникальный идентификатор при генерации шаблона обработчика, поэтому менять его нет необходимости.
class function GetDescription: UnicodeString;
Функция должна возвращать описание обработчика.
procedure FillProgIDList(AList: TStrings);
В процедуре должно происходить заполнение списка AList ключами реестра, в которые будет прописан обработчик при регистрации расширения. Регистрация происходит в раздел реестра HKEY_CLASSES_ROOT. Например, если будет добавлен ключ .bmp и будет соответствовать всем файлам, имеющим расширение bmp, то расширение будет прописано в ветку HKEY_CLASSES_ROOT\.bmp\ShellEx\ContextMenuHandlers, а если будет добавлен ключ SystemFileAssociations\Audio, то расширение будет прописано в ветку HKEY_CLASSES_ROOT\SystemFileAssociations\Audio\ShellEx\ContextMenuHandlers и будет соответствовать всем файлам, расширения которых имеют PerceivedType Audio.
Примеры ключей реестра:
Ключ реестра | Примечание |
---|---|
ProgID | |
.Расширение | |
SystemFileAssociations\.Расширение | |
SystemFileAssociations\PerceivedType | |
Kind.Kind | |
Unknown | Файл, не имеющий описанного в реестве расширения |
* | Любой файл |
Directory | Физическая директория |
Folder | Виртуальная директория |
В общем случае рекомендуется регистрировать расширение на ProgID расширения файла.
procedure CreateMenu(AMenu: TdecMenu; AFlags: TdecContextMenuFlags);
Процедура должна создать дерево пунктов меню, включая вложенные в подменю. Процедура вызывается в реализации метода QueryContextMenu интерфейса IContextMenu.
Для формирования меню можно дополнительно анализировать флаги AFlags. Тип TdecContextMenuFlags определен следующим образом:
TdecContextMenuFlag = (cmfDefaultOnly, cmfVerbsOnly, cmfExplorer, cmfNoVerbs, cmfNoDefault, cmfItemMenu, cmfExtendedVerbs, cmfDisabledVerbs, cmfAsyncVerbState, cmfOptinizaForInvoke, cmfSyncCascadeMenu, cmfDoNotPickDefault);
TdecContextMenuFlags = set of TdecContextMenuFlag;
Каждый из элементов множества соответствует соответствующему флагу, переданному в метод QueryContextMenu:
Значение | WinAPI флаг | Описание |
---|---|---|
cmfDefaultOnly | CMF_DEFAULTONLY | Оболочка просит добавить только пункт меню по умолчанию. Библиотека Shell Ace самостоятельно обрабатывает этот флаг - независимо от того, сколько пунктов было добавлено, библиотека оставит только один пункт, имеющий значение свойства Default равное True. |
cmfVerbsOnly | CMF_VERBSONLY | The shortcut menu is that of a shortcut file |
cmfExplore | CMF_EXPLORE | The Windows Explorer tree window is present. |
cmfNoVerbs | CMF_NOVERBS | This flag is set for items displayed in the Send To menu. Shortcut menu handlers should ignore this value. |
cmfNoDefault | CMF_NODEFAULT | No item in the menu has been set as the default. A drag-and-drop handler should ignore this flag. A namespace extension should not set any of the menu items as the default. |
cmfItemMenu | CMF_ITEMMENU | The calling application is invoking a shortcut menu on an item in the view (as opposed to the background of the view). Windows Server 2003 and Windows XP: This value is not available. |
cmfExtendedVerbs | CMF_EXTENDEDVERBS | The calling application wants extended verbs. Normal verbs are displayed when the user right-clicks an object. To display extended verbs, the user must right-click while pressing the Shift key. |
cmfDisabledVerbs | CMF_DISABLEDVERBS | The calling application intends to invoke verbs that are disabled, such as legacy menus. Windows Server 2003 and Windows XP: This value is not available. |
cmfAsyncVerbState | CMF_ASYNCVERBSTATE | The verb state can be evaluated asynchronously. Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not available. |
cmfOptinizaForInvoke | CMF_OPTIMIZEFORINVOKE | Оболочка просит добавить в меню только те пункты, для которых установлено свойство Verb. Библиотека Shell Ace самостоятельно обрабатывает этот флаг - все пункты меню, у которых свойство Verb имеет пустое значение, будут автоматически удалены. |
cmfSyncCascadeMenu | CMF_SYNCCASCADEMENU | Populate submenus synchronously. Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not available. |
cmfDoNotPickDefault | CMF_DONOTPICKDEFAULT | When no verb is explicitly specified, do not use a default verb in its place. Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not available. |
Добавление пункта происходит путем вызова метода Add объекта AMenu, который возвращает объект класса TdecMenuItem:
var MenuItem: TdecMenuItem;
MenuItem := AMenu.Add(CommandID, 'Caption');
где CommandID является уникальным в рамках данного обработчика идентификатором команды, а Caption является текстом, который будет выводиться в пункте меню. После добавления пункта он должен быть инициализирован путем присвоения свойствам нужных значений. Доступны следующие свойства:
Наименование | Описание | |||
---|---|---|---|---|
Caption: UnicodeString | Определяет текст, который будет выводиться в пункте меню. | |||
Help: UnicodeString | Определяет описание команды, которое будет выводится в строке статуса. Также данная строка используется в качестве всплывающей подсказки при добавлении данной команды в панель инструментов программы Проводник. | |||
Verb: UnicodeString | Определяет сокращенное название действия, например, print или open. Используется при поиске команды при открытии файла программно. | |||
Icon: HICON | Определяет иконку, которая будет отображаться в данном пункте меню. | |||
IconFileName: UnicodeString | В случае, если свойство Icon не определено (равно нулю), то определяет имя файла и индекс ресурса, в котором содержится иконка, которая будет отображаться в данном пункте меню. Для определения иконки рекомендуется использовать данное свойство, а не свойство Icon, поскольку это позволит программе Проводник отображать иконку команды при добавлении ее в панель инструментов. | |||
AutoIconSize: Boolean |
Определяет, что размеры иконки элемента меню будут автоматически увеличиваться или уменьшаться до размеров, определенных системой. По умолчанию значение свойства установлено в True, менять его не рекомендуется. Свойство проявляет себя в нестандартных визуальных темах оформления, в которых размер шрифта в меню больше или меньше стандартного, или при увеличенном DPI экрана. Так выглядит меню с добавленными пунктами Register и Unregister при стандартном DPI, равном 96: Так выглядит меню при увеличенном DPI, равном 150, с AutoIconSize равном False: А так выглядит меню при увеличенном DPI, равном 150, с AutoIconSize равном True: |
|||
Default: Boolean | Определяет, что данный пункт меню является пунктом меню по умолчанию, при прорисовке выделяется утолщенным шрифтом. Только один пункт меню может являться пунктом меню по умолчанию. Если иное расширение оболочки раньше создало пункт меню по умолчанию, то данное свойство будет проигнорировано. | |||
Enabled: Boolean | Определяет, что данный пункт меню разрешен для вызова. По умолчанию имеет значение True. | |||
Visible: Boolean | Определяет, что данный пункт меню является видимым. По умолчанию имеет значение True. | |||
Checked: Boolean | Определяет, что пункт меню будет отмечен галочкой. | |||
RadioCheck: Boolean | Определяет, что в случае, если свойство Checked равно True, то вместо галочки будет использоваться точка. | |||
OwnerDraw: Boolean |
Определяет, что пункт меню имеет программную прорисовку, при этом должны быть реализованы методы GetItemSize и DrawItem. При использовании программной прорисовки Windows Vista и более современные системы будут игнорировать текущую визуальную тему и будут прорисовывать меню в классическом стиле. Так выглядит контекстное меню, прорисованное с использованием визуальной темы: А так выглядит контекстное меню с добавленным пунктом, имеющим программную прорисовку: |
Добавление пунктов по вложенные меню происходит при вызове метода Add свойства SubMenu:
MenuItem2 := MenuItem.SubMenu.Add(CommandID2);
Построение меню может происходить в зависимости от количества или типа файлов, переданных в обработчик. Список переданных файлов можно получить вызовом метода CreateCurrentFileList. Функция возвращает объект класса TStrings, содержащий список файлов. В версиях Delphi вплоть до версии 2009, в которых тип string равен типу AnsiString, имена файлов в списке хранятся в формате UTF8. Объект должен быть уничтожен после его обработки. Также доступны функции GetCurrentFileListCount, которая возвращает количество файлов, и GetFirstOfCurrentFileList, которая возвращает первый элемент списка (с нулевым индексом).
function CreateItemIcon(AMenuItem: TdecMenuItem; const AIconSize: TSize): HICON;
Функция должна вернуть идентификатор (handle) иконки, которая будет ассоциирована с пунктом меню, в случае отсутствия иконки Функция должна вернуть 0. Значение свойства AMenuItem.ID определяет, для какого пункта меню нужно создать иконку.
Параметр AIconSize определяет рекомендуемые размеры иконки.
Для пунктов меню, имеющих свойство AutoIconSize равное True можно создать иконку любого размера, ее размер при прорисовке будет изменет автоматически до рекомендованного Windows.
Необходимости удалять иконку из памяти нет, поскольку по окончанию работы с иконкой библиотека Shell Ace сама удалит все ресурсы, связанные с иконкой.
В ОС Windows XP и более ранних версиях Windows иконка не может быть ассоциирована с пунктами меню, имеющими вложенные меню. В Windows Vista и более современных системах эта проблема отсутствует.
Если у вас в среде разработки установлен пакет Graphics32, то при использовании иконок в контекстном меню рекомендуется добавлять в проект модуль decShellExtensionGraphics32. Это позволит обработчику использовать более плавные процедуры сглаживания иконок при увеличении или уменьшении их размеров. Это проявляется при прорисовках пунктов меню с иконками и свойством AutoIconSize равным True в режимах работы с увеличенным DPI экрана.
Так выглядит меню с добавленными пунктами Register и Unregister при увеличенном DPI, равном 150, с AutoIconSize равном True без использования модуля decShellExtensionGraphics32:
А так выглядит меню при увеличенном DPI, равном 150, с AutoIconSize равном True с использованием модуля decShellExtensionGraphics32:
Если библиотека Shell Ace обнаружит установленный пакет Graphics32, то модуль decShellExtensionGraphics32 будет автоматически добавлен в список используемых модулей при создании каркаса обработчика.
function GetItemSize(AMenuItem: TdecMenuItem): TSize;
Метод вызывается для определения размеров пунктов меню, имеющих режим DrawMode равный dmCustom. Значение свойства AMenuItem.ID определяет, размеры какого именно пункта меню нужно определить.
procedure DrawItem(AMenuItem: TdecMenuItem; ADC: HDC; const ARect: TRect; ADrawState: TOwnerDrawState);
Метод вызывается для прорисовки пунктов меню, имеющих режим DrawMode равный dmCustom. Свойство AMenuItem.ID определяет, какой именно пункта меню нужно прорисовать. Библиотека Shell Ace самостоятельно отрисовывает фон пункта меню в соответствии с цветовой схемой, используемой в системе.
Параметр ADC определяет контекст, в котором нужно рисовать. Параметр ARect определяет положение и размеры области, отведенной для пункта меню. Размеры области могут быть больше или меньше, чем полученные в функции GetItemSize. Параметр ADrawState определяет стиль, в котором нужно прорисовать пункт меню.
function ExecuteCommand(AMenuItem: TdecMenuItem; AInfo: PShellExecuteInfoW; ATitle: UnicodeString; AShiftState: TShiftState; APoint: PPoint): Boolean;
Функция вызывается при выборе пользователем пункта меню, свойство AMenuItem.ID определяет, какой именно пункта меню был выбран. В этой функции необходимо реализовать непосредственное выполнение команды. В параметре AInfo передаются ссылка на запись, которая может использоваться при вызове системной функции ShellExecuteExW. Нижеперечисленные поля записи могут быть инициализированы, остальные поля содержат значение 0:
Наименование | Описание |
---|---|
cbSize: DWORD | SizeOf(ЕShellExecuteInfoW) |
fMask: ULONG | Комбинация флагов SEE_MASK_ICON, SEE_MASK_HOTKEY, SEE_MASK_NOCLOSEPROCESS, SEE_MASK_CONNECTNETDRV, SEE_MASK_NOASYNC, SEE_MASK_FLAG_NO_UI, SEE_MASK_NO_CONSOLE, SEE_MASK_HASLINKNAME, SEE_MASK_HASTITLE, SEE_MASK_ASYNCOK, SEE_MASK_HMONITOR, SEE_MASK_NOZONECHECKS, SEE_MASK_WAITFORINPUTIDLE и SEE_MASK_FLAG_LOG_USAGE. При использовании этого параметра рекомендуется отфильтровывать флаги, которые нужны для обработки команды. |
Wnd: HWND | Идентификатор (хендл) окна, которое следует использовать как родительское при UI операциях. |
lpParameters: LPCWSTR | Параметры |
lpDirectory: LPCWSTR | Рабочая директория |
nShow: Integer | SW_SHOW или альтернативный флаг |
hkeyClass: HKEY | |
dwHotKey: DWORD | Код горячей клавиши, которая будет ассоциирована с запускаемым приложением. Значение валидно, только если fMask содержит флаг CMIC_MASK_HOTKEY. |
hIcon: THandle | Идентификатор (handle) иконки, которая может использоваться вызываемым приложением в качестве иконки приложения. Значение валидно, только если fMask содержит флаг CMIC_MASK_ICON. |
ATitle определяет строку, которая может использоваться запускаемым приложением в качестве заголовок главного окна, начиная с Windows Vista не используется. AShiftState определяет состояние клавиш Alt, Ctrl и Shift. Указатель APoint указывает на абсолютные координаты мыши в момент вызова команды пользователем, может быть равен nil.
Список файлов для обработки НУЖНО получать методом CreateCurrentFileList, поскольку он может отличаться в большую сторону от того списка, который был получен в методе CreateMenu. Это происходит потому, что при вызове пользователем меню для большого количества файлов Windows для создания меню передает лишь часть списка, а уже при вызове команды передает весь список. Поэтому НЕ кэшируйте список, а всегда вызывайте функцию CreateCurrentFileList повторно!
Обязательными для реализации в обработчике Context menu являются следующие методы:
- GetClassID
- FillProgIDList
- CreateMenu
- ExecuteCommand
Смотрите также:
- Что такое расширение оболочки
- Какие бывают расширения оболочки
- Как создать расширение оболочки
- Инициализация расширений оболочки
- Как создать расширение оболочки Context menu
- Как создать расширение оболочки Drag and drop context menu
- Как создать расширение оболочки Drop target
- Как создать расширение оболочки Icon
- Как создать расширение оболочки Info tip
- Как создать расширение оболочки Overlay icon
- Как создать расширение оболочки Preview
- Как создать расширение оболочки Property sheet
- Как создать расширение оболочки Property store
- Как создать расширение оболочки Thumbnail
- Как зарегистрировать расширение оболочки
- Как отлаживать расширение оболочки
- Использование логов