T
TK128
Unregistered / Unconfirmed
GUEST, unregistred user!
如果我有这样一个数据结构,我应该如何构造一个通用程序调用方法?
数据结构如下:
TProcType=(ptProc,ptFunc,ptUser,ptSystem);
TFunctionAttribute=Packed Record
ProcType: Set of TProcType; //过程类型 系统表示是外部的过程 用户表示内部过程
ParamCount: Integer; //参数个数
ParamType: Array [0..MaxParamNumber-1] of Integer; //参数类型
ParamName: Array [0..MaxParamNumber-1] of String[MaxIdentLen]; //参数名
ProcAddr: Pointer; //函数地址
ResultType: Integer; //返回值类型
End;
TAttribute = Packed Record //属性结构
Name: String[MaxIdentLen]; //名称
DataType: Integer; //数据类型
BaseType: Integer; //基本类型
Size: Integer; //大小
Level: Integer; //所处层次
Address: DWord; //变量地址
Sub: TTypeDescription; //下推式符号表,包含一些必要的操作和数据结构,和本问题无关
Case Integer of
ID_ARRAYArrayParam: TArrayAttribute); //数组描述
ID_PROCEDURE,ID_FUNCTION ProcParam: TFunctionAttribute); //过程描述
ID_CONST: (Value: Pointer); //常量值
End;
上面这个数据结构是我在构造一个解释器时符号表用的数据结构,抛开结构的其他部分不
论,就函数调用而言,现碰到了一些问题:当我根据外部程序的描述,如:
Function Trim(S: String): String;
此时数据结构值为:
Attribute.Name:='Trim';
Attribute.DataType:=ID_FUNCTION;
Attribute.BaseType:=ID_FUNCTION;
Attribute.Size:=0;
Attribute.Level:=0; //最高级别,全局函数,谁都可以访问
Attribute.Address:=Index; //该函数在函数库中的索引
Attribute.Sub:=Nil;
Attribute.ProcType:=[ptFunc,ptSystem];
Attribute.ParamCount:=1;
Attribute.ParamType[0]:=ID_STRING;
Attribute.ParamName[0]:='S';
Attribute.ResultType:=ID_STRING;
当然这个数据结构是由专门的程序分析而得,不是由自己用手输入的!
有了这个数据结构,这时候产生了两个问题:(假定该函数是DELPHI内部的函数或是WINDOWS API,不然问题更多)
1. 如何取得定义函数的地址?(DELPHI中可没有DBASE中宏替换功能)
2. 如何构造一个通用的函数调用函数?(能根据这个数据结构的描述去调用对应的函数)
本人尝试过如下方法:
1. 建立一个形如: Function CallUserFunction(Index: Integer; S: Array of Variant): Variant;
的函数,在该函数中用第一个参数去查找某个数据表,得到要调用函数的地址然后调用,这种方法要求
所有函数都必须有同样参数,同样的申明,申明必须如下:
Function (S: Array of Variant): Variant;
通过定义该函数去调用系统和API函数,具体应用如下:
Function Own_Trim(S: Array of Variant): Variant; //替代Trim函数
Begin
if VarType=varString Then Result:=Trim(S[0])
Else Result:='';
End;
这样也能解决这个问题,但这种方法本人总认为较为不好
2. 由于上面的方法需要对每个系统函数编制另一个替代函数,因此本人又做了如下尝试:
(下面的程序不是本人过的程序仅是方法相同)
Function CallUserFunction(Index: Integer; S: Array of Variant): Variant;
Var
I: Integer;
Begin
For I:=0 To Attribute.ProcParam.ParamCount-1 Do
Begin
Case Attribute.ProcParam.ParamType of
ID_STRING:
Begin
Asm
Push String(S)
End;
End;
ID_INTEGER:
Begin
Asm
Push String(S)
End;
End;
End;
Asm
Call Attribute.ProcParam.ProcAddr
End;
End;
这种通过形成汇编指令间接调用的方式对WINDOWS API有效,对Delphi内部函数就无效了,
原因是Window API因为是操作系统函数,在汇编这个级别上严格的定义了输入、输出结果,
而Delphi内部函数由于有字符串操作,因此当用这样的调用方式去调用一些内部函数就出现
访问无效内存的错误,这种错误不是由于PASCAL调用规则和WINAPI调用规则引起的。
以上就是我的问题描述,请众高手指教!
数据结构如下:
TProcType=(ptProc,ptFunc,ptUser,ptSystem);
TFunctionAttribute=Packed Record
ProcType: Set of TProcType; //过程类型 系统表示是外部的过程 用户表示内部过程
ParamCount: Integer; //参数个数
ParamType: Array [0..MaxParamNumber-1] of Integer; //参数类型
ParamName: Array [0..MaxParamNumber-1] of String[MaxIdentLen]; //参数名
ProcAddr: Pointer; //函数地址
ResultType: Integer; //返回值类型
End;
TAttribute = Packed Record //属性结构
Name: String[MaxIdentLen]; //名称
DataType: Integer; //数据类型
BaseType: Integer; //基本类型
Size: Integer; //大小
Level: Integer; //所处层次
Address: DWord; //变量地址
Sub: TTypeDescription; //下推式符号表,包含一些必要的操作和数据结构,和本问题无关
Case Integer of
ID_ARRAYArrayParam: TArrayAttribute); //数组描述
ID_PROCEDURE,ID_FUNCTION ProcParam: TFunctionAttribute); //过程描述
ID_CONST: (Value: Pointer); //常量值
End;
上面这个数据结构是我在构造一个解释器时符号表用的数据结构,抛开结构的其他部分不
论,就函数调用而言,现碰到了一些问题:当我根据外部程序的描述,如:
Function Trim(S: String): String;
此时数据结构值为:
Attribute.Name:='Trim';
Attribute.DataType:=ID_FUNCTION;
Attribute.BaseType:=ID_FUNCTION;
Attribute.Size:=0;
Attribute.Level:=0; //最高级别,全局函数,谁都可以访问
Attribute.Address:=Index; //该函数在函数库中的索引
Attribute.Sub:=Nil;
Attribute.ProcType:=[ptFunc,ptSystem];
Attribute.ParamCount:=1;
Attribute.ParamType[0]:=ID_STRING;
Attribute.ParamName[0]:='S';
Attribute.ResultType:=ID_STRING;
当然这个数据结构是由专门的程序分析而得,不是由自己用手输入的!
有了这个数据结构,这时候产生了两个问题:(假定该函数是DELPHI内部的函数或是WINDOWS API,不然问题更多)
1. 如何取得定义函数的地址?(DELPHI中可没有DBASE中宏替换功能)
2. 如何构造一个通用的函数调用函数?(能根据这个数据结构的描述去调用对应的函数)
本人尝试过如下方法:
1. 建立一个形如: Function CallUserFunction(Index: Integer; S: Array of Variant): Variant;
的函数,在该函数中用第一个参数去查找某个数据表,得到要调用函数的地址然后调用,这种方法要求
所有函数都必须有同样参数,同样的申明,申明必须如下:
Function (S: Array of Variant): Variant;
通过定义该函数去调用系统和API函数,具体应用如下:
Function Own_Trim(S: Array of Variant): Variant; //替代Trim函数
Begin
if VarType=varString Then Result:=Trim(S[0])
Else Result:='';
End;
这样也能解决这个问题,但这种方法本人总认为较为不好
2. 由于上面的方法需要对每个系统函数编制另一个替代函数,因此本人又做了如下尝试:
(下面的程序不是本人过的程序仅是方法相同)
Function CallUserFunction(Index: Integer; S: Array of Variant): Variant;
Var
I: Integer;
Begin
For I:=0 To Attribute.ProcParam.ParamCount-1 Do
Begin
Case Attribute.ProcParam.ParamType of
ID_STRING:
Begin
Asm
Push String(S)
End;
End;
ID_INTEGER:
Begin
Asm
Push String(S)
End;
End;
End;
Asm
Call Attribute.ProcParam.ProcAddr
End;
End;
这种通过形成汇编指令间接调用的方式对WINDOWS API有效,对Delphi内部函数就无效了,
原因是Window API因为是操作系统函数,在汇编这个级别上严格的定义了输入、输出结果,
而Delphi内部函数由于有字符串操作,因此当用这样的调用方式去调用一些内部函数就出现
访问无效内存的错误,这种错误不是由于PASCAL调用规则和WINAPI调用规则引起的。
以上就是我的问题描述,请众高手指教!