Link to home
Start Free TrialLog in
Avatar of girona
girona

asked on

Runtime functions/procedures

I need to call a function/procedure at runtime. What I know is the name of the function. I don't want to use a case or if condition to do that. I'm using Delphi 4.
Avatar of Brian Mulder
Brian Mulder
Flag of Netherlands image

Hi Girona,

Could you be a bit clearer? Can't figure out what you mean exactly.
You have a function you need to call at runtime, is it under certain conditions or has it to be called by an event?

:O)


Avatar of girona
girona

ASKER

I have an editbox and when I write the name of a function in it I want to execute it.
I guess you mean this:

var str : string = 'functionBlaBla';
begin
  call(str);
end;

Right?

That doesn't work this way, sorry...   :-(

But there are some workarounds. The best one is probably to use a dll, because then you can use GetProcAddress(dllHandle,functionStr).

Perhaps you should tell us more about for which purpose you need that. Then we'll find the best workaround for you...

Regards, Madshi.
Avatar of girona

ASKER

I have an editbox and when I write the name of a function in
Avatar of girona

ASKER

I can't use dll's because do many processes involving other forms and components and it would be a mess right now to move everything into a dll.
Ok, then you should do something like this:

type TGironasProc = procedure (int: integer);  // or other parameters...

var procArr : array [0..9] of record
                                name: string;
                                proc: TGironasProc;
                              end;

function CallProc(name: string; param: integer) : boolean;
begin
  result:=false;
  for i1:=0 to 9 do
    if name=procArr[i1].name then begin
      result:=true;
      procArr[i1].proc(param);
      exit;
    end;
end;

initialization
  procArr[0].name:='example1'; procArr[0].proc:=example1;
  procArr[1].name:=...
  ...
end.

Of course this method has some disadvantages:
(1) The parameters of the functions must be the same.
(2) You must fill the array.
(3) All the functions of the array are always linked in every program where you're using this unit. The linker can't remove them, because he doesn't know if he may do it...

Regards, Madshi.
Then I think I've to agree with Madshi, the way of typing in the name of the function doesn't work. Using a list(box) and a case statement are the solutions I would choose for. You have to do the conversion anyway, from the string in the box to the call of the function in the unit.

:O)
Girona...

Actually you can do it using RTTI info...MethodAddress will return the address of "Published" Methods.

Create a new Component...that will hold all your "Published" procedures and functions....see following example...

Hope this works for you

Rick

unit Unit1;

interface
(*Note ListBox1 has the items filled with the following strings:
  MyProcedure1, MyProcedure2, MyProcedure3*)
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type

  TMethodComponent = Class(Tcomponent)
    procedure MyProcedure1;
    procedure MyProcedure2;
    procedure MyProcedure3;
  end;

  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
  private
    { Private declarations }
    FMyMethod : TNotifyEvent;
    FMethodComponent: TMethodComponent;
  public
    { Public declarations }
    procedure MyMethod;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TMethodComponent.MyProcedure1;
begin
  ShowMessage('My Procedure 1');
end;

procedure TMethodComponent.MyProcedure2;
begin
  ShowMessage('My Procedure 2');
end;

procedure TMethodComponent.MyProcedure3;
begin
  ShowMessage('My Procedure 3');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMethodComponent := TMethodComponent.Create(Self);
end;

procedure TForm1.MyMethod;
begin
  if Assigned(FMyMethod) then
    FMyMethod(Self);
end;

procedure TForm1.ListBox1Click(Sender: TObject);
var
  Meth: TMethod;
begin
  Meth.Data := FMethodComponent;
  Meth.Code := FMethodComponent.MethodAddress(ListBox1.Items[ListBox1.ItemIndex]);
  FMyMethod := TNotifyEvent(Meth);
  MyMethod;
end;

end.



Girona...

You can pass function results as follows...If you need to also have procedures...I would suggest that you convert your procedures to functions and pass Null values or empty strings..

Rick

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type

  TMyFunction = function: variant of Object;

  TMethodComponent = Class(Tcomponent)
    function MyFunction1: variant;
    function MyFunction2: variant;
    function MyFunction3: variant;
  end;


  TForm1 = class(TForm)
    ListBox1: TListBox;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
  private
    { Private declarations }
    FMyMethod : TMyFunction;
    FMyVariant: Variant;
    FMethodComponent: TMethodComponent;
  public
    { Public declarations }
    procedure MyMethod;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function TMethodComponent.MyFunction1: variant;
begin
  ShowMessage('My Function 1');
  result := 100.99
end;

function TMethodComponent.MyFunction2: variant;
begin
  ShowMessage('My Function 2');
  result := 'My String';
end;

function TMethodComponent.MyFunction3: variant;
begin
  ShowMessage('My Function 3');
  result := 99
end;



procedure TForm1.FormCreate(Sender: TObject);
begin
  FMethodComponent := TMethodComponent.Create(Self);
end;

procedure TForm1.MyMethod;
begin
  if Assigned(FMyMethod) then
    FMyVariant := FMyMethod;
end;

procedure TForm1.ListBox1Click(Sender: TObject);
var
  Meth: TMethod;
begin
  Meth.Data := FMethodComponent;
  Meth.Code := FMethodComponent.MethodAddress(ListBox1.Items[ListBox1.ItemIndex]);
  FMyMethod := TMyFunction(Meth);
  MyMethod;
  Label1.Caption := FMyVariant;
end;

Avatar of simonet
You can use GetProcAddress using hInstance as the handle of the file where the functions are, rather than opening a DLL and getting a handle to it.

Alex
Hi Alex,

does that really work? I never tried it, but it sounds like a good idea...    :-)    Does that work for all functions?
However, different parameters are still a problem, but I think that doesn't matter that much.

Regards, Madshi.
Hi Alex,

does that really work? I never tried it, but it sounds like a good idea...    :-)    Does that work for all functions?
However, different parameters are still a problem, but I think that doesn't matter that much.

Regards, Madshi.
Avatar of girona

ASKER

I want an easier solution, instead of yours I could create a form or do the if solution, but I need a way to call it really easy.
Hi Alex, could you be more specific? please send an example, thanks.
Simplier?

Are you trying not to program?

Rick
Hello, Girona...

sorry for taking too long to answer. Gotta work all day long and get ready for Carnival!

You have to export the functions. Make sure all of them use the same number of parameters and parameter types and all in the same sequence. Do it even if you have to make some "dumb" parameters (you know what I mean, right?).

I cannot send you code for that right because there's nothing but Netscape and MS Office in the machie I am an right now.

When I get home you'll do some testing and post the results here.

Yours,

Alex
Happy partying! Alex :O)
Avatar of girona

ASKER

Thanks Alex,
    I'll be waiting any notice from you. I think till then I'll use an 'if' sentence.
ASKER CERTIFIED SOLUTION
Avatar of simonet
simonet
Flag of Brazil image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of girona

ASKER

That works fine, and has good comments. Thanks.