Главная » Delphi » Обработчики контекстной подсказки

0

Контекстная подсказка (InfoTip) впервые появилась в оболочке Windows  2000. Об работчики контекстной подсказки обеспечивают специальные всплывающие контек стные  информационные окна (известные в Delphi как ToolTip), которые возникают в оболочке при  помещении мыши  поверх пиктограммы, представляющей файл.  Стан дартная контекстная  подсказка, отображаемая  оболочкой  Windows,  содержит имя, тип (определенный на основании его расширения) и размер файла. применяются тогда,  когда необходимо отобразить несколько больше информации, чем предоставляет стандартный встроенный механизм.

Наибольший интерес для разработчиков Delphi  представляют файлы пакетов. Не смотря на то, что все знают,  что файлы пакетов могут содержать один  или несколько модулей,  но  не  известно наверняка, какие  именно модули  он  содержит. Ранее  в на стоящей главе  был  представлен обработчик контекстного меню,  способный предос тавить подобную  информацию. Для этого  после  выбора соответствующего пункта контекстного меню запускалось внешнее приложение, которое и предоставляло соот ветствующую  информацию. Теперь  рассмотрим, как  получить  такую  информацию еще проще, и без использования внешней программы.

Интерфейсы обработчика контекстной подсказки

должны  реализовать интерфейсы IPer- sistFile и IQueryInfo. Интерфейс IPersistFile рассматривался ранее, при  об суждении  ярлыков и обработчиков пиктограмм. Здесь  он используется для того,  что бы  получить имя  рассматриваемого файла. Интерфейс  IQueryInfo относительно прост  — он содержит два метода — и определен в модуле ShlObj следующим образом:

type

IQueryInfo = interface(IUnknown)

[SID_IQueryInfo]

function GetInfoTip(dwFlags: DWORD;end;

var ppwszTip: PWideChar): HResult; stdcall;

function GetInfoFlags(out pdwFlags: DWORD): HResult; stdcall;Оболочка обращается к методу  GetInfoTip(), чтобы  вызвать контекстную под сказку для данного файла. Параметр DwFlags в настоящее время  не используется. Па раметр ppwszTip возвращает строку контекстной подсказки.

НА ЗАМЕТКУ

Параметр  PpwszTip представляет  собой  указатель  на  символьную  строку  типа WideChar. Память для этой строки следует выделять внутри обработчика контекстной подсказки с помощью системы выделения памяти оболочки. Оболочка сама несет от- ветственность за освобождение этой памяти.

Реализация

Подобно другим расширениям оболочки, обработчик контекстной подсказки реа лизован в качестве DLL простого сервера COM. Объект COM содержит в своей  реа лизации методы  IQueryInfo и IPersistFile. В листинге 16.12 приведено содержи мое файла  InfoMain.pas, представляющего собой  главный модуль проекта DDGIn- foTip, который содержит реализацию обработчика контекстной подсказки.

Листинг 16.12. InfoMain.pas — главный модуль реализации обработчика контекстной подсказки

unit InfoMain;

{$WARN SYMBOL_PLATFORM OFF}

interface uses

Windows, ActiveX, Classes, ComObj, ShlObj;

type

TInfoTipHandler = class(TComObject, IQueryInfo, IPersistFile)

private

FFileName: string;

FMalloc: IMalloc;

protected

{ IQUeryInfo }

function GetInfoTip(dwFlags: DWORD;

var ppwszTip: PWideChar): HResult; stdcall;

function GetInfoFlags(out pdwFlags: DWORD): HResult; stdcall;

{IPersist}

function GetClassID(out classID: TCLSID): HResult; stdcall;

{ IPersistFile }

function IsDirty: HResult; stdcall;

function Load(pszFileName: POleStr;

dwMode: Longint): HResult; stdcall;

function Save(pszFileName: POleStr;fRemember: BOOL): HResult; stdcall;

function SaveCompleted(pszFileName: POleStr): HResult;

stdcall;

function GetCurFile(out pszFileName: POleStr): HResult;

stdcall;

public

procedure Initialize; override;

end;

TInfoTipFactory = class(TComObjectFactory)

protected

function GetProgID: string; override;

procedure ApproveShellExtension(Register: Boolean;

const ClsID: string); virtual;

public

procedure UpdateRegistry(Register: Boolean); override;

end;

const

Class_InfoTipHandler: TGUID =

‘{5E08F28D-A5B1-4996-BDF1-5D32108DB5E5}';

implementation

uses ComServ, SysUtils, Registry;

const

TipBufLen = 1024;

procedure PackageInfoCallback(const Name: string;

NameType: TNameType; Flags: Byte; Param: Pointer);

var

S: string;

begin

// При передаче имени содержащегося модуля добавить его к

// списку модулей, переданных в параметре Param.

if NameType = ntContainsUnit then begin

S := Name;

if PChar(Param)^ <> #0 then S := ‘, ‘ + S;

StrLCat(PChar(Param), PChar(S), TipBufLen);

end;

end;

function TInfoTipHandler.GetClassID(out classID: TCLSID): HResult;

begin

classID := Class_InfoTipHandler;

Result := S_OK;

end;

function TInfoTipHandler.GetCurFile(out pszFileName: POleStr): HResult;

begin

Result := E_NOTIMPL;end;

function TInfoTipHandler.GetInfoFlags(out pdwFlags: DWORD): HResult;

begin

Result := E_NOTIMPL;

end;

function TInfoTipHandler.GetInfoTip(dwFlags: DWORD;

var ppwszTip: PWideChar): HResult;

var

PackMod: HModule;

TipStr: PChar;

Size, Flags, TipStrLen: Integer;

begin

Result := S_OK;

if (CompareText(ExtractFileExt(FFileName), ‘.bpl’) = 0) and

Assigned(FMalloc) then begin

// Поскольку необходимо получить доступ только к ресурсам

// пакета, используем функцию LoadLibraryEx с

// параметром LOAD_LIBRARY_AS_DATAFILE, обеспечивающим высокую

// скорость загрузки пакета.

PackMod := LoadLibraryEx(PChar(FFileName), 0,

LOAD_LIBRARY_AS_DATAFILE);

if PackMod <> 0 then

try

TipStr := StrAlloc(TipBufLen);

try

// Заполнить нулями область памяти, занимаемую строкой

FillChar(TipStr^, TipBufLen, 0);

// Заполнить строку подсказки содержащимися модулями

GetPackageInfo(PackMod, TipStr, Flags,

PackageInfoCallback);

TipStrLen := StrLen(TipStr) + 1;

Size := (TipStrLen + 1) * SizeOf(WideChar);

// использовать механизм выделения память оболочки

ppwszTip := FMalloc.Alloc(Size);

// Копировать PAnsiChar в PWideChar

MultiByteToWideChar(0, 0, TipStr, TipStrLen,

ppwszTip, Size);

end;

end;

finally

StrDispose(TipStr);

end;

finally

FreeLibrary(PackMod);

end;procedure TInfoTipHandler.Initialize;

begin

inherited;

// применить систему выделения памяти оболочки

// и сохранить результатSHGetMalloc(FMalloc);

end;

function TInfoTipHandler.IsDirty: HResult;

begin

Result := E_NOTIMPL;

end;

function TInfoTipHandler.Load(pszFileName: POleStr;

dwMode: Integer): HResult;

begin

// Это единственный метод интерфейса IPersistFile, необходимый

// для хранения имени файла

FFileName := pszFileName;

Result := S_OK;

end;

function TInfoTipHandler.Save(pszFileName: POleStr;

fRemember: BOOL): HResult;

begin

Result := E_NOTIMPL;

end;

function TInfoTipHandler.SaveCompleted(pszFileName: POleStr): HResult;

begin

Result := E_NOTIMPL;

end;

{ TInfoTipFactory }

function TInfoTipFactory.GetProgID: string;

begin

// Идентификатор программы (ProgID) для расширения контекстной

// подсказки оболочки не нужен.

Result := ”;

end;

procedure TInfoTipFactory.UpdateRegistry(Register: Boolean);

var

ClsID: string;

begin

ClsID := GUIDToString(ClassID);

inherited UpdateRegistry(Register);

ApproveShellExtension(Register, ClsID);

if Register then begin

// Зарегистрировать эту DLL как обработчик контекстной

// подсказки для файлов .bpl

CreateRegKey(‘.bpl\shellex\{00021500-0000-0000-C000-

?000000000046}’, ”, ClsID);

end

else begin

DeleteRegKey(‘.bpl\shellex\{00021500-0000-0000-C000-

?000000000046}’);end;

end;

procedure TInfoTipFactory.ApproveShellExtension(Register: Boolean;

const ClsID: string);

// Этот элемент системного реестра необходим для корректной работы

// расширения под управлением Windows NT.

const

SApproveKey = ‘SOFTWARE\Microsoft\Windows\CurrentVersion\

?Shell Extensions\Approved';

begin

with TRegistry.Create do

try

RootKey := HKEY_LOCAL_MACHINE;

if not OpenKey(SApproveKey, True) then Exit;

if Register then WriteString(ClsID, Description)

else DeleteValue(ClsID);

finally

Free;

end;

end;

initialization

TInfoTipFactory.Create(ComServer, TInfoTipHandler,

Class_InfoTipHandler, ‘InfoTipHandler’,

‘DDG sample InfoTip handler’,

ciMultiInstance, tmApartment);

end.Эта реализация содержит два интересных момента. Обратите внимание, что  метод Initialize() не только  получает, но и сохраняет экземпляр системы выделения памя ти оболочки. Впоследствии он используется для выделения памяти для строки контек стной  подсказки в методе  GetInfoTip(). Метод Load() передает имя рассматриваемо го файла  обработчику. Основную работу  осуществляет метод  GetInfoTip(), который получает информацию о пакете  с помощью функции GetPackageInfo(), рассмотрен ной ранее в настоящей главе. Функция  обратного вызова  PackageInfoCallback() не однократно вызывается внутри  функции GetPackageInfo(), чтобы  один за другим до бавлять имена файлов в стороку контекстной подсказки.

Регистрация

Как  можно  заметить в листинге 16.12,  методика регистрации DLL сервера COM практически аналогична регистрации других расширений оболочки, приведенных в настоящей главе.  Главным  различием является ключ системного реестра, в которым регистрируются обработчики  контекстной  подсказки; для  них  установлено следую щее местоположение:

HKEY_CLASSES_ROOT\<расширение файла>\shellex\{00021500-0000-0000-

?C000-000000000046}Где <расширение файла> представляет собой  расширение файла, включая  в себя предшествующую  точку.  Ниже  (рис. 16.12)  приведен пример обработчика контекст ной подсказки в действии.

Рис. 16.12. Обработчик контекстной  подсказки в действии

Резюме

В этой  главе  были  рассмотрены различные аспекты расширения оболочки Windows:  помещение пиктограмм в область  панели задач,  создание панели  инстру ментов рабочего стола системы (AppBars), работа с ярлыками и разработка расшире ний  оболочки Windows  различных типов.  Материал данной главы  основан на знани ях, содержащихся в предыдущем разделе, —  прежде всего  об объектах COM.  В главе

17, “Применение интерфейса API Open Tools”, содержится более подробная инфор

мация о применении интерфейсов при компонент ориентированной разработке.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии