Главная » Delphi » Обработчики пиктограмм

0

позволяют применять пиктограммы для различных эк земпляров файлов одного  типа. В данном  примере описан объект обработчика пикто грамм TIconHandler, который обеспечивает различные пиктограммы для разных типов  пакетных файлов Borland Package  (BPL).  В зависимости от типа  пакета —  вре мени  выполнения, времени разработки, универсального или  иного  —  при  отображе нии этих файлов в папке оболочки будут использоваться различные пиктограммы.

Флаги пакета

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

TPackType = (ptDesign, ptDesignRun, ptNone, ptRun);Приведем код метода:

function TIconHandler.GetPackageType: TPackType;

var

PackMod: HMODULE;

PackFlags: Integer;

begin

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

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

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

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

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

LOAD_LIBRARY_AS_DATAFILE);

if PackMod = 0 then begin

Result := ptNone;

Exit;

end;

try

GetPackageInfo(PackMod, nil, PackFlags, PackInfoProc);

finally

FreeLibrary(PackMod);

end;

// Отфильтровать по маске все флаги, кроме design и run,

// а результат возвратить.

case PackFlags and (pfDesignOnly or pfRunOnly) of

pfDesignOnly: Result := ptDesign;

pfRunOnly: Result := ptRun;

pfDesignOnly or pfRunOnly: Result := ptDesignRun;

else

Result := ptNone;

end;

end;

Задача  этого  метода  заключается в вызове метода  GetPackageInfo() из модуля SysUtils для получения флагов  пакета.  Отметим, что  для оптимизации производи тельности вместо  встроенной процедуры Delphi  LoadPackage() для  загрузки  биб лиотеки пакета  вызывается функция API LoadLibraryEx(). Внутри  функции Load- Package() содержится вызов  функции API LoadLibrary(), которая загружает биб лиотеку BPL. После  загрузки  библиотеки вызывается функция Initialize- Package(), выполняющая инициализацию каждого  модуля в пакете. Но  поскольку  в данном  случае нужно лишь получить флаги  пакета, которые хранятся в файле ресур сов, связанном с библиотекой BPL, можно  вполне обойтись загрузкой пакета  с помо щью функции LoadLibraryEx() с флагом  LOAD_LIBRARY_AS_DATAFILE в качестве параметра.

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

Как  уже упоминалось в настоящей главе,  обработчики пиктограмм должны  под держивать оба  интерфейса —  и IExtractIcon (определенный в модуле  ShlObj), и IPersistFile (определенный в модуле ActiveX). Определения этих  интерфейсов имеют следующий вид:type

IExtractIcon = interface(IUnknown)

[‘{000214EB-0000-0000-C000-000000000046}’]

function GetIconLocation(uFlags: UINT; szIconFile: PAnsiChar;

cchMax: UINT; out piIndex: Integer;

out pwFlags: UINT): HResult; stdcall;

function Extract(pszFile: PAnsiChar; nIconIndex: UINT;

out phiconLarge, phiconSmall: HICON;

nIconSize: UINT): HResult; stdcall;

end;

IPersistFile = interface(IPersist) [‘{0000010B-0000-0000-C000-000000000046}’] 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;

end;

Хотя  на первый взгляд  кажется, что  данные  интерфейсы выполняют значитель ный  объем  работ, однако  это  впечатление обманчиво: на самом  деле  только  два из приведенных выше  методов должны  быть  реализованы. Первый из  них —  метод IPersistFileLoad(). Данный метод  вызывается для  инициализации расширения оболочки, и внутри  него  нужно  предусмотреть сохранение имени файла, передавае мого с помощью параметра pszFileName. Ниже  приведена реализация такого  метода в объекте TExtractIcon:

function TIconHandler.Load(pszFileName: POleStr;

dwMode: Longint): HResult;

begin

// Этот метод вызывается для инициализированного обработчика

// пиктограмм. Необходимо сохранить имя файла, которое передано

// в параметре pszFileName.

FFileName := pszFileName;

Result := S_OK;

end;

Второй   метод,    подлежащий   обязательной   реализации, —     это    IExtractI- con.GetIconLocation(). Передаваемые ему параметры рассматриваются далее  в настоящей главе.

Параметр uFlags указывает на тип отображаемой пиктограммы. Этот параметр может принимать значение 0, GIL_FORSHELL или GIL_OPENICON. Значение GIL_FORSHELL сви детельствует о том,  что  пиктограмма будет отображаться в папке  системной оболочки. Значение GIL_OPENICON указывает, что пиктограмма должна  быть  в “открытом” состоя нии, если доступны изображения как для открытого, так и для закрытого состояний. Если данный флаг  не задан,  то пиктограмма должна  быть  в нормальном, т.е. “закрытом”, со стоянии. Этот флаг обычно используется для объектов папки.Параметр szIconFile представляет собой  буфер,  в который передается инфор мация  о расположении пиктограммы. Параметр cchMax содержит размер такого  бу фера.  Параметр piIndex — переменная целого  типа — получает индекс  пиктограммы, уточняющий ее расположение.

Параметр pwFlags может  принимать нулевое  значение либо  одно  из  значений, приведенных в табл. 16.8.

Таблица 16.8. Значения параметра pwFlags функции GetIconLocation()

Флаг                                              Назначение

GIL_DONTCACHE    Битовая карта  этой  пиктограммы не подлежит кэшированию вызывающей процедурой. Это необходимо, поскольку  в последующих версиях оболочки может  быть  введен  флаг GIL_DONTCACHELOCATION

GIL_NOTFILENAME  Местонахождение  пиктограммы  не   может   быть   описано парой значений “имя файла/индекс”. Для получения изобра жения пиктограммы вызывающие процедуры должны обратиться к методу IExtractIcon.Extract()

GIL_PERCLASS         Все объекты данного класса  имеют  одну и ту же пиктограмму.

Этот флаг  используется внутренними средствами оболочки. Обычные реализации интерфейса IExtractIcon не  требуют данного флага,  поскольку  для случаев, когда одному объекту соответствует одна  пиктограмма, обработчик пиктограммы не требуется. Для реализации пиктограмм типа “одна пиктограмма на  один  класс”  рекомендуется просто зарегистрировать  стан дартную пиктограмму для данного класса

GIL_PERINSTANCE  Каждый  объект этого  класса  имеет  свою  собственную пиктог рамму. Данный флаг используется оболочкой в случаях при менения файла установки setup.exe. В таких случаях оболочка может  “знать” о нескольких объектах, имеющих идентичные имена, но использовать различные пиктограммы. Обычные реализации интерфейса IExtractIcon не требуют этого флага

GIL_SIMULATEDOC  Вызывающая    процедура    должна     создать     пиктограмму документа, используя указанную пиктограмму

Реализация метода GetIconLocation() в объекте TIconHandler выглядит следую

щим образом:

function TIconHandler.GetIconLocation(uFlags: UINT;

szIconFile: PAnsiChar; cchMax: UINT;

out piIndex: Integer; out pwFlags: UINT): HResult;

begin

Result := S_OK;

try

// Возвращает DLL по имени модуля искомой пиктограммы

GetModuleFileName(HInstance, szIconFile, cchMax);

// Сообщает оболочке о том, что изображение не подлежит// кэшированию при изменении пиктограммы, а также о том, что

// каждый экземпляр может иметь свою собственную пиктограмму.

pwFlags := GIL_DONTCACHE or GIL_PERINSTANCE;

// Индекс пиктограммы согласуется с типом TPackType

piIndex := Ord(GetPackageType);

except

// В случае ошибки используем пиктограмму по умолчанию.

piIndex := Ord(ptNone);

end;

end;

Пиктограммы связываются с библиотекой DLL расширения оболочки в виде файла ресурсов, поэтому  имя текущего  файла, возвращаемое функцией GetModuleFile- Name(), записывается в буфер  szIconFile. Пиктограммы организованы таким  обра зом, чтобы  индекс  пиктограммы для типа  пакета  соответствовал индексу типа  пакета  в перечне типов  TPackType. Поэтому  значение, возвращаемое функцией GetPackage- Type(), присваивается параметру piIndex.

Регистрация

должны  быть  зарегистрированы в системном реестре в следующем виде:

HKEY_CLASSES_ROOT\<тип файла>\shellex\IconHandler

Как  и  в  случае  с  другими  расширениями, для  регистрации обработчика пикто грамм  создается потомок класса  TComObjectFactory. Код модуля обработчика пик тограмм, включающий в себя  код объекта TComObjectFactory, приведен в листин ге 16.11, а на рис. 16.11 показана папка  системной оболочки, содержащая пакеты раз личных типов.  Обратите внимание: для отображения различных типов  пакетов используются различные пиктограммы.

Рис. 16.11. Результат использования обработчика пиктограмм

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

unit IconMain;

interface

uses Windows, ActiveX, ComObj, ShlObj;

type

TPackType = (ptDesign, ptDesignRun, ptNone, ptRun);

TIconHandler = class(TComObject, IExtractIcon, IPersistFile)

private

FFileName: string;

function GetPackageType: TPackType;

protected

// Методы интерфейса IExtractIcon

function GetIconLocation(uFlags: UINT; szIconFile: PAnsiChar;

cchMax: UINT; out piIndex: Integer;

out pwFlags: UINT): HResult; stdcall;

function Extract(pszFile: PAnsiChar; nIconIndex: UINT;

out phiconLarge, phiconSmall: HICON;

nIconSize: UINT): 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;

end;

TIconHandlerFactory = class(TComObjectFactory)

protected

function GetProgID: string; override;

procedure ApproveShellExtension(Register: Boolean;

const ClsID: string); virtual;

public

procedure UpdateRegistry(Register: Boolean); override;

end;

implementation

uses SysUtils, ComServ, Registry;

{ TIconHandler }

procedure PackInfoProc(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);

begin

// В реализации данной процедуры нет необходимости, поскольку

// нужны только флаги пакета, а не модули.

end;

function TIconHandler.GetPackageType: TPackType;

var

PackMod: HMODULE;

PackFlags: Integer;

begin

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

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

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

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

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

LOAD_LIBRARY_AS_DATAFILE);

if PackMod = 0 then begin

Result := ptNone;

Exit;

end;

try

GetPackageInfo(PackMod, nil, PackFlags, PackInfoProc);

finally

FreeLibrary(PackMod);

end;

// Отфильтровать по маске все флаги, кроме design и run,

// а результат возвратить.

case PackFlags and (pfDesignOnly or pfRunOnly) of

pfDesignOnly: Result := ptDesign;

pfRunOnly: Result := ptRun;

pfDesignOnly or pfRunOnly: Result := ptDesignRun;

else

Result := ptNone;

end;

end;

{ TIconHandler.IExtractIcon }

function TIconHandler.GetIconLocation(uFlags: UINT;

szIconFile: PAnsiChar; cchMax: UINT;

out piIndex: Integer; out pwFlags: UINT): HResult;

begin

Result := S_OK;

try

// Возвращает DLL по имени модуля искомой пиктограммы

GetModuleFileName(HInstance, szIconFile, cchMax);

// Сообщить оболочке о том, что изображение не подлежит

// кэшированию при изменении пиктограммы, а также о том, что

// каждый экземпляр может иметь свою собственную пиктограмму.

pwFlags := GIL_DONTCACHE or GIL_PERINSTANCE;// Индекс пиктограммы согласуется с типом TPackType piIndex := Ord(GetPackageType);

except

// В случае ошибки используем пиктограмму по умолчанию.

piIndex := Ord(ptNone);

end;

end;

function TIconHandler.Extract(pszFile: PAnsiChar;

nIconIndex: UINT; out phiconLarge, phiconSmall: HICON;

nIconSize: UINT): HResult;

begin

// Данный метод нужно реализовывать только в том случае, если

// пиктограмма сохранена в каком-то пользовательском формате.

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

// возвращается значение S_FALSE.

Result := S_FALSE;

end;

{ TIconHandler.IPersist }

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

begin

// Для обработчиков пиктограмм данный метод не вызывается.

Result := E_NOTIMPL;

end;

{ TIconHandler.IPersistFile }

function TIconHandler.IsDirty: HResult;

begin

// Для обработчиков пиктограмм этот метод не вызывается.

Result := S_FALSE;

end;

function TIconHandler.Load(pszFileName: POleStr;

dwMode: Longint): HResult;

begin

// Этот метод вызывается для инициализированного обработчика

// пиктограмм. Необходимо сохранить имя файла, которое передано

// в параметре pszFileName.

FFileName := pszFileName;

Result := S_OK;

end;

function TIconHandler.Save(pszFileName: POleStr;

fRemember: BOOL): HResult;

begin

// Для обработчиков пиктограмм этот метод не вызывается.

Result := E_NOTIMPL;

end;

function TIconHandler.SaveCompleted(pszFileName: POleStr): HResult;begin

// Для обработчиков пиктограмм этот метод не вызывается.

Result := E_NOTIMPL;

end;

function TIconHandler.GetCurFile(out pszFileName: POleStr): HRe- sult;

begin

// Для обработчиков пиктограмм этот метод не вызывается.

Result := E_NOTIMPL;

end;

{ TIconHandlerFactory }

function TIconHandlerFactory.GetProgID: string;

begin

// Для расширений контекстного меню ProgID не нужен.

Result := ”;

end;

procedure TIconHandlerFactory.UpdateRegistry(Register: Boolean);

var

ClsID: string;

begin

ClsID := GUIDToString(ClassID);

inherited UpdateRegistry(Register);

ApproveShellExtension(Register, ClsID);

if Register then begin

// Необходимо зарегистрировать .bpl как новый тип файла.

CreateRegKey(‘.bpl’, ”, ‘BorlandPackageLibrary’);

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

// пиктограмм для файлов .bpl.

CreateRegKey(‘BorlandPackageLibrary\shellex\IconHandler’,

”, ClsID);

end

else begin

DeleteRegKey(‘.bpl’);

DeleteRegKey(‘BorlandPackageLibrary\shellex\IconHandler’);

end;

end;

procedure TIconHandlerFactory.ApproveShellExtension(Register: Boo- lean;

const ClsID: string);

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

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

const

SApproveKey = ‘SOFTWARE\Microsoft\Windows\CurrentVersion\

?Shell Extensions\Approved';

begin

with TRegistry.Create do

try

RootKey := HKEY_LOCAL_MACHINE;

end;

if not OpenKey(SApproveKey, True) then Exit;

if Register then WriteString(ClsID, Description)

else DeleteValue(ClsID);

finally

Free;

end;const

CLSID_IconHandler: TGUID =

‘{ED6D2F60-DA7C-11D0-A9BF-90D146FC32B3}';

initialization

TIconHandlerFactory.Create(ComServer, TIconHandler,

CLSID_IconHandler, ‘DDG_IconHandler’,

‘DDG Icon Handler Shell Extension Example’,

ciMultiInstance, tmApartment);

end.

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

По теме:

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