15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Расширения оболочки Windows - Всплывающие подсказки

Автор: Larry J. Rutledge

С каждой новой версией Windows, её оболочка (shell) приобретает всё больше и больше различных возможностей. Обычно эти возможности добавляются через расширения оболочки, которые позволяют разработчикам добавлять различные возможности в существующую оболочку Windows. Вот некоторые примеры расширений оболочки: Context Menus (меню, зависящее от объекта, на котором кликнули правой кнопкой мыши), Property Sheet Handlers (страницы в виде закладок, которые появляются в случае выбора пункта контексного меню Properties), Folder Customization, и т.д.

На сайте Microsoft доступно большое количество информации о расширениях оболочки, но эта информация мало полезна Delphi аудитории. Итак давайте рассмотрим расширение оболочки под названием "Всплывающие подсказки" (InfoTip), которые появляются в эксплорере, при наведении мышкой на файл.

 

   Расширения оболочки – Краткий обзор
Расширения оболочки существуют в виде In Process COM серверов. В ответ на определённые события оболочки проводник вызывает соответствующее расширение. Проводник очень специфически реагирует на различные функции в пределах оболочки. Первое, что делает Проводник - это проверяет модули, которые были зарегистрированы для определённого события и, если таковой существует, то загружает данный модуль.

Чтобы быть расширением оболочки, COM сервер должен включать в себя интерфейс, который определяет специфическое поведение для данного расширения, а так же он должен включать в себя интефейс инициализации. Наконец, чтобы быть расширением оболочки, COM сервер должен следовать определённым в системе методам регистрации.

Следующая таблица представляет собой список всех существующих на сегодняшний день расширений оболочки, а так же их минимальных версий, учавствующих интерфейсов и их описаний:

 

Тип Добавлено в Версия Используемые интерфейсы Описание
Context Menu File class and shell’s object Windows 95+ IContextMenu, IContextMenu2, или IContextMenu3 Позволяет добавлять новые пункты в контекстное меню объекта оболочки.
Right Drag and Drop File class and shell’s object Windows 95+ IContextMenu, IContextMenu2, или IContextMenu3 Позволяет добавлять новые пункты в контекстное меню, при перетаскивании правой кнопкой мыши и отпускании файлов.
Drawing Shell Icons File class and shell’s object Windows 95+ IExtractIcon Позволяет решить в данный момент, какая будет отображаться иконка для данного файла.
Property Sheet File class and shell’s object Windows 95+ IShellPropSheetExt Позволяет добавлять дополнительные страницы property sheet в диалог свойств файла. Так же это работает для Панели управления.
Left Drag and Drop File class and shell’s object Windows 95+ IDropTarget Позволяет решать - что делать с перетаскиваемым объектом (используя левую кнопку мыши) на другой объект в оболочке.
Clipboard File class and shell’s object Windows 95+ IDataObject Позволяет Вам определить, как объект скопирован и извлечён из буфера обмена.
File Hook   Windows 95+ ICopyHook Позволяет контролировать некоторые файловые операции, которые происходят черех оболочку. Вы можете разрешить или запретить их, но Вы не сможете получать уведомление об успешности операции или об ошибке.
Program Execution Explorer Desktop Update IShellExecuteHook Позволяет перехватывать некоторые выполнения программ, которые происходят через оболочку.
Infotip File class and shell’s object Desktop Update IQueryInfo Позволяет отображать короткие текстовые сообщения, когда курсор мышки находится на определённом файле.
Column Folders Windows 2000 IColumnProvider Позволяет добавлять новую колонку в режиме отображения Details в Проводнике.
Icon Overlay Explorer Windows 2000 IShellIconOverlay Позволяет определить собственные изображения, которые будут использоваться как иконки.
Search Explorer Windows 2000 IContextMenu Позволяет добавить новую ячейку в меню "Найти" (в меню, открывающемся при нажатии на "Пуск").
Cleanup Cleanup Manager Windows 2000 IEmptyVolumeCache2 Позволяет добавить новую ячейку в Менеджер Очистки для восстановления дискового пространства.

   Всплывающие подсказки – Введение и обзор
Infotip-ы это всплывающие окна подсказки, которые появляются в случае, если курсор мышки находится над любым файлом. Если расширения для файла не было зарегистрировано, то будет высвечиваться окошко с подсказкой по умолчанию, однако Вы можете создать своё собственно расширение для отображения информации об определённом типе файла. Например, Office 2000 инсталирует обработчики для MS Word и MS Excel, которые отображают Имя, Автора и заголовок из свойств документа. Расширения Infotip отличаются от других расширений оболочки по регистрации. Об этом мы поговорим позже, когда перейдём к регистрации нашего расширения Infotip.

Info tip in Explorer

   Implementing Infotip Extensions
Расширение Infotip является In-Process (Inproc) COM Server. Это значит, что Infotip является обыкновенной Windows DLL, которая экспортирует необходимые методы, чтобы быть как обыкновенным элементом управления ActiveX. Расширение Infotip так же включает IQueryInfo и IPersistFile и должна самостоятельно регистрировать себя в реестре. В виду того, что IQueryInfo и IPersistFile являются интерфейсами, то они не содержат исходного кода своих методов. Поэтому наш объект включает в себя каждый метод, определённый в обоих интерфейсах; однако, некоторые из методов не являются необходимыми для нашего расширения Infotip, поэтому мы просто возвращаем E_NOTIMPL, чтобы показать, что они не осуществимы.

IQueryInfo обеспечивает отображение текста во всплывающем окошке и содержит два метода: GetInfoFlags – Получает информационные флаги. На текущий момент это метод не используется, поэтому возвращаем E_NOTIMPL. GetInfoTip – Получает текст Infotip-а.

GetInfoTip определена следующим образом:

function GetInfoTip(dwFlags: DWORD; var ppwszTip: PWideChar): HResult; stdcall;

.dwFlags – в данный момент не используется
.ppwszTip – Адрес указателя на строку Unicode, кото string pointer that receives the tip string pointer.

Важное замечание
Параметр ppwszTip метода GetInfoTip - это указатель на строковый буфер Unicode, который содержит текст, отображаемый в всплывающем информационном поле. Этот буфер должен быть распределен, используя стандартную программу распределения памяти оболочки, потому что буфер распределен нашим приложением, но освобожден оболочкой. Чтобы быть уверенным, что всё пройдёт успешно, используйте SHGetMalloc для получения указателя на программу распределения памяти оболочки - объект IMalloc. Затем используйте метод Alloc из IMalloc-а для распределения необходимой памяти для буфера содержащего Unicode представление текста Infotip.
Исходник содержит стандартный код, который Вы можете использовать для всех расширений Infotip, которые Вы создадите.

IPersistFile это то, при помощи чего оболочка обеспечивает расширение информацией о файле, на котором находится курсор. В интерфейсе определены пять методов:

.IsDirty – проверяет объект на предмет изменений, сделанных в текущем файле. Наше расширение не требует данного метода, поэтому возвращаем E_NOTIMPL.
.Load – открывает указанный файл и инициализирует объект из содержимого файла. Мы будем использовать этот метод для получения имени файла, на котором находится курсор.
.Save – сохраняет объект в указанном файле. Мы его не используем и возвращаем E_NOTIMPL.
.SaveCompleted – уведомляет объект, о том, что он может быть переведён из режима NoScribble в режим Normal. Не используем, поэтому возвращаем E_NOTIMPL.
.GetCurFile – получает текущее имя файла, связанного с объектом. Тоже возвращаем E_NOTIMPL.

Load определена следующим образом:

function Load(pszFileName: PoleStr; dwMode: LongInt ): HResult; stdcall;

.pszFileName – указатель на строку, содержащую абсолютный путь открываемого файла. Строка должна завершаться нулём.
.dwMode – содержит набор атрибутов для открытия файла.

Чтобы получить имя файла и его путь, мы будем использовать только IPersistFile; фактически мы не используем интерфейс для доступа к файлу, поэтому игнорируем флаги. Стандартная реализация метода Load сохраняет содержимое pszFileName в приватную переменную, которая будет использоваться в IQueryInfo::GetInfoTip для расположения файла.

 

 

   Проект Delphi: Infotip

Скачать исходник
Скомпилированный проект (169KB) - Содержит DPRInfoTip.dll.
Project Files (6KB) - Содержит исходные файлы проекта на Delphi.
Registration File (1KB) - Содержит два файла регистрации (один для Win9x, а второй для Win2000).

Исходник содержит завершённое расширение оболочки Infotip. Infotip будет отображать имя файла, тип проекта (Программа или Библиотека), имя проекта (из файла исходника), и размер файла в байтах.

Для начала нам необходимо создать объект автоматизации и назвать его DPRInfoTip. Сперва кликните File | New... (для открытия архива объектов), затем на закладке ActiveX выберите ActiveX Library. Будет сгенерирована пустая библиотека ActiveX и экспортированы необходимые функции, требуемые для данного объектаавтоматизации.

Далее, снова кликните File | New... и на закладке ActiveX выберите Automation Object. После этого откроется Automation Object Wizard, в котором необходимо ввести DPRInfoTip как имя CoClass (ниже показано, как выглядит этот диалог). Оставьте остальные опции по умолчанию и нажмите OK, будет сгенерирована основная Type Library и добавлен каркас для интерфейса IDPRInfoTip, который генерируется автоматически.

Automation Object Wizard

Как только файлы будут созданы, то следующее, что нам нужно сделать - это добавить поддержку для дополнительных интерфейсов, которые будут поддерживаться:

TDPRInfoTip = class(TAutoObject, IDPRInfoTip, IQueryInfo, IPersistFile, IPersist);

Обратите внимание: нам необходимо включить также и IPersist, потому что IPersistFile наследуется от IPersist.

Прилагаемы исходник можно использовать для всех расширений InfoTip. Единственное, что нужно изменить - это метод GenerateTip. Этот метод определяет текст, который будет отображён InfoTip.

В методе Initialization, мы вызываем SHGetMalloc, которая заставляет Windows распределить некоторое количество памяти, а затем возвращает указатель на неё в приватной (private) переменной pMalloc. В деструкторе устанавливаем pMalloc равной Nil. Это позволяет оболочке Windows выделять память при необходимости.

IPersistFile::Load
Когда мышка находится на файле, то оболочка вызывает метод Load, чтобы получить имя файла. В нашем случае имя файла хранится в приватной переменной FFile, поэтому оно будет доступно когда нам необходимо будет сгенерировать текст InfoTip.

 

function TDPRInfoTip.Load
  (pszFileName: POleStr;
   dwMode: Integer):
   HResult; 
begin 
 FFile  := pszFileName; 
 Result := S_OK; 
end; 

Для всех остальных методов IPersistFile просто возвращаем E_NOTIMPL.

IQueryInfo::GetInfoTip
Когда оболочка готова отобразить InfoTip, она вызывает метод GetInfoTip для получения текста для отображения. В нашем случае, чтобы определить текст для отображения, вызывается метод GenerateTip.

 

   Регистрация расширения Infotip
Регистрация происходит в два этапа:

1. При помощи regsvr32.exe регистрируется COM DLL (Пуск (Start)..Выполнить(Run))

regsvr32 "C:\...\DPRInfoTip.dll"

2. Добавление ссылки на расширение (.dpr) в ключ реестра HKEY_CLASSES_ROOT.

По умолчанию значение для нового ключа должно быть CLSID объекта COM, который содержит расширение оболочки. Данное значение можно получить из файла Type Library, который был сгенерирован Delphi (имя файла оканчивается на "_TLB.pas"). Для нашего примера расширения CLSID назван CLASS_DPRInfoTip и содержит значение "{B20433A8-D083-11D4-993A-00D00912C440}".

Самый простой способ внести изменения в реестр - это сделать копию файла .REG, содержащуюся в исходниках проекта. Просто измените CLSID и расширение файла на необходимые значения.

Одно важное замечание: если Вы регистрируете расширение оболочки в Windows NT или 2000, то необходимо войти в систему с правами администратора.