zoukankan      html  css  js  c++  java
  • 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)

    在C++中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用。但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。C++专门为成员指针准备了三个运算符: "::*"用于指针的声明,而"->*"和".*"用来调用指针指向的函数。

    // Thunk.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    typedef unsigned int DWORD;
    
    //取类成员函数的地址.vc8版本.可以取私有成员函数地址.
    #define GetMemberFuncAddr_VC8(FuncAddr,FuncType)
    {                                                
         __asm                                        
        {                                            
            mov eax,offset FuncType                    
        };                                            
        __asm                                        
        {                                            
            mov FuncAddr, eax                        
        };                                            
    }
    
    //取类成员函数的地址.vc6版本.
    template <class ToType, class FromType>
    void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
    {
        union 
        {
            FromType _f;
            ToType   _t;
        }ut;
    
        ut._f = f;
    
        addr = ut._t;
    }
    
    //调用类成员函数
    DWORD CallMemberFunc(int callflag,DWORD funcaddr,void *This,int count,...)
    {
        DWORD re;
    
        if(count>0)//有参数,将参数压入栈.
        {
            __asm
            {
                mov  ecx,count;//参数个数,ecx,循环计数器.
    
                mov  edx,ecx;
                shl  edx,2;    
                add  edx,0x14;  edx = count*4+0x14;
    
          next:    push  dword ptr[ebp+edx];
                sub   edx,0x4;
                dec   ecx  
                jnz   next;
            }
        }
    
        //处理this指针.
        if(callflag==0) //__thiscall,vc默认的成员函数调用类型.
        {
            __asm mov ecx,This;
        }
        else//__stdcall
        {
            __asm push This;
        }
    
        __asm//调用函数
        {
            call funcaddr; //call 1.向堆栈中压入下一行程序的地址;2.JMP到call的子程序地址处。
            mov  re,eax;
        }
    
        return re;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////////
    void test1()//演示c++成员函数指针的用法.
    {
       class tt
       {
           public: void foo(int x){ printf("
     %d 
    ",x); }
       };
    
       typedef   void (tt::* FUNCTYPE)(int);
    
    
        FUNCTYPE ptr = &tt::foo;  //给一个成员函数指针赋值.
    
        tt a;
        (a.*ptr)(5);   //调用成员函数指针.
    
        tt *b = new tt;
        (b->*ptr)(6);  //调用成员函数指针.
    
        delete b;
    //    DWORD dwFooAddrPtr= 0;
    //    dwFooAddrPtr = (DWORD) &tt::foo;  /* Error C2440 */
    //    dwFooAddrPtr = reinterpret_cast<DWORD> (&tt::foo); /* Error C2440 */
    }
    
    void test2()//示范如何取成员函数地址.
    {
       class tt
       {
           public: void foo(int x){ printf("
     %d 
    ",x); }
       };
    
    #if _MSC_VER >1200
        DWORD dwAddrPtr1;
        GetMemberFuncAddr_VC8(dwAddrPtr1,tt::foo);
        printf("
     test2 tt::foo %08x",dwAddrPtr1);
    #endif
    
        DWORD dwAddrPtr2;
        GetMemberFuncAddr_VC6(dwAddrPtr2,&tt::foo);
        printf("
     test2 tt::foo %08x",dwAddrPtr2);
    }
    
    void test3()//示范如何调用成员函数地址.
    {
        class tt 
        {
         public:
    
            void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
            {
                printf("
     m_a=%d, %d,%c,%s
    ",m_a,x,c,s);
            }
    
            void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
            {
                printf("
     m_a=%d, %d,%c,%s
    ",m_a,x,c,s);
            }
    
            int m_a;
        };
    
        typedef  void (__stdcall *FUNCTYPE) (       int,char,char*);//定义对应的非成员函数指针类型,注意指定__stdcall.
        typedef  void (__stdcall *FUNCTYPE2)(void *,int,char,char*);//注意多了一个void *参数.
    
        tt abc;
        abc.m_a = 123;
    
        DWORD ptr;
        DWORD This = (DWORD)&abc;
     
        GetMemberFuncAddr_VC6(ptr,&tt::foo); //取成员函数地址.
    
        FUNCTYPE fnFooPtr  = (FUNCTYPE) ptr;//将函数地址转化为普通函数的指针. 
    
        __asm //准备this指针.
        {
            mov ecx, This;
        }
    
        fnFooPtr(5,'a',"7xyz"); //象普通函数一样调用成员函数的地址.
    
    
        GetMemberFuncAddr_VC6(ptr,&tt::foo2); //取成员函数地址.
    
        FUNCTYPE2 fnFooPtr2 = (FUNCTYPE2) ptr;//将函数地址转化为普通函数的指针. 
    
        fnFooPtr2(&abc,5,'a',"7xyz"); //象普通函数一样调用成员函数的地址,注意第一个参数是this指针.
    }
    
    void test4()//示范通过CallMemberFunc调用成员函数
    {
        class tt 
        {
         public:
    
            void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
            {
                printf("
     m_a=%d, %d,%c,%s
    ",m_a,x,c,s);
            }
    
            void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
            {
                printf("
     m_a=%d, %d,%c,%s
    ",m_a,x,c,s);
            }
    
            int m_a;
        };
    
        tt abc;
        abc.m_a = 123;
    
        DWORD ptr1,ptr2;
    
        GetMemberFuncAddr_VC6(ptr1,&tt::foo); //取成员函数地址.
        GetMemberFuncAddr_VC6(ptr2,&tt::foo2); //取成员函数地址.
    
        CallMemberFunc(0,ptr1,&abc,3,5,'a',"7xyz");//第一个参数0,表示采用__thiscall调用.
        CallMemberFunc(1,ptr2,&abc,3,5,'a',"7xyz");//第一个参数1,表示采用非__thiscall调用.  
    }
    
    void test5()//示范在继承情况下使用函数地址.
    {
        class tt1
        {
        public:
                    void foo1(){ printf("
     hi, i am in tt1::foo1
    ");        }
            virtual void foo3(){ printf("
     hi, i am in tt1::foo3
    ");    }
        };
    
        class tt2 : public tt1
        {
        public:
                    void foo2(){ printf("
     hi, i am in tt2::foo2
    ");  }
            virtual void foo3(){ printf("
     hi, i am in tt2::foo3
    ");    }
        };
    
    
        DWORD tt1_foo3,tt2_foo1,tt2_foo2,tt2_foo3;
    
        GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3);
        GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1);
        GetMemberFuncAddr_VC6(tt2_foo2,&tt2::foo2);
        GetMemberFuncAddr_VC6(tt2_foo3,&tt2::foo3);
    
        tt1 x;
        tt2 y;
    
        CallMemberFunc(0,tt1_foo3,&x,0); // tt1::foo3
        CallMemberFunc(0,tt2_foo1,&x,0); // tt2::foo1 = tt1::foo1
        CallMemberFunc(0,tt2_foo2,&x,0); // tt2::foo2
        CallMemberFunc(0,tt2_foo3,&x,0); // tt2::foo3
    
        CallMemberFunc(0,tt1_foo3,&y,0); // tt1::foo3
        CallMemberFunc(0,tt2_foo1,&y,0); // tt2::foo1 = tt1::foo1
        CallMemberFunc(0,tt2_foo2,&y,0); // tt2::foo2
        CallMemberFunc(0,tt2_foo3,&y,0); // tt2::foo3
    }
    
    int main(int argc, char* argv[])
    {
        test1();
        test2();
        test3();
        test4();
        test5();
    
       return 0;
    }

    http://download.csdn.net/download/tikycc2/1580557

  • 相关阅读:
    VMWare的Cloud Foundry实践(二):和MongoDB对接成功~
    MongoDB实践
    MongoDB 可读性比较差的语句
    C#异步编程之:(一)Task对象和lamda表达式探究
    创建自己的awaitable类型
    C#异步编程之(三):深入 Async 和 Await 的实现及其成本
    Node.js实践
    MVC+EasyUI+三层新闻网站建立(六 tabs的完成)
    MVC+EasyUI+三层新闻网站建立(七:分页查询出数据)
    MVC+EasyUI+三层新闻网站建立(八,详情页面完成)
  • 原文地址:https://www.cnblogs.com/findumars/p/5050029.html
Copyright © 2011-2022 走看看