首页  编辑  

根据文件给出的函数声明动态调用一个函数

Tags: /超级猛料/COM、ActiveX,DDE/   Date Created:
在已知函数名称和参数的情况下,静态调用和动态调用一个函数都是很简单的,但是如果我不知道这个函数的参数(编译的时候),但是在运行的时候,可以给出一个函数的声明到一个文件里面,那么这个时候如何去调用这个函数呢?
///Kingron测试的时候,发现用下面的方法可以做到,但是其中有一个PtrRec没有定义,而且会出现非法操作~~~~~~:(,不过你可以用简单的语句来测试:
asm
 push 100;   ///Push进去的参数值和个数可以动态改变的
 push 200;
 call windows.beep;   /// Call可以调用一个指针,因此也是可以动态改变的
end;
就是这个动态的改变需要用汇编来做,很麻烦~~~~~~~~~:(,因为必须判断参数个数和类型,之于调用那个函数倒是很简单
一般来说,凡是编译型的语言很难做到这一点,不过可以采取特殊的方法来做到它。用Delphi也可以做到,但是需要用到汇编代码。
当然,主要的问题是如何调用那些参数,至于函数名称和从DLL中读取都是很简单的事情,用LoadLibrary和GetProcAddress就可以做到了,在此不予讨论。只要解决了参数的个数和传递的问题,那么我们的问题就解决了,我们知道,函数的参数实际上都是一个堆栈来管理的,在调用函数之前,把参数压栈,然后Call那个函数即可,因此,明白了这个道理,那么我们就可以用一个自己创建的堆栈来进行模拟~~~~~~~~~
首先我们需要一个堆栈类,用于管理函数的参数:
Type
 TStack= Class
 private
   FPtr: Pointer;
   FSize: Word;
   FStackTop: Pointer;
   FUsed: Word;
   Function GetFree: Word;
 public
   Constructor Create( size: Word );
   Destructor Destroy; override;
   Procedure Push( Var data; datasize: Word );
   Property StackTop: Pointer read FStackTop;
   Property Free: Word read GetFree;
   Property Used: Word read FUsed
 end;
{  Methods of TStack  }
Function TStack.GetFree: Word;
 Begin
   Result := FSize - FUsed;
 End; { TStack.GetFree }
Constructor TStack.Create( size: Word );
 Begin
   inherited Create;
   FSize := size;
   GetMem( FPtr, size );
   FStackTop := FPtr;
   Inc( PtrRec( FStackTop ).ofs, size );
 End; { TStack.Create }
Destructor TStack.Destroy;
 Begin
   FreeMem( FPtr, size );
 End; { TStack.Destroy }
Procedure TStack.Push( Var data; datasize: Word );
 Begin
   If Free >= datasize Then Begin
     Dec( PtrRec( FStackTop ).ofs, datasize );
     Move( data, FStackTop^, datasize );
     Inc( FUsed, datasize );
   End { If }
   Else
     raise Exception.Create( 'Stack full!' );
 End; { TStack.Push }
接下来我们必须创建一个堆栈类的实例,然后把那些参数压栈,最后调用函数即可,那么调用的代码可能类似下面的:
Var
  Stack: TStack;
  size : Word;
  Top  : Pointer;
Begin
  ..create stack and fill it
  size := Stack.Used;
  Top  := Stack.StackTop;
  asm
    mov cx, size
    jcxz @noParams
    mov ax, ss
    mov es, ax
    sub sp, cx
    mov di, sp
    push ds
    lds si, Top
    cld
    rep movsb
    pop ds
  @noParams:
    call DLLProc
    { add sp, size  only if DLLProc is cdecl and size <> 0! }
  end;
end;
One caveat: TStack.Push should raise an exception if you try to push data with an odd datasize; the CPU stack uses WORD as the smallest unit so only data with an even datasize can be pushed; odd size items like Char and Byte have to be extended to Words first!