指向任意函数的“通用函数签名”指针

时间:2011-03-25 19:06:50

标签: c++ windows

我会试着更好地解释一下我想做什么。 我读了一个带有函数签名的文件,我想创建一个指向每个函数的指针。

例如,一个如下所示的文件:

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转换为正确的签名,但我不能在运行时(或者至少我不知道如何)这样做。

有没有人知道如何设计呢?

谢谢! : - )

3 个答案:

答案 0 :(得分:3)

  1. 函数类型在C ++中是编译时的,所以它不起作用,除非您可以提前定义所有类型。

    < / LI>
  2. 将参数推送到堆栈(本地变量就是这样)并将函数调用为void(__ cdecl *)(void)。

  3. 使用其他一些功能(如fastcall或thiscall)可能会出现问题。

  4. 更新:我实际上做了一个例子,它适用于键盘: (也适用于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 );
    }
    

答案 1 :(得分:2)

获得FARPROC后,可以将FARPROC转换为指向相应函数类型的指针。例如,你可以说

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

或者,如果您想使用typedef来简化此操作:

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

现在您已将函数指针存储在相应类型的函数指针中,您可以通过编写

来调用f
fPtr("My string!", 137, someStructInstance);

希望这有帮助!

答案 2 :(得分:2)

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

您可以通过对编译器和某些汇编程序的深入了解来做您想做的事情,但我建议不要这样做。