Is it possible to call a function whose name is stored in a string in Delphi?
You didn't specify your Delphi version, However if you have Delphi 2010(+) you can do it using the enhanced RTTI, I'm not expert on them, but I tried this sample for you:
TProcClass = class
public
procedure SayHi;
function GetSum(X,Y:Integer): Integer;
end;
uses
Rtti;
{ TProcClass }
procedure TProcClass.SayHi;
begin
ShowMessage('Hi');
end;
function TProcClass.GetSum(X, Y: Integer): Integer;
begin
ShowMessage(IntToStr(X + Y));
end;
procedure ExecMethod(MethodName:string; const Args: array of TValue);
var
R : TRttiContext;
T : TRttiType;
M : TRttiMethod;
begin
T := R.GetType(TProcClass);
for M in t.GetMethods do
if (m.Parent = t) and (m.Name = MethodName)then
M.Invoke(TProcClass.Create,Args)
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ExecMethod('SayHi',[]);
ExecMethod('GetSum',[10,20]);
end;
The good things, if you have procedure or function with parameters it will work without more work.
Put each function in an Action. Then you can find the Action by name and Execute it
function ExecuteActionByName(const S: String);
var
I: Integer;
begin
for I := 0 to MainForm.ComponentCount-1 do
if (MainForm.Components[I] is TAction)
and SameText(TAction(MainForm.Components[I]).Name,S) then
begin
TAction(MainForm.Components[I]).Execute;
Break;
end;
end;
With Delphi 2010 you can uses JSON and SuperObject to invoke method with parametters.
http://code.google.com/p/superobject/source/browse/#svn/trunk
If you need, there is also an xml parser to transform xml to json.
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure TestMethod(const value: string);
end;
var
Form1: TForm1;
implementation
uses superobject;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
SOInvoke(Self, 'TestMethod', SO('{value: "hello"}'));
end;
procedure TForm1.TestMethod(const value: string);
begin
Caption := value;
end;
The following simple solution using exports and GetProcAddress also works for old Delphi versions:
type
TMyProc = procedure(const value: Integer);
procedure Test(const value: Integer);
exports Test;
implementation
procedure Test(const value: string);
begin
ShowMessage('It works! ' + value);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
p: TMyProc;
begin
p := GetProcAddress(HInstance, 'Test');
if Assigned(p) then P('Yes');
end;
Please give more details on what are you trying to achieve.
As far as I know:
For the last one, declare a function type, then get a function pointer and cast it like this:
type
TMyFuncType = function(a: integer; b: integer): string of object;
TMyClass = class
published
function Func1(a: integer; b: integer): string;
function Func2(a: integer; b: integer): string;
function Func3(a: integer; b: integer): string;
public
function Call(MethodName: string; a, b: integer): string;
end;
function TMyClass.Call(MethodName: string; a, b: integer): string;
var m: TMethod;
begin
m.Code := Self.MethodAddress(MethodName); //find method code
m.Data := pointer(Self); //store pointer to object instance
Result := TMyFuncType(m)(a, b);
end;
{...}
//use it like this
var MyClass: TMyClass;
begin
MyClass := TMyClass.Create;
MyClass.Call('Func1', 3, 5);
MyClass.Call('Func2', 6, 4);
MyClass.Destroy;
end.
OK, I'm very late to the party, but you can definitely call routines by name with this code (There are some limitations thought)
type
TExec = procedure of Object;
// rest of section...
procedure TMainForm.ExecuteMethod(MethodName : String);
var
Exec : TExec;
Routine : TMethod;
begin
Routine.Data := Pointer(Form1);
Routine.Code := Form1.MethodAddress(MethodName);
if Not Assigned(Routine.Code) then
Exit;
Exec := TExec(Routine);
Exec;
end;
Just in case someone needs this for Delphi 7 / 2010