问题的描述:1.有一个test.dll库,其中有一些函数,但是我们并不知道其中的函数名和参数表;2.当我们的程序在运行时会得到需要调用的函数名和其参数表,我们用这些信息来调用test.dll中相应的函数。比如在运行时获得了调用 int Add(int i,intj)函数的命令,我们需要首先装载dll文件,然后查找相应的函数是否存在,如果存在则获得函数的入口地址并希望通过函数指针调用该函数。问题产生了:在编译时我们并不清楚被调用的函数的返回值和参数表,我们如何定义这个函数指针呢?用汇编代码直接把参数push到堆栈中,然后再调用函数,最后恢复堆栈,这样就能解决这些问题了,具体的实现方法如下:我们调用函数的方式是__stdcall,在调用函数时是以从右至左的顺序将参数依次压栈,与C/C++默认的__cdecl方式不同,__stdcall在函数返回时会自动恢复堆栈,而__cdecl需要显式的恢复堆栈;__stdcall函数如有返回值,则会把值保存在寄存器eax中。我们获得了函数名_Add@8存储在字符串变量procName中;参数从左至右为int型的i,int型的j;返回值为int 首先定义一个参数的结构体: typedef struct{ int tag;//代表参数的类型;其中1为int,2为char,3为float value val; }parameter;其中的value是一个union: typedef union{ int intVal; char chVal; float fltVal; }value;
在程序中我们定义了vector<parameter> v ,将参数按从左至右的顺序push_back。然后就可以进行调用了:#define PUSH_INT(var) __asm push var#define PUSH_CHAR(var) __asm push var#define PUSH_FLOAT(var) __asm push var
HINSTANCE hdll = LoadLibrary("Test.dll"); if (hdll!=NULL) { FARPROC proc = (FARPROC)GetProcAddress(hdll,procName); if(proc != NULL) { for(int i=v.size()-1;i>=0;i-) { parameter p = v.at(i); switch(p.tag){ case 1: PUSH_INT(p.val.intVal) break; case 2: PUSH_CHAR(p.val.chVal) case 3: PUSH_FLOAT(p.val.fltVal) break; } } __asm call proc int retVal; __asm mov dword ptr[retVal],eax } }
这样就完成了不确定参数的函数的调用
