⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 membfunc.cpp

📁 在《C++ Templates: The Complete Guide》一书中(以下简称书)
💻 CPP
字号:
// 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("\n %d \n",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("\n %d \n",x); }
   };

#if _MSC_VER >1200
    DWORD dwAddrPtr1;
    GetMemberFuncAddr_VC8(dwAddrPtr1,tt::foo);
	printf("\n test2 tt::foo %08x",dwAddrPtr1);
#endif

	DWORD dwAddrPtr2;
    GetMemberFuncAddr_VC6(dwAddrPtr2,&tt::foo);
	printf("\n test2 tt::foo %08x",dwAddrPtr2);
}

void test3()//示范如何调用成员函数地址.
{
	class tt 
	{
	 public:

		void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
		{
			printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
		}

	    void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
		{
            printf("\n m_a=%d, %d,%c,%s\n",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("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
		}

	    void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
		{
            printf("\n m_a=%d, %d,%c,%s\n",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("\n hi, i am in tt1::foo1\n");	    }
		virtual void foo3(){ printf("\n hi, i am in tt1::foo3\n");	}
	};

	class tt2 : public tt1
	{
	public:
		        void foo2(){ printf("\n hi, i am in tt2::foo2\n");  }
		virtual void foo3(){ printf("\n hi, i am in tt2::foo3\n");	}
	};


	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;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -