2011-03-25 101 views
3

我将尝试更好地解释我想要执行的操作。 我读了一个带有函数签名的文件,我想创建一个指向每个函数的指针。指向任意函数的“通用函数签名”指针

例如,看起来像这样的文件:

something.dll;int f(char* x, int y, SOMESTRUCT z) 
something.dll;void g(void) 
something.dll;SOMESTRUCT l(longlong w) 

现在,运行时我希望能够(通过something.dll加载和使用GetProcAddress的这些功能)来创建指向这些功能中。

现在,GetProcAddress返回指向任意函数的FARPROC,但是如何在运行时使用FARPROC来调用这些函数? 从我所知道的,我需要将FARPROC转换为正确的签名,但是我不能在运行时(或者至少我不知道如何)执行它。

有没有人有任何想法如何设计做到这一点?

谢谢! :-)

+0

你试图以错误的方式解决问题。也许描述你想要解决什么问题。 – ybungalobill 2011-03-25 19:35:18

+0

如果您不知道要投射到哪个函数指针类型,则'FARPROC'句柄是无用的;就像'void *'指针是无用的,如果你不知道要投射到什么数据指针类型。 – aschepler 2011-03-25 19:37:26

回答

3
  1. 函数类型是编译时在C++中,所以它不会工作,除非你可以定义所有你要事先要使用的类型。

  2. 它将参数推送到堆栈(和局部变量是这样)并将函数调用为void(__cdecl *)(void)。

  3. 对于其他类型的函数(如fastcall或thiscall)它可能会更成问题。

更新:其实,我做出了表率,它适用于键盘: (还与STDCALL功能的作品,因为堆的恢复比对后,堆页头)

http://codepad.org/0cf0YFRH

#include <stdio.h> 

#ifdef __GNUC__ 
#define NOINLINE __attribute__((noinline)) 
#define ALIGN(n) __attribute__((aligned(n))) 
#else 
#define NOINLINE __declspec(noinline) 
#define ALIGN(n) __declspec(align(n)) 
#endif 

//#define __cdecl 

// Have to be declared __cdecl when its available, 
// because some args may be passed in registers otherwise (optimization!) 
void __cdecl test(int a, void* b) { 
    printf("a=%08X b=%08X\n", a, unsigned(b)); 
} 

// actual pointer type to use for function calls 
typedef int (__cdecl *pfunc)(void); 

// wrapper type to get around codepad's "ISO C++" ideas and gcc being too smart 
union funcwrap { 
    volatile void* y; 
    volatile pfunc f; 
    void (__cdecl *z)(int, void*); 
}; 

// gcc optimization workaround - can't allow it to know the value at compile time 
volatile void* tmp = (void*)printf("\n"); 
volatile funcwrap x; 
int r; 

// noinline function to force the compiler to allocate stuff 
// on stack just before the function call 
NOINLINE 
void call(void) { 
    // force the runtime stack pointer calculation 
    // (compiler can't align a function stack in compile time) 
    // otherwise, again, it gets optimized too hard 

    // the number of arguments; can be probably done with alloca() 
    ALIGN(32) volatile int a[2]; 
    a[0] = 1; a[1] = 2; // set the argument values 
    tmp = a; // tell compiler to not optimize away the array 
    r = x.f(); // call the function; returned value is passed in a register 

    // this function can't use any other local vars, because 
    // compiler might mess up the order 
} 

int main(void) { 
    // again, weird stuff to confuse compiler, so that it won't discard stuff 
    x.z = test; tmp=x.y; x.y=tmp; 
    // call the function via "test" pointer 
    call(); 
    // print the return value (although it didn't have one) 
    printf("r=%i\n", r); 
} 
2

一旦你有了FARPROC,你可以将FARPROC转换成指向适当函数类型的指针。例如,你可以说

int (*fPtr)(char*, int, SOMESTRUCT) = (int (*)(char*, int, SOMESTRUCT))GetProcAddress("f"); 

或者,如果你想使用typedef s到使它更容易些:

typedef int (*FType)(char *, int, SOMESTRUCT); 
FType fPtr = (FType)GetProcAddress("f"); 

现在你已经存储在合适类型的函数指针的函数指针,你可以拨打电话f

fPtr("My string!", 137, someStructInstance); 

希望这有助于!

2

编译器需要知道确切的函数签名,以便为调用创建适当的设置和拆卸。没有简单的方法来伪造它 - 从文件中读取的每个签名都需要相应的编译时签名才能与之匹配。

你也许可以通过熟悉编译器和汇编程序来完成你想要的任务,但我建议不要这样做。