Рассылка закрыта
При закрытии подписчики были переданы в рассылку "О карьере и профессиональном развитии IT-специалистов" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Программирование для начинающих и не только
Информационный Канал Subscribe.Ru |
По материалам сайта www.gigabyte.iatp.org.ua
Усовершенствование FAR-a
Большинство пользователей ПК не представляют себе эффективной и оперативной работы на ПК без использования файловых менеджеров. И одним из популярнейших представителей этого класса программ является разработка Евгения Рошала под названием FAR. В этой статье пойдет речь о том, как расширить штатные возможности этой программы путем написания плагинов.
Постановка задачи
Для начала откроем директорию в которой установлен FAR и поищем то, что могло бы нам пригодится при разработке плагинов. Здесь мы обнаружим архив PlugDoc.rar и распакуем его в отдельный каталог. Теперь можно более детально разобраться с содержимым этого архива:
- Папка Examples - здесь находятся примеры уже имеющихся расширений (Временная панель, Архиватор, Просмотр сетевого окружения и т.п.)
- В папке Headers.c, как видно из названия хранятся заголовки и объявления функций необходимых для написания плагинов на С.
- Папка Headers.pas включает модули с теми же объявлениями для языка Pascal.
Из других полезных вещей, на которые Вам следует обратить внимание можно назвать файл справки plugins.hlp в котором достаточно подробно описаны все возможности по использованию функций FAR-а, к которым имеет доступ плагин.
И хотя для беглого ознакомления с техникой разработки плагинов для FAR-a нам будет достаточно заглянуть в исходник HelloWorld.pas расположенный в Examples\HelloWorld. Но его точно будет недостаточно для написания более менее полезных модулей.
И поэтому после HelloWorld мы разберемся с задачей написания просмотрщика ID3 тегов в MP3 файлах.
Здравствуй, Мир!
Как уже говорилось в каталоге Expamples\HelloWorld есть исходник, простенького плагина с которого мы и начнем изучение расширений для FAR-a.
Итак скомпилировав файл HelloWorld.pas (а это можно сделать написав в командной сроке "dcc32 helloworld.pas") мы получим файл библиотеки HelloWorld.dll. который вместе с дополнительными файлами (*.lng и *.hlf) поместить в отдельную папку каталога Plugins который размещается в директории FAR-a (к примеру C:\Program Files\Far\Plugins\Simple\). Далее, следуя рекомендациям из справки и дополнительных файлов из архива PlugDoc.rar, мы закрываем FAR и открываем его снова (дабы он обнаружил наш вновь созданный плагин). Хотя лично я просто открываю еще одну его копию. Теперь для просмотра результатов наших титанических усилий мы в заново открытом FAR-e жмем F11 и внимательно изучаем список подключенных модулей (рис.1). Наш плагин в этом списке выведен под названием "Здравствуй, Мир!". При нажатии на него появляется следующее предупреждение (рис.2).
Реализация этого модуля довольно проста. Если взглянуть на исходник HelloWorld.pas то там мы увидим:
Остановимся на каждом пункте более подробно.
Процедура SetStartupInfo.
procedure SetStartupInfo(var psi: TPluginStartupInfo); stdcall;
begin
Move(psi, FARAPI, SizeOf(FARAPI));
end;
Как уже говорилось она вызывается 1 раз при загрузке плагина и передает ему всю необходимую информацию в параметре psi. Параметр psi в свою очередь содержит список всех жизненно важных функций:
TPluginStartupInfo = packed record
StructSize: integer;
ModuleName: packed array[0..Pred(NM)] of char;
ModuleNumber: integer;
RootKey: PChar;
Menu: TFarApiMenu;
Dialog: TFarApiDialog;
Message: TFarApiMessage;
GetMsg: TFarApiGetMsg;
Control: TFarApiControl;
SaveScreen: TFarApiSaveScreen;
RestoreScreen: TFarApiRestoreScreen;
GetDirList: TFarApiGetDirList;
GetPluginDirList: TFarApiGetPluginDirList;
FreeDirList: TFarApiFreeDirList;
Viewer: TFarApiViewer;
Editor: TFarApiEditor;
CmpName: TFarApiCmpName;
CharTable: TFarApiCharTable;
Text: TFarApiText;
EditorControl: TFarApiEditorControl;
FSF: PFarStandardFunctions;
ShowHelp: TFarApiShowHelp;
AdvControl: TFarApiAdvControl;
InputBox: TFarApiInputBox;
DialogEx: TFarApiDialogEx;
SendDlgMessage: TFarApiSendDlgMessage;
DefDlgProc: TFarApiDefDlgProc;
Reserved: array[0..1] of DWORD;
end;
Большинство из которых отвечают за вызов тех или иных сервисных функций самого FAR-a. Так функции Menu, Message, Dialog, Control отвечают за вызов соответственно указателей на меню, вывод информационных сообщений, создание диалогов, получение информации об имеющихся в наличии панелях (Файловая, Информационная, Временная:).Другие же функции позволяют выводить текст, справку, открывать редактор и просмотрщик файлов. Кроме этих функций используется также и другой набор из т.н. Стандартных функций (FSF:PFarStandardFunctions) в который включены функции по работе со строками (сравнение, преобразование:), с буфером обмена, с таблицами перекодировок символов и т.п.
Процедура GetPluginInfo. В модуле HelloWorld реализована следующим образом:
procedure GetPluginInfo(var pi: TPluginInfo); stdcall;
begin
pi.StructSize:= SizeOf(pi);
pi.Flags:= PF_EDITOR;
PluginMenuStrings[0]:= GetMsg(MTitle);
pi.PluginMenuStrings:= @PluginMenuStrings;
pi.PluginMenuStringsNumber:= 1;
end;
Здесь происходит "заполнение анкеты" нашего плагина (т.е. структуры TPluginInfo) путем указания флага и названия нашего модуля. Кроме этих параметров можно также заполнить параметры:
- DiskMenuStrings: PPCharArr - указатель на список с названиями пунктов, которые будут добавлены в меню дисков (Alt+F1,Alt+F2).
- DiskMenuNumbers: PintArr - указатель на список с клавишами быстрого вызова пункта из меню дисков. Если этот параметр равен NULL, то FAR автоматически назначит горячие клавиши для каждого пункта.
- DiskMenuStringsNumber: integer - количество строк, которые будут добавляться в меню дисков.
- PluginConfigStrings: PPCharArr - список пунктов, которые будут добавлены в меню конфигурации подключаемых модулей.
- PluginConfigStringsNumber: integer - количество этих самых пунктов.
- CommandPrefix: Pchar - префикс команд, используется для перехвата стандартной реакции FAR на командную строку с различными префиксами типа http://www.site.com, ftp://ftp.site.com и т.д.
Функция OpenPlugin вызывается каждый раз при запуске плагина тем или иным образом. Здесь размещается код, который собственно и отвечает за отображение и деятельность нашего модуля:
function OpenPlugin(OpenFrom: integer; Item: integer): THandle; stdcall; var Msg: array[0..6] of PChar; begin Msg[0]:= GetMsg(MTitle); Msg[1]:= GetMsg(MMessage1); Msg[2]:= GetMsg(MMessage2); Msg[3]:= GetMsg(MMessage3); Msg[4]:= GetMsg(MMessage4); Msg[5]:= #01#00; // separator line Msg[6]:= GetMsg(MButton); FARAPI.Message(FARAPI.ModuleNumber, // PluginNumber FMSG_WARNING or FMSG_LEFTALIGN, // Flags 'Contents', // HelpTopic @Msg, // Items 7, // ItemsNumber 1); // ButtonsNumber result:= INVALID_HANDLE_VALUE; end;
Здесь в первых строках идет заполнение массива строк из которых будет состоять наше сообщение. Значения этих строк берутся из стандартного языкового файла (т.е. файла с расширением lng расположенного в той же директории, что и модуль и соответствующего используемому в FAR языку). Далее происходить вызов стандартной функции Message которая и отображает окно сообщения. Присвоение результату функции значения INVALID_HANDLE_VALUE необходимо для того, чтоб потом не возится с освобождение ресурсов, которые выделяет FAR под создание новой панели для нашего плагина. В других же случаях необходимо будет реализовать еще и процедуру ClosePlugin, которая теоретически принимает дескриптор созданный в функции OpenPlugin и освобождать соответствующие ему ресурсы.
ID3 Вьювер
Теперь уже можно перейти от баловства к созданию более интересного и практичного плагина.
Для приготовления этого блюда нам понадобится:
- IDE Delphi 3,4,5,6,7,8 - одна штука
- Компонент TvID3v1 из набор компонентов JCL/JVCL для чтения id3 тегов, или любой другой компонент с теми же функциями (можно и не компонент, а просто функцию или процедуру).
- Набор заголовочных файлов из директории Headers.pas
- Другие приправы по вкусу.
После сбора всех ингредиентов нам следует запустить Delphi и создать в нем новый проект-библиотеку. В эту библиотеку мы будет поочередно носить все функции рассмотренные в предыдущей главе.
Сперва мы сохраним указатель на сервисные функции FAR-a:
library Simple; uses windows, plugin, DialogDef in 'DialogDef.pas'; procedure SetStartupInfo(var psi: TPluginStartupInfo); stdcall; begin Move(psi, FARAPI, SizeOf(FARAPI)); end;
Далее добавляем название нашего модуля в список модулей вызываемых клавишей F11:
Теперь реализуем собственно отображение информации на экране:var PluginMenuStrings: array[0..0] of PChar; procedure GetPluginInfo(var pi: TPluginInfo); stdcall; begin pi.StructSize:= SizeOf(pi); pi.Flags:= PF_EDITOR; PluginMenuStrings[0]:= 'Simple Plugin'; pi.PluginMenuStrings:= @PluginMenuStrings; pi.PluginMenuStringsNumber:= 1; end;
function OpenPlugin(OpenFrom: integer; Item: integer): THandle; stdcall; begin CreateDialog; FARAPI.Dialog(FARAPI.ModuleNumber, -1, -1, 40, 20, nil, @DialogItems, DialogItemsCount); result:= INVALID_HANDLE_VALUE; end;
Здесь главную роль играет объявленная в модуле DialogDef функция, которая создает элементы диалога, который отображается посредством функции Dialog.
Сам вид уже готового диалога показан на рисунке 3. Как видим наш диалог состоит из 7-ми элементов:
- Панели с названием "Информация MP3"
- Статического текста с названием <Файл> (Аналог Tlabel в стандартных оконных приложениях)
- Редактируемого названия файла
- Трех строк текста, которые отображают соответственно название, исполнителя и альбом
- Кнопки закрыть
Все эти элементы создаются путем заполнения массива структур TfarDialogItem, который имеет довольно много различных параметров не востребованных при реализации данного плагина. И поэтому мы заполним только самые нужные из полей т.е. координаты, тип поля, название каждого элемента:
with DialogItems[0] do
begin
ItemType:=DI_DOUBLEBOX;
X1:=0;Y1:=0;
X2:=39;Y2:=19;
Focus:=0;
Flags:=DIF_BOXCOLOR;
S:=FARAPI.GetMsg(FARAPI.ModuleNumber,0);
with Data do
ZeroMemory(@Data,SizeOf(Data));
with Data do
Move(Pointer(S)^,Data,Length(S));
end;
Как видите, название панели (как и других элементов) мы берем из языкового файла, что существенно облегчит нам трансляцию нашего плагина на другие языки.
Создание других элементов также не является более трудной задачей, только при назначении их координат следует помнить о том, что они задаются в клиентской системе координат нашей панели.
Теперь возьмемся за заполнение названий наших компонентов. Так для заполнения элемента, который отображает название текущего файла мы используем функцию FARAPI.Control в таком контексте:
FARAPI.Control(INVALID_HANDLE_VALUE,FCTL_GETPANELINFO,@P);
Такой код позволяет нам в переменной P получить указатель на текущую панель, которой в нашем случае является файловая панель. В чем мы еще раз убеждаемся сделав в коде проверку:
if @P<>nil then if (P.PanelType=PTYPE_FILEPANEL) and (P.ItemsNumber>0) then begin S:=P.PanelItems^[P.CurrentItem].FindData.cFilename; with Data do ZeroMemory(@Data,SizeOf(Data)); with Data do Move(Pointer(S)^,Data,Min(512,Length(S))); end;
Далее, как видно из кода, мы запрашиваем информацию о текущей позиции курсора и считываем информацию о текущем файле. Эти данные (точнее имя текущего файла) мы и передаем в параметр Data нашего элемента, а также используем его для извлечения ID3 тега посредством компонента TvID3v1:
id3:=TJvId3v1.Create(nil); try id3.FileName:=S; with DialogItems[3] do begin ItemType:=DI_TEXT; X1:=2;Y1:=5;X2:=35; if id3.TagPresent then S:=FARAPI.GetMsg(FARAPI.ModuleNumber,2)+': '+id3.SongName else S:='No mp3 tag found'; with Data do ZeroMemory(@Data,SizeOf(Data)); Move(Pointer(S)^,Data,35); S:=''; end;
Если же данный файл не содержит тегов или это вообще не тот файл, то мы просто записываем на место данных строку "No mp3 tag found".
В конце модуля мы на всякий случай очищаем массив DialogItems:
begin ZeroMemory(@DialogItems,SizeOf(DialogItems)); end.
Замечания и предложения
Инсталляция этого плагина реализуется тем же образом, что HelloWorld. Но перед этим следует дополнительно создать языковый файл с указанием названий всех элементов нашего диалога. К счастью программистов и простых пользователей языковый файл FAR это простой текстовый файл, в котором в отдельных строках размещаются названия отдельных элементов. Первая строка заполняется служебным идентификатором <.Language>, в который записывается название используемого языка. В нашем случае мы создадим языковый файл следующего
содержания:
.Langugage = Russian,Russian (Русский) "Информация MP3" "Файл" "Название" "Исполнитель" "Альбом" "Закрыть"
Кроме того тут есть возможность использования комментариев, а также символов табуляции, конца строки и т.п. Которые записываются в стиле C/C++.
Естественно нет предела совершенству и эта маленькая библиотека еще очень далека от него. Ее возможностей хватит пожалуй только то чтоб быстро упорядочить ваши mp3 файлы не выходя из любимого файлового менеджера. К возможным последующим усовершенствованиям этого плагина можно отнести добавление дополнительных ID3 полей и возможность их редактирования, а также более быстрый вызов этой надстройки посредством скажем горячих клавиш, или вывод информации на информационную панель (Ctrl+L); но это уже темя для отдельной статьи.
Листинг - Simple.dpr
{$APPTYPE CONSOLE} {$MINENUMSIZE 4} library Simple; uses windows, plugin, DialogDEf in 'DialogDEf.pas'; procedure SetStartupInfo(var psi: TPluginStartupInfo); stdcall; begin Move(psi, FARAPI, SizeOf(FARAPI)); end; var PluginMenuStrings: array[0..0] of PChar; procedure GetPluginInfo(var pi: TPluginInfo); stdcall; begin pi.StructSize:= SizeOf(pi); pi.Flags:= PF_EDITOR; PluginMenuStrings[0]:= 'Simple Plugin'; pi.PluginMenuStrings:= @PluginMenuStrings; pi.PluginMenuStringsNumber:= 1; end; function OpenPlugin(OpenFrom: integer; Item: integer): THandle; stdcall; begin CreateDialog; FARAPI.Dialog(FARAPI.ModuleNumber,-1,-1,40,20,nil,@DialogItems,DialogItemsCount); result:= INVALID_HANDLE_VALUE; end; exports SetStartupInfo,GetPluginInfo,OpenPlugin; end.
Листинг - DialogDef.pas
unit DialogDef; interface uses plugin,windows; Const DialogItemsCount = 7; var FARAPI: TPluginStartupInfo; var DialogItems: array[0..DialogItemsCount-1] of TFarDialogItem; procedure CreateDialog; implementation uses jvid3v1,DebugUnit; function Min(A,B:Integer):Integer; begin Result:=A; if A>B then Result:=B; end; procedure CreateDialog; var S:String;Mem:Pointer; P:TPanelInfo; id3:TJvId3v1; begin with DialogItems[0] do begin ItemType:=DI_DOUBLEBOX; X1:=0;Y1:=0; X2:=39;Y2:=19; Focus:=0; Flags:=DIF_BOXCOLOR; S:=FARAPI.GetMsg(FARAPI.ModuleNumber,0); with Data do ZeroMemory(@Data,SizeOf(Data)); with Data do Move(Pointer(S)^,Data,Length(S)); end; with DialogItems[1] do begin ItemType:=DI_TEXT; X1:=2;Y1:=2; S:=FARAPI.GetMsg(FARAPI.ModuleNumber,1); X2:=Length(S); with Data do ZeroMemory(@Data,SizeOf(Data)); with Data do Move(Pointer(S)^,Data,Length(S)); end; with DialogItems[2] do begin ItemType:=DI_EDIT; X1:=2;Y1:=3; X2:=37; Focus:=1; DefaultButton:=True; GetMem(Mem,2048); try FARAPI.Control(INVALID_HANDLE_VALUE,FCTL_GETPANELINFO,@P); finally if @P<>nil then if (P.PanelType=PTYPE_FILEPANEL) and (P.ItemsNumber>0) then begin S:=P.PanelItems^[P.CurrentItem].FindData.cFilename; with Data do ZeroMemory(@Data,SizeOf(Data)); with Data do Move(Pointer(S)^,Data,Min(512,Length(S))); end; FreeMem(Mem,2048); end; end; id3:=TJvId3v1.Create(nil); try id3.FileName:=S; with DialogItems[3] do begin ItemType:=DI_TEXT; X1:=2;Y1:=5;X2:=35; if id3.TagPresent then S:=FARAPI.GetMsg(FARAPI.ModuleNumber,2)+': '+id3.SongName else S:='No mp3 tag found'; with Data do ZeroMemory(@Data,SizeOf(Data)); Move(Pointer(S)^,Data,35); S:=''; end; with DialogItems[4] do begin ItemType:=DI_TEXT; X1:=2;Y1:=6;X2:=35; if id3.TagPresent then S:=FARAPI.GetMsg(FARAPI.ModuleNumber,3)+': '+id3.Artist else S:='No mp3 tag found'; with Data do ZeroMemory(@Data,SizeOf(Data)); Move(Pointer(S)^,Data,35); S:=''; end; with DialogItems[5] do begin ItemType:=DI_TEXT; X1:=2;Y1:=7;X2:=35; if id3.TagPresent then S:=FARAPI.GetMsg(FARAPI.ModuleNumber,4)+': '+id3.Album else S:='No mp3 tag found'; with Data do ZeroMemory(@Data,SizeOf(Data)); Move(Pointer(S)^,Data,35); S:=''; end; finally id3.free; end; with DialogItems[6] do begin ItemType:=DI_BUTTON; S:=FARAPI.GetMsg(FARAPI.ModuleNumber,5); X1:=15; X2:=Length(S); Y1:=18; Y2:=1; Focus:=1; DefaultButton:=True; with Data do ZeroMemory(@Data,SizeOf(Data)); with Data do Move(Pointer(S)^,Data,Length(S)); S:=''; end; end; begin ZeroMemory(@DialogItems,SizeOf(DialogItems)); end.
Листинг - Simple.lng
.Langugage = Russian,Russian (Русский) "Информация MP3" "Файл" "Название" "Исполнитель" "Альбом" "Закрыть"
Subscribe.Ru
Поддержка подписчиков Другие рассылки этой тематики Другие рассылки этого автора |
Подписан адрес:
Код этой рассылки: comp.soft.prog.programmershelp |
Отписаться
Вспомнить пароль |
В избранное | ||