如何把一个字符串能当作函数或过程执行?(222分)

  • 主题发起人 主题发起人 7030
  • 开始时间 开始时间
7

7030

Unregistered / Unconfirmed
GUEST, unregistred user!
由于要执行的函数名是动态的,所以要类似实现execmethod(methodname)来运行函数,methodname是我已定义的N个函数名?
 
type<br> &nbsp;ta = class(TPersistent)<br> &nbsp;published<br> &nbsp; &nbsp;class function fa:string;<br> &nbsp; &nbsp;class function fb(const i : Integer):string;<br> &nbsp;end;<br> &nbsp;TtestMethod = function (AObj : TObject) : string;<br> &nbsp;TtestMethod2 = function (AObj : TObject; const i:Integer) : string;<br><br><br>............<br><br>{ ta }<br><br>class function ta.fa: string;<br>begin<br> &nbsp;Result := 'fa.fa';<br>end;<br><br>class function ta.fb(const i: Integer): string;<br>begin<br> &nbsp;Result &nbsp;:= &nbsp;IntToStr(i);<br>end;<br><br>procedure TMainForm.Button2Click(Sender: TObject);<br>var<br> &nbsp;a : TClass;<br> &nbsp;f : TtestMethod;<br> &nbsp;f2 : TtestMethod2;<br>begin<br> &nbsp;a := &nbsp;GetClass('Ta');<br> &nbsp;if Assigned(a) then<br> &nbsp;begin<br> &nbsp; &nbsp;f := &nbsp;TtestMethod(a.MethodAddress('fa'));<br> &nbsp; &nbsp;if Assigned(f) then<br> &nbsp; &nbsp; &nbsp;ShowMessage(f(nil));<br> &nbsp; &nbsp;f2 := &nbsp;TtestMethod2(a.MethodAddress('fb'));<br> &nbsp; &nbsp;if Assigned(f2) then<br> &nbsp; &nbsp; &nbsp;ShowMessage(f2(nil, 111));<br> &nbsp;end;<br>end;<br><br>initialization<br> &nbsp;RegisterClass(ta);<br>finalization<br> &nbsp;UnregisterClass(ta);<br><br>end.<br><br>注:上面的方法只能调用类方法,或普通方法中没有引用类成员的方法<br>如果引用了类成员,ShowMessage(f(nil))这里的nil必须改为类实例,否则会出不可预料的结果.<br>如果引用了类实例,则与楼主的要求不符.<br>PS:方法只能是published的,也就是具有RTTI信息的才能用MethodAddress取得地址
 
楼上的方法是不错,但对于动态参数处理不是很灵活,已经从以前的贴子找到方法了,明后天结贴<br>function ExecuteRoutine(AObj: TObject; AName: string; Params: array of const): DWord;<br>const<br> &nbsp;RecSize = SizeOf(TVarRec); // 循环处理参数列表时递增的字节数<br>var<br> &nbsp;PFunc: Pointer;<br> &nbsp;ParCount: DWord;<br>begin<br>//对于字符作为参数,不知为什么一定要传长度大于2的,否则会出错<br> &nbsp;if not Assigned(AObj) then<br> &nbsp; &nbsp;raise Exception.Create ('你确定传进来的是一个对象?');<br> &nbsp;PFunc := AObj.MethodAddress(AName); // 获取方法地址<br> &nbsp;if not Assigned(PFunc) then<br> &nbsp; &nbsp;raise Exception.CreateFmt('找不到 %s 的 Method: %s', [AObj.ClassName, AName]);<br> &nbsp;ParCount := High(Params) + 1; // 获取参数个数<br> &nbsp;asm<br> &nbsp; &nbsp;PUSH &nbsp; &nbsp; &nbsp; &nbsp;ESI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 保存 ESI,我们待会儿要用到它<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; ESI, Params &nbsp; &nbsp; &nbsp; &nbsp; // ESI 指向参数表首址<br> &nbsp; &nbsp;CMP &nbsp; &nbsp; &nbsp; &nbsp; ParCount, 1 &nbsp; &nbsp; &nbsp; &nbsp; // 判断参数个数<br> &nbsp; &nbsp;JB &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@NoParam<br> &nbsp; &nbsp;JE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@OneParam<br> &nbsp; &nbsp;CMP &nbsp; &nbsp; &nbsp; &nbsp; ParCount, 2<br> &nbsp; &nbsp;JE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@TwoParams<br> &nbsp;@ManyParams: // 超过两个参数<br> &nbsp; &nbsp;CLD &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 清空方向标志<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; ECX, ParCount<br> &nbsp; &nbsp;SUB &nbsp; &nbsp; &nbsp; &nbsp; ECX, 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 循环 ParCount - 2 次<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// EDX 依次指向每个参数的首址,每次递增 8 Bytes<br> &nbsp; &nbsp;ADD &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// 跳过前两个参数<br> &nbsp;@ParamLoop:<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; EAX, [ESI][EDX] &nbsp; &nbsp; // 用基址变址寻址方式取得一个参数<br> &nbsp; &nbsp;PUSH &nbsp; &nbsp; &nbsp; &nbsp;EAX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 参数进栈<br> &nbsp; &nbsp;ADD &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// EDX 指向下一个参数首址<br> &nbsp; &nbsp;LOOP &nbsp; &nbsp; &nbsp; &nbsp;@ParamLoop<br> &nbsp;@TwoParams: // 两个参数<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; ECX, [ESI] + RecSize<br> &nbsp;@OneParam: // 一个参数<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; EDX, [ESI]<br> &nbsp;@NoParam:<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; EAX, AObj &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 传入实例地址(即,隐藏参数 Self)<br> &nbsp; &nbsp;CALL &nbsp; &nbsp; &nbsp; &nbsp;PFunc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 调用方法<br> &nbsp; &nbsp;MOV &nbsp; &nbsp; &nbsp; &nbsp; Result, EAX &nbsp; &nbsp; &nbsp; &nbsp; // 返回值放入 Result<br> &nbsp; &nbsp;POP &nbsp; &nbsp; &nbsp; &nbsp; ESI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 记得还原<br> &nbsp;end;<br>end;
 
我来晚了,还有另外的方法,函数保存在数据库里面
 
问题: 我周围的人都搞不懂,在DELPHI中怎样运行字符中所包含的命令 ( 积分: 100 ) &nbsp;<br>分类: 非技术问题 &nbsp;<br> <br>来自: s9461128946112894611, 时间: 2003-08-27 9:40:00, ID: 2136479 &nbsp;<br>在DELPHI中怎样运行字符中所包含的命令 <br>有如下代码 <br>procedure ....... <br>var <br>s:string; <br>begin <br>s:=&quot;form1.button1.enabled:=true&quot;; <br>怎样通过运行S来达到给form1.button1.enabled赋值true <br>及运行 <br>aaaa &nbsp;s <br>就可以达到 <br>给form1.button1.enabled赋值true <br>请问有aaaa这个命令吗? <br><br> <br>来自: 来如风, 时间: 2003-08-27 9:46:00, ID: 2136495 &nbsp;<br>没有 <br> <br>来自: ycxy, 时间: 2003-08-27 9:47:00, ID: 2136496 &nbsp;<br>这是不可能的 <br>你只能通过程序来判断执行 <br>如 <br>case i of <br>1:form1.button1.enabled:=true; <br>2:.. <br>end; <br> <br>来自: HunterTeam, 时间: 2003-08-27 9:48:00, ID: 2136501 &nbsp;<br>类似于foxpro中的&命令是吧?Delphi中没有这个命令,只能对字符串进行解析判断后才能 <br>作具体的处理。 <br> <br>来自: linglingx, 时间: 2003-08-27 9:51:00, ID: 2136513 &nbsp;<br>你自己做一个像Delphi的编译器也就可以执行了,呵呵~ <br> <br>来自: superFans, 时间: 2003-08-27 9:58:00, ID: 2136541 &nbsp;<br>Dream Script 控件即可 可以从51Delphi 下载,有Demo <br> <br>来自: s9461128946112894611, 时间: 2003-08-28 11:54:00, ID: 2139460 &nbsp;<br>怎么没有一个人回答我的问题,太难了吗? <br> <br>来自: Passion, 时间: 2003-08-28 12:01:00, ID: 2139480 &nbsp;<br>上面不是有这么多人回答了吗? <br> <br>来自: lichaogang, 时间: 2003-08-28 12:05:00, ID: 2139488 &nbsp;<br>delphi 中没有宏,你不可以这样做。 <br> <br>来自: 孤灯夜影, 时间: 2003-08-28 12:15:00, ID: 2139512 &nbsp;<br>只能对字符串进行判断 才能执行什么 <br>如果直接执行字符串 不太可能 除非你自己定义一个过程 也是先判断 再执行 <br> <br>来自: ty123, 时间: 2003-08-28 13:38:00, ID: 2139707 &nbsp;<br>同意ycxy和孤灯夜影 <br> <br>来自: yue_shan, 时间: 2003-08-28 13:53:00, ID: 2139752 &nbsp;<br>哥们,若有你这样的功能,哪写程序岂不是很舒服,从文本文件中读要执行的指令,程序编译后,这个文本文件用户都可能写,那太爽了吧,而你这个程序也相当于一个编译器了 <br> <br>来自: lz999, 时间: 2003-08-28 14:29:00, ID: 2139869 &nbsp;<br>我今天也遇见类似的问题,需要在运行时可改变计算公式,基本包括 + - * / 等综合运算。 我想应该有办法的,因为我看到过有一个小软件能实现,如果有办法的话,能否也告知我一下? <br> <br>来自: yangh888, 时间: 2003-08-28 14:43:00, ID: 2139932 &nbsp;<br>关注~! <br>up~! <br><br> <br>来自: clever_boy_2000, 时间: 2003-08-28 17:12:00, ID: 2140418 &nbsp;<br>不可能,字符串没没经过编译 <br> <br>来自: 牛车, 时间: 2003-08-28 17:32:00, ID: 2140489 &nbsp;<br>问题很具有挑战性。如果你的要执行的命令是少量的话应该是有办法的;如果是大量的话,嘿嘿,自己搞个编译器。 <br> <br>来自: Pau1, 时间: 2003-08-28 17:38:00, ID: 2140520 &nbsp;<br>如何根据字符串(如:‘ABC’)判断是否存在同名的Procedure或function(如:Procedure ABC或function ABC),如存在,请教如何通过字符串(如:'ABC')调用该Procedure或function? <br>这在FOXPRO下很容易实现,但在DELPHI下却很棘手,不是吗? <br><br>如: <br>type <br>TProcedureType=Procedure(Num:Integer); <br>... <br>procedure ABC(Num:Integer); <br>procedure ProcessOtherProcedure(OtherProcedure:TProcedureType); <br><br>var <br>String1:string='ABC'; <br><br>implementation <br><br>Procedure ABC(Num:Integer); <br>begin <br>// <br>// <br>end; <br><br>Procedure ProcessOtherProcedure(OtherProcedure:TProcedureType) <br>begin <br>OtherProcedure(); <br>end; <br><br>请教如果不知道Procedure ABC是否存在,如何根据字符串String1的值判断是它否存在,如存在,请教如何利用字符串String1调用ProcessOtherProcedure? <br><br>----------------------------------------------------------------------- <br><br>第一篇:按名字调用方法高级解决方案。 <br>声明:本文乃 beta 原创,如要转载请保持文章完整。 <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 按名字调用方法高级解决方案 --- by beta <br>按名字调用方法似乎一直以来都是大家比较关注的技术,在论坛上有一个经典的答复: <br> type <br> &nbsp; TProcedure = procedure(Test: string) of object; <br><br> procedure ExecuteRoutine(Obj: TObject; Name, Param: string); <br> var <br> &nbsp; PMethod: TMethod; <br> &nbsp; AProcedure: TProcedure; <br> begin <br> &nbsp; PMethod.Data := Pointer(Obj); <br> &nbsp; PMethod.Code := Obj.MethodAddress(Name); <br> &nbsp; if Assigned(PMethod.Code) then <br> &nbsp; begin <br> &nbsp; &nbsp; AProcedure := TProcedure(PMethod); <br> &nbsp; &nbsp; AProcedure(Param); <br> &nbsp; end; <br> end; <br><br> 使用:待调用方法声明为某个类的 published 方法,Obj 为拥有待调用方法的类的 <br>实例,Name 和 Param 分别为待调用方法的名字和参数。 <br><br>但是这个办法有一个很大的局限性:一旦 TProcedure 声明定了下来,待调用方法的参 <br>数表也就一定了。要是我定义了多个待调用方法,且参数个数、类型、返回值均不同, <br>则这个办法也就无能为力了。另:用 GetProcAddress 代替 MethodAddress 也可以实 <br>现类似的效果,不过我们今天讨论的是调用类的“方法”,而它所返回的不是“方法”, <br>因为 GetProcAddress 仅能取得应用程序的输出(exports)了的过程或函数,这些过 <br>程或函数不属于任何类,也就称不上“方法”。当然,效果类似,但是局限也类似 :-( <br><br>那么要是参数的个数、类型均可变就无法解决了吗?(要是这样就不会有本文了)通过 <br>研究,我发现了一种行之有效的办法:Format 函数(注意,不是 DOS 命令,呵呵)相 <br>信大家都不陌生吧,传入它的参数的个数和类型不都是可变的吗?只要声明如下: <br><br> procedure AProc(Param: array of const); <br><br>即可这样调用: <br><br> AProc([123, 'X', True, 'hello'...]); <br><br>有朋友可能要说了,那不就简单了,这样不就可以了: <br><br> type <br> &nbsp; TProcedure = procedure(Params: array of const) of object; <br><br> procedure ExecuteRoutine(Obj: TObject; Name: string; Params: array of const); <br> var <br> &nbsp; ... <br> begin <br> &nbsp; ... <br> &nbsp; &nbsp; AProcedure(Params); <br> &nbsp; ... <br> end; <br><br>别急,问题才刚刚出现呢,你运行试一试?出问题了吧。(为方便起见,暂时称我们的 <br>ExecuteRoutine 函数,为控制函数;待调用方法简称为待调方法)这个形参表的声明 <br>办法的确适合我们的控制函数,但是不适合待调方法。为什么?因为待调方法的形参表 <br>的确不是这样(array of const)的啊。当然了,你说你把所有待调方法的形参表都改 <br>成这个样子不就可以了?且不说你需要改动多少东西(包括待调函数的参数表和内部实 <br>现,关键是内部实现部分),就看看你改了过后的待调方法的形参表,全部都成了一个 <br>模样。说不定到时候你自己都不知道到底应该传什么参数进去了。因此,我们应该尽量 <br>保持待调方法的形参表。 <br><br>现在问题转化为了在控制函数中已知待调方法的地址及其参数列表(存放在一个 <br>TVarRec 的数组中),如何在调用它的时候将参数传进去。这需要几点预备知识: <br><br> 1. 首先我们来看看传进来的这个参数表:Params。它的类型被 Delphi 称作可变开 <br>放数组(Variant open array),等价于 array of TVarRec,也就是说 Params 是一 <br>个成员为 TVarRec 的数组。换句话说,在参数被传进 Params 的时候,各种类型都被 <br>Delphi 自动转化为了 TVarRec(参见帮助中的 Variant open array parameters 一 <br>节)。看一下 TVarRec 的定义可知,它实际储存的数据域为 4 Bytes,超过 4 Bytes <br>的只存指针,需要注意的是 TVarRec 的大小是 8 Bytes(经研究发现前 4 Bytes 存放 <br>数据,第 5 Byte 为类型)。 <br><br> 2. 调用函数时的参数传递的一般情况(未使用 stdcall 的情况)。对于一般的函数 <br>或过程,前三个参数分别放在 EAX、EDX、ECX,后面如果还有更多参数的话,就在堆栈 <br>里面;对于类的方法,EAX 固定用于存放类实例的地址,EDX、ECX 分别存放前两个参 <br>数,其余参数进栈。在堆栈中每个元素占用 4 Bytes,而前面说了,TVarRec 中储存的 <br>数据也是 4 Bytes,刚好一个参数在堆栈里面占一个位子,处理方便。另外,结果返回 <br>到 EAX 中。 <br><br> 3. 对于调用类的方法,其实有一个默认的隐藏参数 Self 作为第一个参数传入,放 <br>入 EAX 寄存器。因此我们看到的第一参数其实是第二个,因此我们处理的时候要注意。 <br><br> 4. 用 ObjectPascal 语法调用方法,Delphi 会自动帮我们处理参数的传递问题,而 <br>在汇编里面调用任何函数之前都需要先手动设置各参数。 <br><br>因此,我决定用内嵌汇编的办法来解决参数传递问题:如果是一个参数,放入 EDX;若 <br>为两个参数,分别放入 EDX,ECX;对多于两个参数的情况,用 参数个数 - 2 个循环依 <br>次将后续参数进栈。然后将拥有待调方法的实例地址传入 EAX,就可以 CALL 了。 <br><br> function ExecuteRoutine(AObj: TObject; AName: string; <br> &nbsp; Params: array of const): DWord; <br> const <br> &nbsp; RecSize = SizeOf(TVarRec); // 循环处理参数列表时递增的字节数 <br> var <br> &nbsp; PFunc: Pointer; <br> &nbsp; ParCount: DWord; <br> begin <br> &nbsp; if not Assigned(AObj) then <br> &nbsp; &nbsp; raise Exception.Create ('你确定传进来的是一个对象?'); <br> &nbsp; PFunc := AObj.MethodAddress(AName); // 获取方法地址 <br> &nbsp; if not Assigned(PFunc) then <br> &nbsp; &nbsp; raise Exception.CreateFmt('找不到 %s 的 Method: %s', [AObj.ClassName, <br> &nbsp; &nbsp; &nbsp; AName]); <br> &nbsp; &nbsp; &nbsp;<br> &nbsp; ParCount := High(Params) + 1; // 获取参数个数 <br><br> &nbsp; asm <br> &nbsp; &nbsp; PUSH &nbsp; &nbsp; &nbsp; &nbsp;ESI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 保存 ESI,我们待会儿要用到它 <br><br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; ESI, Params &nbsp; &nbsp; &nbsp; &nbsp; // ESI 指向参数表首址 <br> &nbsp; &nbsp; CMP &nbsp; &nbsp; &nbsp; &nbsp; ParCount, 1 &nbsp; &nbsp; &nbsp; &nbsp; // 判断参数个数 <br> &nbsp; &nbsp; JB &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@NoParam <br> &nbsp; &nbsp; JE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@OneParam <br> &nbsp; &nbsp; CMP &nbsp; &nbsp; &nbsp; &nbsp; ParCount, 2 <br> &nbsp; &nbsp; JE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@TwoParams <br><br> &nbsp; @ManyParams: // 超过两个参数 <br> &nbsp; &nbsp; CLD &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 清空方向标志 <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; ECX, ParCount <br> &nbsp; &nbsp; SUB &nbsp; &nbsp; &nbsp; &nbsp; ECX, 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 循环 ParCount - 2 次 <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// EDX 依次指向每个参数的首址,每次递增 8 Bytes <br> &nbsp; &nbsp; ADD &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// 跳过前两个参数 <br> &nbsp; @ParamLoop: <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; EAX, [ESI][EDX] &nbsp; &nbsp; // 用基址变址寻址方式取得一个参数 <br> &nbsp; &nbsp; PUSH &nbsp; &nbsp; &nbsp; &nbsp;EAX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 参数进栈 <br> &nbsp; &nbsp; ADD &nbsp; &nbsp; &nbsp; &nbsp; EDX, RecSize &nbsp; &nbsp; &nbsp; &nbsp;// EDX 指向下一个参数首址 <br> &nbsp; &nbsp; LOOP &nbsp; &nbsp; &nbsp; &nbsp;@ParamLoop <br><br> &nbsp; @TwoParams: // 两个参数 <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; ECX, [ESI] + RecSize <br><br> &nbsp; @OneParam: // 一个参数 <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; EDX, [ESI] <br><br> &nbsp; @NoParam: <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; EAX, AObj &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 传入实例地址(即,隐藏参数 Self) <br> &nbsp; &nbsp; CALL &nbsp; &nbsp; &nbsp; &nbsp;PFunc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 调用方法 <br> &nbsp; &nbsp; MOV &nbsp; &nbsp; &nbsp; &nbsp; Result, EAX &nbsp; &nbsp; &nbsp; &nbsp; // 返回值放入 Result <br><br> &nbsp; &nbsp; POP &nbsp; &nbsp; &nbsp; &nbsp; ESI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 记得还原 <br> &nbsp; end; <br> end; <br><br>前面已经说过了,任何类型都可以塞进 4 Bytes,因此将返回值定义为 DWord,你可以 <br>根据自己的需要进行类型转换。这个办法最大限度地保护了待调方法,但也不是完全不 <br>用修改,只有一个地方需要作出适当调整:与 DLL 中的函数返回值一样(别告诉我引用 <br>ShareMem,那不属于本文讨论的范畴),如果要返回一个长 string,请改为 PChar, <br>并注意申请必要的空间。 <br><br>以下是一个使用的例子(再次提醒一下,待调方法必须是某个类的 published 方法): <br><br> TForm1 = class(TForm) <br> &nbsp; Button1: TButton; <br> &nbsp; procedure Button1Click(Sender: TObject); <br> private <br> &nbsp; { Private declarations } <br> public <br> &nbsp; { Public declarations } <br> published // 几个待调方法 <br> &nbsp; function TowInt(I, J: Integer): Integer; <br> &nbsp; function ThreeInt(I, J, K: Integer): Integer; <br> &nbsp; function FiveInt(X1, X2, X3, X4, X5: Integer): Integer; <br> &nbsp; function ThreeChar(I, J, K: Char): PChar; <br> &nbsp; function TwoStr(X, Y: string): PChar; <br> &nbsp; function IntNBool(I: Integer; B: Boolean): Boolean; <br> end; <br><br> ... <br><br> function ExecuteRoutine(AObj: TObject; AName: string; <br> &nbsp; Params: array of const): DWord; <br> ... <br><br> function TForm1.TowInt(I, J: Integer): Integer; <br> begin <br> &nbsp; ShowMessage(Format('%d + %d', [I, J])); <br> &nbsp; Result := I + J; <br> end; <br><br> function TForm1.ThreeInt(I, J, K: Integer): Integer; <br> begin <br> &nbsp; ShowMessage(Format('%d + %d + %d', [I, J, K])); <br> &nbsp; Result := I + J + K; <br> end; <br><br> function TForm1.FiveInt(X1, X2, X3, X4, X5: Integer): Integer; <br> begin <br> &nbsp; ShowMessage(Format('%d + %d + %d + %d + %d', [X1, X2, X3, X4, X5])); <br> &nbsp; Result := X1 + X2 + X3 + X4 + X5; <br> end; <br><br> function TForm1.ThreeChar(I, J, K: Char): PChar; <br> var <br> &nbsp; Res: string; <br> begin <br> &nbsp; ShowMessage(Format('%s + %s + %s', [I, J, K])); <br> &nbsp; Res := I + J + K; <br> &nbsp; Result := AllocMem(Length(Res) + 1); <br> &nbsp; StrPCopy(Result, Res); <br> end; <br><br> function TForm1.TwoStr(X, Y: string): PChar; <br> var <br> &nbsp; Res: string; <br> begin <br> &nbsp; ShowMessage(Format('%s + %s', [X, Y])); <br> &nbsp; Res := X + Y; <br> &nbsp; Result := AllocMem(Length(Res) + 1); <br> &nbsp; StrPCopy(Result, Res); <br> end; <br><br> function TForm1.IntNBool(I: Integer; B: Boolean): Boolean; <br> begin <br> &nbsp; if B then <br> &nbsp; &nbsp; ShowMessage(IntToStr(I) + ' and True') <br> &nbsp; else <br> &nbsp; &nbsp; ShowMessage(IntToStr(I) + ' and False'); <br><br> &nbsp; Result := B; <br> end; <br><br> procedure TForm1.Button1Click(Sender: TObject); <br> var <br> &nbsp; i: Integer; <br> &nbsp; b: Boolean; <br> &nbsp; s: string; <br> begin <br> &nbsp; i := ExecuteRoutine(Self, 'ThreeInt', [10, 23, 17]); <br> &nbsp; ShowMessage('Result: ' + IntToStr(i)); <br><br> &nbsp; i := ExecuteRoutine(Self, 'FiveInt', [1, 2, 3, 4, 5]); <br> &nbsp; ShowMessage('Result: ' + IntToStr(i)); <br><br> &nbsp; b := Boolean(ExecuteRoutine(Self, 'IntNBool', [10, False])); <br> &nbsp; if b then <br> &nbsp; &nbsp; ShowMessage('Result: True') <br> &nbsp; else <br> &nbsp; &nbsp; ShowMessage('Result: False'); <br><br> &nbsp; s := PChar(ExecuteRoutine(Self, 'ThreeChar', ['a', 'b', 'c'])); <br> &nbsp; ShowMessage('Result: ' + s); <br><br> &nbsp; s := PChar(ExecuteRoutine(Self, 'TwoStr', ['hello', ' world'])); <br> &nbsp; ShowMessage('Result: ' + s); <br> end; <br><br> ... <br><br>我之所以称该办法为高级解决方案,而非终极,因为它仍然有一个问题没有解决:变参 <br>问题。但是这不是什么大问题,因为完全可以用函数返回值代替变参。啊?你要返回多 <br>个值?那建议返回一个指向结构体的指针,或一个最简单的对象。 <br> <br>来自: fisheryj, 时间: 2003-08-28 17:42:00, ID: 2140529 &nbsp;<br>太麻烦了 <br>还是用 &nbsp;IF &nbsp; &nbsp;THEN <br> &nbsp; &nbsp; &nbsp; &nbsp;ELSE <br>吧 <br> <br>问题讨论没有结束 ...
 
不光函数可以保存在数据库中,界面也可以保存在数据库中
 
哦,怎么实现,超级牛X介绍一下
 
多人接受答案了。
 
后退
顶部