Delphi: Call a function whose name is stored in a string

后端 未结 10 1339
旧时难觅i
旧时难觅i 2020-12-08 05:30

Is it possible to call a function whose name is stored in a string in Delphi?

相关标签:
10条回答
  • 2020-12-08 05:32

    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.

    0 讨论(0)
  • 2020-12-08 05:35

    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;
    
    0 讨论(0)
  • 2020-12-08 05:36

    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;
    
    0 讨论(0)
  • 2020-12-08 05:42

    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;
    
    0 讨论(0)
  • 2020-12-08 05:50

    Please give more details on what are you trying to achieve.

    As far as I know:

    • It is not possible to call a random function like that.
    • For class and object functions (MyObject.Function) this can be done with RTTI, but it's a lot of work.
    • If you just need to call one particular type of functions (say, function(integer, integer): string), it's a lot easier.

    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.
    
    0 讨论(0)
  • 2020-12-08 05:50

    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

    0 讨论(0)
提交回复
热议问题