Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Как динамически создать и выполнить код в Delphi?


Автор: Andrey_P 27.8.2005, 14:22
Суть в следующем... есть у меня компонент, имеет он 2 события - OnEnter и OnExit.
Пользователю я даю возможность в специально предоставленном Memo ввести некоторое количество строк кода на Delphi.
При этом значения переменных известны, код (к примеру, OnEnter) должен отработать и вернуть те же переменные, но уже измененные, с другими значениями. При следующем наступлении события берутся уже новые значения переменных и код работает еще раз...

Я динамически создал dpr-файл на Delphi, скомпилировал его программно с помощью dcc32,
но вот беда - готовый exe-шник мне надо запускать 1000 и более раз в рамках однократного выполнения моей большой программы. 1000-кратный запуск занимает 100 секунд, даже если в этом exe-шнике записан лишь один оператор (a:= 1). Это очень много, надо быстрее.

Какие еще есть варианты того, что пользователь ввел код, какой хочет на Delphi, а моя программа бы его выполнила? Есть подозрение, что можно с помощью dll, как думаете - даст это результат или нет. Как программно создать dll и вызывать ее функции?
Писать собственный компилятор или интерпретатор уже нет сил и времени... (может у кого-то есть готовый? - грамматика: Delphi).



Автор: p0s0l 27.8.2005, 14:32
Цитата(Andrey_P @ 27.8.2005, 14:22)
Есть подозрение, что можно с помощью dll, как думаете - даст это результат или нет. Как программно создать dll и вызывать ее функции?
Результат конечно же даст, и очень неплохой. Делается точно так же, как ты создавал exe, только вместо program - library и код заключи в экспортируемую функцию. А как вызывать функцию из DLL - это тыщу раз задавалось на форуме, поищи...

Цитата(Andrey_P @ 27.8.2005, 14:22)
Писать собственный компилятор или интерпретатор уже нет сил и времени... (может у кого-то есть готовый? - грамматика: Delphi).
Я немного использовал только Innerfuse Pascal Script... Но имхо, лучше через DLL делать...

Автор: Andrey_P 27.8.2005, 14:33
Работало долго почему? 100% из-за ShellExecute. Через dll заметно быстрее будет или нет?

Автор: p0s0l 27.8.2005, 14:39
Цитата(Andrey_P @ 27.8.2005, 14:33)
Работало долго почему? 100% из-за ShellExecute. Через dll заметно быстрее будет или нет?
Конечно из-за создания нового процесса.
Если будешь1 раз компилить DLL и 1000 раз вызывать функцию из неё, то никаких лишних телодвижений не надо будет делать. Быстрее этого сделать будет уже нельзя... Если будет тормозить - то только из-за тормозного кода, который выполняется (то что вводится в Memo)...
Как вариант - модернизировать exe (в смысле компилируемый код) так, чтобы он сам выполнял 1000 раз функцию, а не 1000 раз запускать exe smile

Автор: Andrey_P 27.8.2005, 14:43
Огромное человеческое спасибо за помощь.

Автор: Alex 27.8.2005, 14:54
Andrey_P, обратите внимание на http://www.fastreport.ru/ru/products/products.php?BID=5 может это то, что вы ищите.

Автор: Andrey_P 27.8.2005, 15:02
Alex не скачиваются у меня файлы оттуда почему-то.. smile
Добавлено @ 15:06
p0s0l, а как быть, если компонентов этих с событиями OnEnter и OnExit (см. 1-й пост) в модели несколько, соответственно нужно несколько dll с разными именами
(например, MyComponent1OnEnter.dll, MyComponent1OnExit.dll, MyComponent124OnEnter.dll, MyComponent124OnExit.dll и т.д.). Нужно же их прописывать в uses секции или необязательно?
Когда я вызывал exe-шник, я не задумывался, а просто писал в качестве параметра ShellExecute имя файла. С dll-кой я могу сделать что-то подобное?

Автор: Alex 27.8.2005, 15:23
Цитата(Andrey_P @ 27.8.2005, 16:02)
Alex не скачиваются у меня файлы оттуда почему-то..

Все нормально там скачивается http://www.fastreport.ru/pbc_download/fsd7.exe

Автор: Andrey_P 27.8.2005, 15:26
Точно, скачалось. У меня просто FlashGet глючил что-то. Спасибо за ссылки, ща посмотрю

Автор: Andrey_P 27.8.2005, 15:36
Alex, ты его случайно не покупал? Как он, нормально работает? Похоже, это действительно то, что мне нужно!

Автор: Alex 27.8.2005, 15:57
Отдельно его не покупал, но уже два года пользуюсь построителем отчетов FastReport, в который входит FS притензий к FS у меня небыло хотя иногда довольно сложные выражения расчетов на нем писались

Автор: Andrey_P 27.8.2005, 17:34
Сделал я по 2 библиотеки для каждого компонента, из своего кода (программно) их компилирую примерно так:

CreateProcess (nil, PChar ('dcc32.exe ' + FileName + '.dpr'), nil, nil, False, CREATE_NEW_PROCESS_GROUP, nil, PChar (Directory), Si, P);
Компилируется один раз за все время выполнения модели, в самом начале, так что
время компиляции для меня некритично.

Затем для каждого компонента (после явной загрузки библиотек в память) я нахожу адреса процедур CodeExecute и выполняю эти процедуры каждый раз при наступлении события OnEnter и OnExit.

Для 200 событий программа работает секунд 10 примерно, даже если в коде процедуры (в dll-ке) всего один оператор.
Так что ощутимого улучшения по сравнению с ShellExecute я не получил. Что делать?
Уже руки опускаются smile

Автор: Alex 27.8.2005, 18:40
Я конечно не спец в этом вопросе, но я бы начал копать все же в сторону FS. Так как он встроен и очень активно используется в FastReport и тормозов я там не замечал

Автор: Andrey_P 27.8.2005, 19:01
Его еще купить надо smile. Да и вообще, разобраться хочу с этим. Но FS все равно, скорее всего, впоследствии приобрету.

Автор: p0s0l 28.8.2005, 19:49
Цитата(Andrey_P @ 27.8.2005, 17:34)
Для 200 событий программа работает секунд 10 примерно, даже если в коде процедуры (в dll-ке) всего один оператор.
Этого быть не может.
100% ты что-то неправильно сделал.
Покажи текст dpr (длл-ки), который ты компилишь с помощью dcc32, и код загрузки DLL и вызова процедур из DLL...

Цитата(Andrey_P @ 27.8.2005, 15:02)
Нужно же их прописывать в uses секции или необязательно?
Кого прописывать в uses, не понял ?
Если у тебя 100 событий, значит, либо нужно сделать 100 экспортируемых процедур в 1 DLL, либо сделать 100 DLL (первый вариант определенно лучше). Загружаешь библиотеку с помощью LoadLibrary, получаешь адрес функций (GetProcAddress), потом когда надо их вызываешь. Тормозов при вызове не будет.

Автор: Andrey_P 1.9.2005, 14:44
pOsOl,


Вот текст dpr-ки, которая компилируется в dll.



Код

library OnExit1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, IniFiles;

var
  Ini: TIniFile;

  MasI: Array [0..99] of Integer;
  MasS: Array [0..99] of String;

procedure CodeExecute;
begin
  Ini:= TIniFile.Create ('C:\Program Files\Borland\Delphi7\Projects\Simulation\params.ini');

  MasI[0]:= Ini.ReadInteger ('Integer', 'Var1', 0);
  MasI[1]:= Ini.ReadInteger ('Integer', 'Var2', 0);
  MasI[2]:= Ini.ReadInteger ('Integer', 'Var3', 0);
  MasI[3]:= Ini.ReadInteger ('Integer', 'Const1', 0);


  MasS[0]:= Ini.ReadString('String', 'In1.DestPort', '');


  MasI[1]:= 34;
  MasI[0]:= MasI[1] div 2;
  MasI[2]:= 1;
  

  Ini.WriteInteger ('Integer', 'Var1', MasI[0]);
  Ini.WriteInteger ('Integer', 'Var2', MasI[1]);
  Ini.WriteInteger ('Integer', 'Var3', MasI[2]);
  Ini.WriteInteger ('Integer', 'Const1', MasI[3]);

  Ini.WriteString ('String', 'In1.DestPort', MasS[0]);


  Ini.Free;
end;

exports
  CodeExecute index 1;

begin
end.





[b]
Вот загрузка
[/b]


  FExitHandle:= LoadLibrary (PChar (Dir + 'OnExit' + IntToStr (FID) + '.dll'));
  if (FExitHandle >= 32)
  then begin
    FLoadedExit:= True;
    FExitProc:= GetProcAddress (FExitHandle, 'CodeExecute');
  end
  else begin
    if (MessageDlg ('Error', mtError, [mbOk], 0) = mrOK)
    then FLoadedExit:= False;
  end;


вызов такой:

if FLoadedExit
then FExitProc;

Я заказал fastScript кстати, так и не разобравшись с dll-ками smile. Если увидишь, где косяки, пиши, буду очень рад.
p0s0l

Автор: p0s0l 1.9.2005, 15:47
То что написано - то всё верно. Ошибка у тебя где-то зарыта не тут, где-то вкралась не заметно... Тебе её всё равно придётся найти, т.к. если ты просто заменишь вызов функции из DLL на выполнение скрипта, тормоза будут эти же самые, даже больше.

Для убедительности прикрепляю файлик, открывай Project1.dpr и запускай его. Там ты увидишь, что вызов приведенной тобой функции из DLL нисколько не тормозит (200 вызовов за 170 мс), в то время как запуск .exe 200 раз выполняется за 4-5 сек... Как у тебя 10 секунд получается - не знаю даже...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)