» Близкие контакты третьего вида с Visual Foxpro (или как написать свой провайдер для FoxPro) Borland Delphi. Базы данных. . Блог программистов


Блог программистов






200919 Мар

Близкие контакты третьего вида с Visual Foxpro (или как написать свой провайдер для FoxPro)

Многие наверное как и я в свое время задавались интересным вопросом — «А вот как бы задействовать всю силу применяемой в моем проекте СУБД? Не только стандартные SQL запросы, а и скрытые возможности.» Тогда ведь можно будет получать результат найэффективнешими методам.

Верно.

Не так уж и сложно разработать свой провайдер, по крайней мере  для FoxPro, думаю что эта СУБД еще имеет широкое применение.

А вот как — описано в статье.

ПРЕДИСЛОВНАЯ ПОБОЛТАЛОВКА

Ну что ж. Вот и я дожил до того что пишу собственную статью. Возможно потому что хочется поделиться наработками, или из альтруистических побуждений или потому что не нашел подобных статей (может искал плохо) но истинный смысл в том что многие знают и умеют интегрировать свои программы с СУБД обычными путями, непрекословными истинами, прописанными кем-то из аналогичных побуждений, а ведь на них свет клином не сошелся. Очень жаль что не всегда то что кажется хорошим хорошее на самом деле.

Вот и я столкнулся с весьма нетривиальной ситуацией, в которой нужно было разработать программу, хранящую и обрабатывающую данные в какой-нить удобной локальной СУБД. Первое что пришло в голову (а тут читатель скажет — «А что же еще могло прийти») — это воспользоваться стандартным набором ADO, благо Delphi его любит и уважает. А что неплохо, методы стандартные, хорошо задокументированные, от BDE, которого изучают в любых универах, отличающиеся мало.

Да никто и не спорит — ADO удобно, можно подключить любую СУБД, проинсталированную на локальном компьютере или подключить провайдера удаленно.

Что ж подумал я, можно попробовать. Но только я начал набирать прожку и базы, как оказалось, что все это до меня уже набрано хитрыми программистами. Базы, коды-рассчетчики… Все уже есть, но не в Delphi а в достаточно популярной раньше СУБД FoxPro.

УРА!!! Сказал я и попытался почитать «километровый» код программы… Ух… малоприятно скажу я читать чужие писульки, особенно если они плохо закоментированны…

Основное я для себя уяснил — функции, которые мне нужны были оформлялись в виде подпрограмм с четкими названиями, соответствуя своим задачам, их аргументы были предельно понятны, и вызывать их не составляло труда. Но это можно было сделать только в FoxPro… так что пришлось мне выбирать — либо писать свои, и терять время, либо как-то заставит самого Фокса выполнять этот код.

Я выбрал второе, поскольку я ленивый мне никак не хотелось перелопачивать заново всю методику, и вот что из этого вышло…

НЕМНОГО ТЕОРИИ

Для начала пару слов об ADO. Говоря о компоненте Delphi, ADO позволяет обрабатывать команды классического SQL плюс SQL навороты,

которые поддерживает провайдер в командах. Для этого можно использовать либо ADOQuery, как привычный компонент, либо ADOCOmmand, позволяющий выполнять как отдельные команды так и целый файл с таковыми.

Однако и в этой ложке меда оказалась своя бочка дегтя. И дело здесь вот в чем. Многим извесно что FoxPro это одна из первых СУБД, являющаяся на то время весьма революционной. Помимо применения сверхбыстрых (на то время) технологий обработки данных RushMore,  она еще и имела мощный язык обработки данных, который кстати не очень сильно изменился и по сей день. Его возможности позволяли достаточно гибко работать с данными, написав при этом кода меньше чем скажем в Клиппере. К тому же Ядро FoxPro было сделано оверлеями — прадедушками нынешней DLL, что само по себе давало неплохую экономию ресурсов и прирост скорости даже на слабеньких машинах 8086.

С переходом под крылышко Микрософтовцев эта СУБД приобрела полноценный модуль провайдера, и стала доступна как COM система.

Что ж гарно — сказали программисты и… слегка обломались — провайдер настолько урезали, что он уже перестал понимать стандартные команды этой СУБД, кроме тех что попадают под определение классического SQL (SELECT,DELETE,UPDATE,CREATE,ALTER…).

Но оригинальный язык Фокса был помимо этих команд наполнен массой функций, которые увы оказались запертыми в недрах ядра системы, и могли выполняться лишь программами, написанными в самом FoxPro.

Практически все функции (а их в FoxPro множество) больше не смогли работать в ADO. А ведь было бы удобно тем кто знает эту СУБД как пять своих пальцев использовать ВСЕ ее возможности в своих программах, написанных на других языках.

Тут я сделаю отступление, ибо может кто-то скажет — «Да ради бога, пусть пишут прям на Фоксе», Э нет — тут много минусов. Дело все в том что прибрав к рукам СУБД Микрософт не особо позаботился о ее прогрессе, оно и понятно — купил конкурента чтоб задавить своими продуктами. Посему наверное именно такими мыслями руководствовались тамошние разработчики, подарив Фоксу весьма корявую среду разработки, совершенно неудобную в пользовании и кучу багов в ядре. Да и обьектная модель ее желает лучшего. Уж лучше бы не трогали вообще, от оконных разработок на Фоксе одни проблемы. Взять хотя бы распространенный баг с закрытием окна — не всегда срабатывает крестик закрытия окна а иногда просто вешает программу. И смех и грех. Выходили из этой проблемы банально — ставили свою кнопку «Закрыть». Где ж тут удобства?

Впрочем ладно, разговор не об этом… Вернемся к нашим баранам. Поскольку ADO мы отбрасываем возникает вопрос — а что вместо него?

Резонно, что ж есть возможность решения этой проблемы. Дело в том, что FoxPro было сделано во времена, когда большой славой пользовались интерпретаторы — программы пошагово выполняющие код написанный программистом. Каждая строчка программы переводилась в код и сразу же исполнялась, потом интерпретатор повторял этот фокус на следующей строчке. Эта возможность в FoxPro осталась до сих пор, правда FoxPro не совсем интерпретатор, а скоре псевдокомпилятор, а ядро на самом деле работает со скомпилированными байт-кодами (На P-CODE Visual Basiс похоже)
но это нам совершенно не важно, главное, что все-таки источником является именно «писанина» программиста аз есьм, даже одна строчка команды посланной интерпретатору будет рассматриваться им как целостная программа, и будет успешно переведена в псевдокод и выполнена.

Причем строчка эта может быть представленная такими типами как String,Pchar.

Уже неплохо, но как послать интерпретатору строку-команду? Вот мы и подошли к самому главному. Дело в том что одна из магических возможностей FoxPro есть инструкция, которая выполняет переданную ей строку-параметр как команду.

На Фоксе это называется макроподстановкой и звучит так:

StrCommand="Select * from table"&StrCommand

Где StrCommand:String говоря языком Вирта, строка содержащая команду.

При этом интерпретатору все равно, что там будет находиться, если это правильная команда он ее выполнит.

С этим можно провести примерно такую аналогию:

StrCommand:='Select * from Table';
     Query.SQL.Add(StrCommand);
     Query.ExecSQL

«Ну и что такого?»-скажут многие. Чем круче макроподстановка? А те, кто знают FoxPro на пять, ответят — макроподстановка позволяет не только выполнять ВСЕ команды но и еще возвращать результат, если в качестве команды поступило выражение.

т.е.

StrCommand="2+6*Sin(20)"
     STORE &d TO StrCommand
     return StrCommand && - вернет вычисленное выражение 

а вот аналогия в SQL

S:='select 2+6*Sin(20)';
     Query.SQL.Add(s);
     Query.open
     :=Query.Fields[0].AsFloat

К тому же как по мне неэтично создавать отдельный курсор (курсор в FoxPro это набор данных полученный каким либо образом) ради одного значения. Можно конечно и так, но что будет, если в выражении повстречаются команды, которые заложены в ядре, но неизвестные провайдеру?

Например команду замены в поле, где содержится имя файла расширения с Tif на Jpg в таблице А1

REPLACE a1.fullname WITH  LEFT(a1.fullname,AT(".TIF",a1.fullname))+".JPG" all

Query подавится ею.

Впрочем для любителей классики есть менее эффективная команда UPDATE

Но если поздороваться так с интерпретатором тет-а-тет то команда будет выполнена немедля.

А значит таким образом можно легко взять старые программы и построчно (или прям целиком программу из файла, указав его имя в SET PROCEDURE TO после чего, пустив на выполнение процедуру командой DO или, если это функция просто выполнить ее) скармливать их интерпретатору напрямую обходя, или вообще не имея установленного провайдера.

Вот эту идею я взял за основу.

Первоначально пришлось почитать литературу по FoxPro. Смысл связи оказался простым — Дело все в том что на FoxPro можно писать компоненты, которые потом с легкостью применять в Delphi, поскольку Микросовтовцы все таки пошли навстречу и снабдили СУБД возможностью компиляции (на сей раз полноценной) кода в COM Server в виде DLL. Опа! Собственный интерфейс — вот то, что нужно. И там же можно навертеть все чего пожелаем.

СТРАТЕГИЯ

Ну что ж — приступим к разработке стратегии. Нам нужно написать на FoxPro DLL с функциями, которые бы общались напрямую с интерпретатором, передавая ему строку команды, и возвращали бы результат выполнения этой команды. Для передачи строки без возвращения результата напишем процедуру, ибо может понадобиться выполнять такие команды как, скажем Use или Replace (подобной вышеописанной, из тех что не возвращают результат или генерируют курсоры). Для получения результата выполненного выражения системой напишем функцию. Потом все это скомпилируем как DLL с COM сервером и зарегистрировав на машине (Командой Regsvr32 <Имя DLL> в консоли) вставим в Delphi через команду меню Project->Import type library, где выберем эту DLL. После чего можно будет распоряжаться этими функциями, как методами компонента.

ТАКТИКА

Начнем с написания библиотеки. Для этого понадобится Visual Foxpro. Я делал на 8-й версии но и более ранние тоже подходят.

Запустим Foxpro и в меню File выберем пункт New. В появившемся окошке File Type выберем Project, и нажмем на кнопку New File.

Нас попросят написать имя Проекта. Имя допустим будет TFoxPro. Ок.

Появилось окошко с описанием проекта – это шаблон компонента.

Создадим новый класс, для чего, став на ветку, Class Library кликнем по кнопке New. Появившееся окошко попросит нас написать имя класса и его наследование.

Допустим имя будет TFoxPro (Назвать можно как угодно). Наследовать мы будем пользовательский «чистый» класс, поскольку нам визуальные и контейнерные классы никак не нужны, поэтому в поле Based On выбираем Custom. В поле Store In укажем путь куда сохранится класс. Жмем Ок.

Теперь добавим в него методы. Тем кто знает как в Delphi писать ActiveX будет не сложно понять следующие действия, поскольку они похожи. В главном меню Class выбираем New Method. Чтоб меню Class появилось нужно стать в окно Class Designer созданного класса. В появившемся окошке создаем ему метод. Допустим назовем его MyProc с видимостью Public. Жмем Add. И так же добавим еще один метод MyFunc.

Если на экране есть окно Properties то можно в нем увидеть как появляются новые методы. Если окошка этого нет, нужно его открыть либо с тулбара, либо контекстным меню по формочке класса (который у нас называется tFoxPro в окне Class Designer) выбрать элемент Properties. Добавив методы, впишем в них код. Сначала в MyProc, для чего в окне Properties найдем строчку с его названием и откроем ее, кликнув дважды. Открывшееся окно редактора всем своим видом пригласит нас писать программку, чем и займемся.

Текст программы будет весьма простой, подобный тому, что приведен выше. Добавим только команду описания параметра, ибо нам же нужно в метод передавать команду в виде строки, вот и опишем его как строка:

LPARAMETERS lcrun as String  &&- Это указание что метод примет  параметр типа String
&&- Далее на всякий случай, дабы  задобрить интерпретатор обрезаем
&&ведущие и закрывающие пробелы. Можно и без этой команды обойтись,
&&но лишняя предусмотрительность не  помеха.


 lcrun=ALLTRIM(lcrun)  

&lcrun &&– И наконец Выполним команду из строки
Здесь && означают комментарии (как // в Делфи или Си), так что можно копипастить эти строки полностью

«Всего то?» — удивится кто-то. А что тут такого? Все проще простого.Принимаемая строка будет расценена как команда.

Займемся теперь функцией, «Те же яйца только в профиль». Так же открываем ее код и вписываем вышеприведенный пример, не забыв прикрутить параметр, в который будет передана команда:

LPARAMETERS lcrun as String 
STORE &lcrun TO mret         &&-    Сохраняем результат выполнения команды-выражения
&&в переменную
RETURN mret            &&-   которую  потом возвращаем.

Das Ist Alles – сохраним проект. Теперь дело за малым – скомпилировать библиотеку,  но сначала укажем что методы класса являются OLE видимыми, для чего в меню Class откроем окно Class Info. Здесь поставим галочку на OLE Public. Если этого не сделать компилятор не впишет класс в сервер заругавшись строчкой «Cannot build a DLL without OLE Public Class». Непонятно зачем создатели сделали эту опцию, могли бы сделать так чтоб компилятор сам проверял необходимость публикации класса если компилируется COM Server.

После перепрыгиваем в окно Project Manager, и кликаем по кнопке Build. В появившемся окне Выберем Multi-threaded COM server DLL. И выставим все птички в Options, чтоб перекомпилирование прошло над всеми фалами (Recomile All Files), если всплывут ошибки мы их захотим увидеть (Display errors) и пусть перестраивает ID компонента.

Жмем ОК.

Итак – Как говорил Слепой Пью – «Дело сделано». Заглянув в папку с проектом можно увидеть что в нем лежит библиотека tfoxpro.dll (учитывая что я все файлы называл одинаковым именем и сложил в одну папку). Компилятор так же любезно предоставил нам библиотеку типов tfoxpro.tlb. Остальные файлы принадлежат самому проекту FoxPro. Например VCX  это тот самый класс, VCT – описание его методов (можно посмотреть в блокноте), тот код что мы написали. Остальные файлы версия проекта и описания проектов.

ИНТЕГРАЦИЯ

Вот и наступил второй этап. Свой пров мы написали, теперь его нужно зарегистрировать (я рекомендую сделать это программой RegSVR32, расположенной как правило в папке C:\WINDOWS\system32\. Потом нужно импортировать библиотеку типов « превратив» ее в компонент Delphi, компонент которой кинуть на форму и пользоваться им как родным.

Приступим:

Поместив DLL в какой-нибудь каталог, где она будет жить, зарегим ее (можно даже в System32 но я не рекомендую загаживать его). Если вы используете Total Commander или подобные проводники то вам проще – стали на тот файл и в командной строке набрали RegSvr32 TFoxPro.DLL. Энтер и Ок. На самом деле это можно сделать и в Delphi при импорте, но я лично сталкивался с непонятными для меня глюками, когда импорт в «компонент» проходит успешно, а регистрации его в реестре нет. Поэтому «чтоб уж наверняка не было ни одного упырька» зарегим дедовским способом. Если библиотека правильно сделана, сообщение об успешной регистрации вылезет на экран. Кстати если у вас нет regsvr32, нечего отчаиваться, его аналог можно написать и на Delphi. Эта возможность имеется благодаря наличию в такого рода библиотеках функций DLLRegisterServer – которая регистрирует в реестре Windows свои классы. И Соответственно DLLUnregisterServe – которая отменяет регистрацию. Эти функции regsvr32 и вызывает. Для регистрации или ее отмены достаточно просто вызвать эти функции из библы.

В Delphi это выгляди так:

function DllRegisterServer: HResult; stdcall;  external 'TFoxPro.dll';
     ...
     begin
     DllRegisterServer;
     end;
     ...

Соответственно предполагается что эта прожка-регистратор лежит возле DLL.

Итак, в реестр библиотеку с классом мы поселили, теперь получим компонентик. Для этого  откроем окно Import Type Library из меню Project. По крайней мере так делается в Delphi 6. Если у вас другая версия то нужно найти соответствующую возможность импорта библиотеки.

Предположим нашли. Найдем в списке нашу библиотеку и проинсталлируем ее класс в какой-нибудь package. Выберите сами ему название.

После всего если вы правильно проинсталлировали пакет, компонент должен появиться на соответствующей вкладке палитры.

Теперь можно им пользоваться.

ПРИМЕНЕНИЕ

Для начала создадим таблицу в FoxPro. Да не важно что там будет. Предположим список файлов в строковом поле. Назовем таблицу «а1». Допустим в ней будет поле Filename где прописаны пути к файлам.

Кинем на форму наш компонент. Дадим ему имя FoxPro. Теперь мы хотим отобразить содержимое этого поля в таблице. Долой тяжелые и неповоротливые DB компоненты – скажу я и растяну на форме обычный StringGrid. Его и будем наполнять данными.

Программно нам нужно проделать следующее

  1. Открыть базу. Для этого в FoxPro используется команда USE. Если нужно получить не все записи можно следующей командой послать что-то типа SELECT * FROM… WHERE <Условие отбора> ибо FoxPro понимает классический SQL
  2. Получить количество записей функцией RECNO()
  3. В цикле вписать записи в таблицу 😉

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

var m,k:integer;
   begin
   // Откроем таблицу командой USE 
   foxpro.MyProc('USE  "'+ExtractFilePath(paramstr(0))+'a1.dbf"');
   // Получим количество записей и выставим количество строк в таблице
    StringGrid1.RowCount:=foxpro.MyFunc('reccount()')+1;
    StringGrid1.ColCount:=2;
   // Для красоты можно масштабировать размер колонки
по максимально  длинной строке
    m:=0;
   // Пока не конец текущей таблицы
    while foxpro.MyFunc('.NOT.  EOF()') do begin
      // в соответствующую ячейку записываем из текущей записи поле FILENAME
      // обрезая ненужные ведущие и замыкающие пробелы функцией ALLTRIM
        StringGrid1.Cells[1,k]:=foxpro.MyFunc('alltrim(filename)');
      // Получаем ее порядковый номер
        StringGrid1.Cells[0,k]:=foxpro.MyFunc('recno()');
      // Переходим на следующую запись
        foxpro.MyProc('SKIP');
      // Маштабируем колонку авторазмером
        if  StringGrid1.Canvas.TextWidth(StringGrid1.Cells[1,k])>m then
          m:=StringGrid1.Canvas.TextWidth(StringGrid1.Cells[1,k]);
        StringGrid1.ColWidths[1]:=m;
    end;
 end;

А в событии OnClose формы закроем все курсоры командой foxpro.MyProc(‘close all’), дабы не оставлять мусора;

Обратите внимание я легко воспользовался стандартным набором функций FoxPro и выражниями. Аналог Alltrim конечно и в Delphi есть, но почему бы не напрячь саму СУБД?.

Не очень много кода. Кто-то скажет «А зачем все это если можно применить DBGrid не написав «ни одной» строчки кода?». Можно, но работать с DB компонентами в Delphi – сущий мазохизм.

К тому же в плюс приведу еще один аргумент:

Растяните на чистой форме DBGrid и ADOQuery. Скомпилируйте и посмотрите размер файла. У меня он равен 758 с копейками килобайт. А теперь скомпильте проект с TFoxPro. 453 с копейками. И это при том что я в первом проекте ни строчки кода не написал. Убедил? Если нет попробуйте написать тяжеловесный проект с кучей DB компонентов и посмотрите что разница будет в десятки раз (Когда-то я писал весьма сильный проект по обработке конструкторской документации. Не PDM но все же. Применил соответственно BDE. Когда база разрослась, а лежала она на расшаренной папке, программа заметно начала тормозить. Даже оптимизация толком не дала прироста скорости. После того как я перешел на FoxPro таким способом программа опять стала летать. Я практически не замечал тормозов. Плюс ко всему эту программу поставили на убитый горем старый компьютер, который еще «Ленина видел живым». Вот тогда оператор-расчетчик с удивлением сказал что новая версия доставляет удовольствие от работы, и спросил что я сделал.).

Ну да ладно. Продолжим. Теперь наша задача – редактирование.

Редактировать будем прямо в Гриде, благо тот позволяет это сделать выставив в свойстве Options флажок goEditing и к нему goAlwaysShowEditor чтоб не выходить из режима редактирования.

Писать сам код можно в событии OnSetEditText. Тактика будет такова:

  1. Становимся на запись, индекс которой передается в OnSetEditText. Здесь очень важно чтоб количество строк в гриде совпадало с количеством строк в курсоре базы
  2. Заменяем значение в поле

Все это делается примерно так:

procedure  TForm1.StringGrid1SetEditText(Sender: TObject; ACol,
       ARow: Integer; const Value: String);
     begin
     // Становимся на  запись
       foxpro.MyProc('GO '+inttostr(aRow));
     // Заменяем значение ее поля новым значением  
     foxpro.MyProc('REPLACE  fullname WITH "'+value+'"');
     end;

Как видим тоже ничего мудреного. И это притом что DBGrid в паре с Query так просто не позволит провернуть такую операцию – обязательно повыбрыкиватся чем-нибудь вроде «DataSet not in edit or insert mode». FoxPro такого не скажет, потому как запись то открыта по умолчанию и для чтения и для записи, если конечно на этой записи не стоит какой-нибудь другой клиент при многопользовательской работе. Тогда запись блокируется. Но речь сейчас не о многопользовательском сеансе. Плюс к этому (опять я похвалю FoxPro) это правило действует в любых курсорах даже тех которые были получены классическими SELECT * FROM… или подобными. TQuery без шаманских танцев с бубном над ним подавится такими запросами. Как ни странно это касается очень многих СУБД с которыми взаимодействует этот компонент, не потому что это плохие СУБД а потому что сам компонент не рассчитан на такую гибкость. Впрочем, и с ним можно решить такую задачу, но чего это будет стоить… Мигрени точно.

А теперь представим, что проект ведет человек хорошо знающий FoxPro, но хуже знающий Delphi. Естественно ему выгоднее будет основную работу с БД написать командами FoxPro, а на Delphi сделать только интерфейс и выполнение таких команд. Есть два выхода из этой ситуации:

1. Написать или взять командные файлы FoxPro (.PRG)  и просто в Delphi считывая построчно скармливать их интерпретатору.

2. FoxPro имеет возможность выполнять целые файлы, которые содержат код, самостоятельно их читая.

Первый способ неплох, но только в случае линейной программы, без процедур и функций, так как если бы оператор ручками вводил команды в консоль FoxPro. К тому же механизм выражений теряет свою силу. Поэтому мы возьмемся за второй способ – пакетное выполнение программ и модулей.

Для этого в FoxPro предусмотрена команда SET PROCEDURE TO которая действует примерно по аналогии с Include некоторых языков, ну или, скажем, отдаленно напоминает uses в паскале.

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

Выглядит это так:

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

Вот как он будет выглядеть:

FUNCTION ReplExtension
      LPARAMETERS s as String
  && Найдем  расширение и заменим его на новое во всех записях
&& Тут же можно написать тучу кода чего-то рассчитывающего
replace filename WITH  LEFT(filename,RAT(".",filename)-1)+"."+s all
     && Вернем True 
      RETURN .t.
     ENDFUNC
FUNCTION FindName
      LPARAMETERS s as String
     && Поищем введенную  подстроку в записях и станем на нее если нашли
     LOCATE for AT(s,filename)<>0
     &&  вернем номер найденной строки 
     RETURN RECNO()
     ENDFUNC 

Теперь откроем этот файлик в FoxPro и скомпилируем его. (Увы, последние версии FoxPro обязательно нуждаются в псевдокомпиляции – это минус. Впрочем нужно отдать должное разработчикам — они оставили команду COMPILE. Так что можно не компилировать ничего, но перед вызовом SET PROCEDURE TO выполнить COMPILE.) Полученный в результате компиляции FXP псевдокод ложем в папку с программой.

В Delphi пишем следующий код:

В OnCreate инициализируем модуль:

{Ладно уж. Пусть скомпилирует сам. чего программисту то напрягаться}
foxpro.aproc('COMPILE "'+ExtractFilePath(paramstr(0))+'File1.prg"');
{Скомпилиный модуль инициализируем}
foxpro.MyProc('set  procedure to "'+ExtractFilePath(paramstr(0))+'file1"');

Предполагается что он называется File1.prg. На самом же деле выполняться будет лежащий рядом FXP.

Теперь поместим на форму две кнопки. Одна будет скармливать функцию ReplExtension другая FindName.

Код первой кнопки:

var s:string;
     begin
       s:=InputBox('Введите новое разширение','','');
       foxpro.MyFunc('ReplExtension("'+s+'")');
       FillGrid(StringGrid1);
     end;

Код второй:

procedure  TForm1.Button1Click(Sender: TObject);
     var s:string;
     begin
     s:=InputBox('Введите что искать','','');
       StringGrid1.Row:=foxpro.MyFunc('findname("'+s+'")');
       caption:=IntToStr(StringGrid1.Row);
       StringGrid1.SetFocus;
     end;

В первом случае возвращаемое значение мы не обрабатываем, во втором случае присваиваем его свойству Грида, отвечающему за позиционирование курсора в Гриде.

Опять таки ничего сложного, зато весь управляющий код мы спихнули на совесть FoxPro. А ведь это только пример… Мне довелось повидать расчеты в бухгалтерии в частности калькулирование себестоимости, где модули такие насчитывали около 100 строк. Там очень много деталей учитывалось. Удобная схема – не нужно менять EXE-шник.  По аналогии с этим есть компонент TStoredProc. Но его возможностей гораздо меньше.

ПОСЛЕВКУСИЕ

Вот так вот, други мои. Против лома нет приема если нет другого лома. Я не настаиваю н том что FoxPro круче всех и вся, но умелое применение возможностей этой СУБД извне позволит достичь весьма эффектных результатов достаточно простыми путями. Кто-то скажет: «Да ну… Это нужно ставить на каждую машину FoxPro полностью…». Не обязательно. Например достаточно поставить ее на сервер, а в Delphi в свойстве компонента RemoteMachineName указать сервер. Плюс на сервере правильно настроить достут к нему удаленно. Это обычная практика для хорошего администратора. Или есть еще возможность (если ее уже не отменили разработчики) просто проинсталлировать одно ядро (это около 10 DLL’ок) на машину. Подобное мне показывал один фан этой СУБД, и ниче — заработало нормально. Опять таки повторюсь — данная статья описывает однопользовательскую систему. В многопользовательских нужно покрупнее пошаманить, например запретить клиенту вызовы компиляции, чтоб не повесить сервер.

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

С  уважением. Stilet.

Комментарии

  1. 18 сентября, 2009 | 20:00

    поражаюсь вашим потрясающим постам… еще одно большое спс

  2. Dag
    3 ноября, 2009 | 22:05

    Безусловно интересная статья. Поэтому было бы неплохо уточнить некоторые детали.

    [i]STORE &d TO StrCommand
    return StrCommand && — вернет вычисленное выражение [/i]

    Не сработает.Правильно будет

    STORE &StrCommand TO d
    return d && — вернет вычисленное выражение

    [i] Получить количество записей функцией RECNO()[/i]
    Правильно — RECCOUNT()

    [i]Впрочем нужно отдать должное разработчикам — они оставили команду COMPILE. Так что можно не компилировать ничего, но перед вызовом SET PROCEDURE TO выполнить COMPILE.) Полученный в результате компиляции FXP псевдокод ложем в папку с программой.[/i]

    Абсолютно свободно заменяется функцией EXECSCRIPT( ). И никаких плясок с бубном.

    [i]Это нужно ставить на каждую машину FoxPro полностью…”. Не обязательно. [/i]
    Именно, необязательно и даже противозаконно. А использовать файлы RunTime абсолютно законно и очень просто. Бросьте 2-3 файла dll в system32 и вуаля — ваш компонент будет работоспособен.