    ГЛАВА 29

    Работа с интерфейсом Open Tools API 

    Тодд Миллер 

    Вам никогда не хотелось, чтобы интегрированная среда разработки (IDE) 
Delphi делала еще больше работы вместо вас? Например, было бы неплохо 
научиться переносить проект в другой каталог с сохранением целостности всех 
ссылок файловой системы или осуществлять поиск в исходных текстах VCL по 
ключевому слову и загружать найденный файл в редактор. С помощью Open Tools 
API сделать это легко и просто. В настоящей главе рассказывается об Open Tools 
API и создании экспертов. 
    Вы можете заметить, что встроенные эксперты в Delphi называются мастерами. 
(Wizards дословно означает колдун, чародей. В русскоязычных версиях Windows 
используется перевод мастер — Прим. перев.) Однако я буду использовать именно 
термин эксперт, особенно учитывая, что в Open Tools API используется именно 
это название (по крайней мере, в просмотренных мною исходных текстах). 
    Open Tools API представляет собой набор классов, позволяющий вам выполнить 
множество задач в среде Del-"f>hi7 В экспертах Open Tools API может 
использоваться для выполнения следующих задач. 
    И   Получение информации о проекте. В   Получение информации о модуле или 
форме. в   Управление модулями проекта (открытие, добавление, создание, 
закрытие и т.д.). 
    •   Управление ресурсами  проекта (пиктограммами, курсорами, рисунками и т.п.). 
    •	Управление меню Delphi. 
    •	Регистрация изменений в проекте. 
    Ш	Регистрация изменений в модуле. 
    Интерфейс Open Tools API доступен только из программ, запущенных как часть 
интегрированной среды Delphi (именно так запускаются эксперты). Эксперты — 

    29 

    Open Tools API 

    Информация о возможностях Open Tools API интегрированной среды Delphi. 

    Эксперты Delphi 

    Как создать и зарегистрировать четыре типа экспертов в интегрированной 
среде Delphi. 

    ToolServices — открытая дверь в Delphi 

    Изучите центральную часть интерфейса Open Tools API (ToolServices), чтобы 
управлять интегрированной средой Delphi. 

681

    это специализированные программы-надстройки, которые, будучи 
зарегистрированными, могут работать с Delphi IDE, выполняя перечисленные выше задачи. 
    В этой главе вы узнаете о создании и регистрации экспертов и изучите 
интерфейс ToolServices для управления средой Delphi и проектами. 
    В этой главе описан Open Tools API из Delphi 3. Рассмотренные здесь 
эксперты могут не работать в среде разработки Delphi 1 из-за изменений в Open 
Tools API. Здесь не рассматриваются вопросы, связанные с раз-^    личиями 
между версиями Delphi, поэтому, если вам необходимо разработать экспертов для 
ранних версий Delphi, обратитесь к другой литературе по Delphi. 

    Создание эксперта Delphi 

    Для создания нового эксперта необходимо наследовать новый класс от класса 
TIExpert, заменив часть методов (какую именно, зависит от создаваемого 
эксперта). TIExpert определен как абстрактный виртуальный класс, что означает, 
что его функциональность задана, но не реализована. Эти методы класса TIExpert 
созданы для предоставления информации о вашем эксперте Delphi, чтобы среда 
могла вызвать вашего эксперта и знала, как его запускать и как с ним работать. 

    Стили экспертов 

    Прежде чем приступить к изучению методов класса TIExpert, рассмотрим типы 
экспертов, доступные в Delphi: стандартный, надстройки, формы и проекта 
(standard, add-in, form и project), описанные в табл. 29.1. 

    Таблица 29.1. Стили экспертов Delphi 

    Стиль	Способ вызова 

    Стандартный	Добавить в подменю Help пункт меню 
    Надстройки	Добавить в определенное экспертом подменю пункт меню 
    Формы	Добавить во вкладку Forms диалогового окна New Items пиктограмму эксперта 
    Проекта	Добавить во вкладку Projects диалогового окна New Items 
пиктограмму эксперта 

    Основное отличие в стилях экспертов заключается в способе jjbisosa 
эксперта пользователем в среде Delphi. Другими словами, стиль не влияет на 
механизм работы эксперта с Operi TooJs_.Aj,I. Само собой разумеется, стиль 
эксперта должен соответствовать его назначению. "" 
    Простейший вид эксперта — стандартный, поскольку при его использовании 
нужно только указать текст для пункта в подменю Help и определить, когда новый 
пункт доступен, а когда нет. Эксперты форм и проектов используются при 
создании неких специфичных проектов или форм и, как правило, интенсивно 
используют функции управления модулями Open Tools API. 
    3	Исходные тексты Open Tools API доступны только в поставках Delphi 
Developer и Client Server, в то время как скомпилированные модули поставляются 
со всеми версиями Delphi. Исходный код (если у вас соответствующая поставка 
Delphi) можно найти в каталоге .. \DELPHI   3\SOURCE\TOOLSAPI. 

    Реализация класса TIExpert 

    При разработке эксперта необходимо переопределить до десяти методов класса 
TIExpert, в зависимости от разрабатываемого эксперта. Полное определение 
абстрактного класса TIExpert приведено в листинге 29.1. 

    Листинг 29.1. EXPINTF. PAS. Определение абстрактного класса TIExpert	| 

    TIExpert  =  class (TInterface) public 
    function GetName:   string;   virtual;   stdcall;   abstract; 
    function GetAuthor:   string;   virtual;   stdcall;   abstract; 


    682	Часть VI. Сложный материал 


    function GetComment: string; virtual; stdcall; abstract; function GetPage: 
string; virtual; stdcall; abstract; function GetGlyph: HICON; virtual; 
stdcall; abstract; function GetStyle: TExpertStyle; virtual; stdcall; 
abstract; function GetState: TExpertState; virtual; stdcall; abstract; 
function GetlDString: string; virtual; stdcall; abstract/function GetMenuText: 
string; virtual; stdcall; abstract; procedure Execute; virtual; stdcall; 
abstract; end; 

    Теперь познакомимся с методами поближе. Как вы видите, они предназначены 
для возврата среде Delphi информации о новом классе. 

    GetStyle 

    Эта функция определяет стиль эксперта. В качестве возвращаемого значения 
может использоваться одно из четырех значений: esStandard, esAddin, esForm, 
esProject. Для определения стандартного эксперта достаточно строки 
Result:=esStandard; О различиях между стилями экспертов рассказывалось 
выше в этой главе. 

    GetlDString 

    Этот метод должен переопределяться во всех экспертах. Возвращает строку, 
идентифицирующую эксперт. Поскольку строка должна быть уникальной, компания 
Borland рекомендует использовать следующий формат: ИмяКомпа-нии.Эксперт, например 

    Result   :=   'UDelphiS.Proj^ctlnfoExpert'; Если вы используете текст 
старого эксперта для создания нового, не забудьте изменить эту строку! 


    GetName 

    Эта функция также должна быть переопределена. Возвращает краткое 
описывающее имя эксперта, например 

    Result   :=   'Project   Information  Expert'; 

    В случае использования эксперта формы или проекта это имя будет 
подписьк^под соответствующей пиктограммой в диалоговом окне New 
Items.	уf!t)ffif'ffjQ" ЦЛИг S 

    GetMenuText 

    Этот метод необходим тoль|c?_дjlя_?т^дJ?гнoгo_экcпepтa и возвращает 
строку, которая будет внесена в подменю Help среды Delphi, например 

    Result   :=   'UD3   Project   Information  Expert...' 

    Метод GetMenuText вызывается при каждом выводе меню, поэтому можно сделать 
эксперта контекстночувствительным. 

    На 
    

    GetState 

    Этот метод, также необходимый только для стандартного эксперта, 
определяет, доступен ли в настоящий момент эксперт, т.е. может ли пользователь 
выбирать соответствующий пункт меню. 
    Метод GetState вызывается при каждом выводе меню, поэтому можно сделать 
эксперта контекстно-з^етку   чУв™ель„ым. 
    Вот пример подтверждения доступности эксперта: 

    Result   :=   [esEnabled]; 


    Глава 29. Работа с интерфейсом Open Tools API	683 


    Execute 

    Этот метод требуется для стандартных экспертов и экспертов форм и 
проектов. Он вызывается при выборе пункта меню эксперта или выбора пиктограммы 
эксперта в диалоговом окне. Добавленный эксперт не вызывает этого метода, так 
как имеет собственный обработчик события нажатия кнопки мыши, если он добавлен 
в меню Delphi. 
    Обычно метод отвечает за вывод некоего диалогового окна эксперта, например 

    procedure TProjectlnfo.Execute; begin 
    if not Assigned(ProjectlnfoForm)   then 
    ProjectlnfoForm   := TProjectlnfoForm.Create(Application); 
    ProjectlnfoForm.Show; 
    ProjectlnfoForm.SetFocus end; 

    He забудьте, что программист отвечает за уничтожение всех диалоговых окон, 
созданных экспертом, по окончании работы эксперта. Обычно это делается в 
разделе модуля f inalization. 

    GetPage 

    Этот метод необходим для экспертов форм и проектов. Он возвращает имя 
страницы, добавляемой в диалоговое окно New Items, например 

    Result   :=   'Projects'; 
    GetGlyph 

    Этот метод требуется для экспертов форм и проектов. Он возвращает 
дескриптор пиктограммы, выводимой в списках и диалоговых окнах формы (или 
проекта). При возврате значения 0 используется пиктограмма по умолчанию, например 

    Result   :=  Loadlcon(Hinstance,'MYICON'); 
    GetAuthor 

    Этот метод необходим для экспертов форм и проектов. Он возвращает имя 
автора или компании —производителя эксперта, выводимое в режиме детального 
просмотра в диалоговом окне New Items, например 

    Result   :=   'KIV  without   Co   (AKA  2:463/59)'; 
    GetComment 

    Этот метод требуется для экспертов форм и проектов. Он возвращает 
комментарий из одного-двух предложений, выводимый в режиме детального 
просмотра хранилища объектов, например 

    Result   :=   'DLL  project   expert.   Write   Delphi   1   Style   DLLs'; 

    Чтобы легче было запомнить, какой метод в проекте какого типа должен быть 
переопределен, обратите внимание на табл. 29.2. 

    Таблица 29.2. Переопределение методов класса TI Expert 

    Метод	Стандартный             Надстройки	Формы	Проекта 

    GetStyle	S                                        •/	•/	/• 
    GetlDString	•/                             •/	s	s 
    GetName	•/                             •/	•/	s 
    Execute	•/	s	V 
    GetPage		s	s 
    GetGlyph		s	•/ 
    GetAuthor		s	V 
    GetComment		•/	V 
    GetMenuText	s 
    GetState	s 


    684 Часть VI. Сложный материал 


    Теперь приступим к созданию эксперта. Создадим стандартную форму Delphi 
(для диалогового окна эксперта) и добавим определения наследованного класса 
эксперта в исходный текст эксперта (в раздел interface). Затем добавим 
реализацию методов эксперта в разделе implementation (листинг 29.2). 

    Листинг 29.2. СОМРЕХРТ . PAS. Общая форма и определение эксперта 

    unit CompExpt; interface 
    uses 
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
Exptlntf, Toollntf; 
    type 
    TGenericComponentDialog = class(TForm) procedure FormCreate(Sender: 
TObject); procedure FormClose(Sender: TObject; 
    var Action: TCloseAction); end; 
    Type 
    // Примечание. Нужны не все методы TIExpert. // Здесь они приведены для 
полноты картины. TGenericExpert = class(TIExpert) public 
    function GetlDString: string; Override; function GetStyle: TExpertStyle; 
Override; function GetState: TExpertState; Override; function GetMenuText: 
string; Override; function GetPage: string; Override; function GetName: 
string; Override; function GetAuthor: string; Override; function GetComment: 
string; Override; function GetGlyph: HICON; Override 
    procedure Execute; Override; end; 
    var GenericComponentDialog: TGenericComponentDialog; 
    procedure Register; implementation {$R *.DFM} 
    procedure Register; 
    begin 
    RegisterLibraryExpert(TGenericExpert.Create); end; 
    // TGenericExpert Implementation 
    / / ——— ———— ———— ———  ———  ———  ——  ———  '———   —    —   —	—   —       ' 
    function TGenericExpert.GetlDString: String; begin 
    Result := 'UDelphi3.GenericComponentExpert'; end; 
    function TGenericExpert.GetStyle: TExpertStyle; begin 
    Result := esStandard; // Стандартный эксперт, end; 


    Глава 29. Работа с интерфейсом Open Tools API	685 


    function TGenericExpert.GetState: TExpertState; begin 
    Result := [esEnabled] // Всегда доступен, end; 
    function TGenericExpert.GetMenuText: String; begin 
    Result := 'UD3 Generic Component Expert...1 end; 
    function TGenericExpert.GetName: String; begin 
    Result := 'Generic Component Expert' end; 
    function TGenericExpert .GetPage: string/begin 
    Result := ''; // Требуется только для экспертов форм и проектов, end; 
    function TGenericExpert.GetAuthor: string; begin 
    Result := ''; // Требуется только для экспертов форм и проектов, end; 
    function TGenericExpert.GetComment: String; begin 
    Result := ''; // Требуется только для экспертов форм и проектов, end; 
    function TGenericExpert.GetGlyph: HICON; begin 
    Result := 0; // Требуется только для экспертов форм и проектов, end; 
    procedure TGenericExpert.Execute; begin 
    if not Assigned(GenericComponentDialog) then 
    GenericComponentDialog := TGenericComponentDialog.Create(Application); 
    GenericComponentDialog.Show; 
    GenericComponentDialog.SetFocus; end; 
    / /______________________________________________________________________i__________ 
    // TTestDialog Implementation 
    / /_________________________________________ 
    / /  —— —— —— ——————————————————————————————— 
    procedure TGenericComponentDialog.FormCreate(Sender: TObject); begin if 
not Assigned(ToolServices) then Exit; 
    // Настройка диалогового окна эксперта, end; 
    procedure TGenericComponentDialog.FormClose(Sender: TObject; 
    var Action: TCloseAction); begin 
    Action := caFree; 
    GenericComponentDialog := Nil; end; 
    Initialization GenericComponentDialog := Nil; 
    Finalization end. 


    686	Часть VI. Сложный материал 


    В листинге приведены все методы TIExpert, хотя не все они используются, 
так как создаваемый эксперт— стандартный. 
    Заметьте, что класс TGenericExpert добавлен в исходный файл диалогового 
окна эксперта. Это не необ-Совет 1  Х°ДИМ°> н° удобно. 
    Теперь наша задача — добавить эксперта в интегрированную среду Delphi. 

    Регистрация эксперта 

    Определив тип и поведение эксперта, зарегистрщуйте^^его_д_с?ед?Ое1?Ь1 
одним из двух способов. Первый — определение эксперта как компонента путем 
вызовгГпроцедуры RegisterLibraryExpert из процедуры Register, используемой 
Delphi для установки компонентов. Именно этот метод здесь и используется. 
    Второй способ — создание DLL-библиотеки эксперта, после чего Delphi IDE 
вызовет определенную инициализирующую функцию в DLL с запросом о параметрах 
интерфейса эксперта. Список загружаемых экспертов Delphi берет из раздела 
Experts в реестре Windows.	•——.— ••- — - - -. 
    Главное достоинство первого способа состоит в том, что не надо закрывать 
среду Delphi при изменениях эксперта — его достаточно перекомпилировать. 
    Регистрация эксперта как компонента 
    Зарегистрировать эксперта в качестве компонента можно в два этапа. Первый 
— добавление специальной процедуры Register в модуль эксперта. 

    procedure  Register; 
    implementation {$R  *.DFM} procedure Register; begin 
    RegisterLibraryExpert(TGenericExpert.Create); end; 

    Эта процедура вызывается при регистрации Delphi компонентов и экспертов. В 
свою очередь, Delphi вызывает процедуру RegisterLibraryExpert, после чего 
эксперт становится частью Delphi IDE. 
    Второй этап, конечно же, заключается в добавлении эксперта в пакет 
инсталлированных компонентов. Детально об этом рассказывается в главе 15, 
"Работа с пакетами", а соответствующий dpk-файл можно найти на дополнительно 
распространяемой дискете в каталоге \UDELPHI3\CHP29\. 
    После установки эксперта соответствующий ему пункт меню появляется в 
подменю Help (рис. 29.1). 

    Регистрация эксперта DLL 

    Для регистрации эксперта как DLL также следует выполнить две операции. 
Первая состоит в создании нового проекта DLL, показанного в листинге 29.3. 

    ЛИСТИНГ 29.3. \UDELPHI3\CHP29\GENERIC\AS_DLL\DLLEXPRT . DPR. ПрОбКТ 
СОЗДЭНИЯ библиотеки DLL-ЭКСП 

    library DllExprt; 
    uses 
    Exptintf, 


    Глава 29. Работа с интерфейсом Open Tools API	687 


    dllexpt in 'dllexpt.pas' {GenericDLLDialog}; {$R *.RES} 
    exports	'      """" '""^s InitExpert name ExpertEntryPoint;}      , 
    begin end. 

    Обратите внимание, что функция InitExpert экспортируется с помощью 
специальной константы ExpertEntryPoint, которую Delphi определяет для всех 
экспертов в виде DLL. InitExpert работает так же, как и описанная в предыдущем 
разделе процедура Register. В листинге 29.4 приведена реализация функции InitExpert. 

    Рис. 29.1. Пункт меню для вызова стандартного эксперта 

    Листинг 29.4. \UDELPHI3\CHP29\GENERIC\AS_DLL\DLLEXPT.PAS. Реализация 
функции InitExpert '«щ 

    function InitExpert(ToolServices: TIToolServices; >  RegisterProc: TExpertRegisterProc; 
    var Terminate: TExpertTerminateProc): Boolean; export; stdcall; 
    implementation {$R *.DFM} 
    procedure TerminateExpert; begin 
    // Завершение работы эксперта, end; 
    function InitExpert(ToolServices: TIToolServices; 


    688 Часть VI. Сложный материал 


    RegisterProc: TExpertRegisterProc; var Terminate: TExpertTerminateProc): 
Boolean; export; stdcall; begin Result := False; 
    // Запущенное приложение — единственное. 
    if (ToolServices = Nil) or Assigned(Exptlntf.ToolServices) then Exit; 
    // Сохранить указатель на ToolService. Exptlntf.ToolServices := ToolServices; 
    // To же самое для родительского окна. Application.Handle := ToolServices.GetParentHandle; 
    // Установить процедуру завершения. Terminate := TerminateExpert; 
    // Зарегистрировать эксперта. RegisterProc(TGenericExpert.Create); 
    { Все получилось. } Result := True; end; 
    Функция initExpert предназначена для получения ссылки на объекты 
ToolService для дальнейшего использования и вызова процедуры RegisterProc для 
регистрации эксперта. При необходимости можете определить процедуру 
завершения, как в приведенном примере. 
    Вторая операция представляет собой простую компиляцию DLL и добавление 
записи в системный реестр для того, чтобы среда Delphi могла загрузить и 
зарегистрировать эксперта. 
    Воспользуйтесь программой RegEdit и добавьте запись. 

    HKEY_CURRENT_USER Software Borland Delphi 3.0 
    Experts 
    TestExpert=C:\UDELPHI3\CHP29\GENERIC\DLL\DLLEXP.DLL 


    ПРЕДОСТЕРЕЖЕНИЕ 

    Необходимо перезапустить Delphi для того, чтобы среда зарегистрировала 
DLL. Обычно я не использую такой вариант эксперта, так как мне не хочется 
каждый раз при изменении DLL перезагружать среду. 

    Обработка исключительных ситуаций 

    Эксперт сам должен обрабатывать все исключительные ситуации. Для любого 
необработанного исключения следует вызвать метод RaiseException класса 
TIToolServices. Обычно в качестве параметра ему передается результат вызова 
функции ReleaseException из модуля Virtlntf, которая сбрасывает флаг 
исключительной ситуации, удаляет ее объект и возвращает сообщение об ошибке 
для исключительной ситуации. Вот пример обработчика. 

    procedure HandleException; begin 
    if Assigned(ToolServices) then 
    ToolServices.RaiseException(ReleaseException) end; 


    Глава 29. Работа с интерфейсом Open Tools API	689 

