游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2622|回复: 6

修正的第三版 非静态类成员函数指针 解决方案

[复制链接]

2万

主题

2万

帖子

6万

积分

论坛元老

Rank: 8Rank: 8

积分
66494
QQ
发表于 2007-2-27 17:49:00 | 显示全部楼层 |阅读模式
可指向任何类,包括未知类的成员函数。

仅保证Borland C++与Visual C++ 2005正常。


  1. #include<stdio.h>
  2. #include<stddef.h>
  3.        
  4. class _Object{};
  5.        
  6. #if defined(SetEventCall)||defined(CallEvent)||defined(DefineEvent)
  7.     #error SetEventCall,CallEvent,DefineEvent 已经定义
  8. #endif//
  9.        
  10. #ifdef __BORLANDC__
  11.        
  12.     #define SetEventCall(event_obj,obj,event_func)          event_obj=obj->event_func
  13.     #define CallEvent(event_obj)                            event_obj
  14.     #define DefineEvent(result,name,intro)                  result (__closure *name)intro
  15.        
  16. #else
  17.        
  18.     #pragma warning(disable:4311)
  19.        
  20.     template <typename T> struct EventFunc
  21.     {
  22.         unsigned __int32 this_address;
  23.         unsigned __int32 func_address;
  24.        
  25.         _Object *This;
  26.         T Func;
  27.        
  28.         EventFunc()
  29.         {
  30.             this_address=offsetof(EventFunc,This);
  31.             this_address+=(unsigned __int32)this;
  32.        
  33.             func_address=offsetof(EventFunc,Func);
  34.             func_address+=(unsigned __int32)this;
  35.         }
  36.     };
  37.        
  38.     #define SetEventCall(event_obj,obj,event_func)      {                                                           unsigned __int32 this_address=event_obj.this_address;                                                           unsigned __int32 func_address=event_obj.func_address;                                                                                                                   {                                                               __asm mov eax,this_address                                                              __asm mov ebx,obj                                                               __asm mov [eax],ebx                                                                                                                         __asm mov eax,func_address                                                              __asm mov ebx,event_func                                                                __asm mov [eax],ebx                                                         }                                                       }
  39.        
  40.     #define CallEvent(event_obj)                    (event_obj.This->*(event_obj.Func))             //(*(event_obj.This).*(event_obj.Func))
  41.        
  42.     #define DefineEvent(result,name,intro)          EventFunc<result (_Object:: *)intro> name;
  43. #endif//__BORLANDC__
  44.        
  45. class Button
  46. {
  47. public:
  48.        
  49.     DefineEvent(void,OnClick,(Button *,int));           //定义事件,原型为: void OnClick(Button *,int)
  50.        
  51. public:
  52.        
  53.     Button()
  54.     {
  55.         printf("Button this=%p\n",this);
  56.     }
  57.        
  58.     void TestButtonClick()
  59.     {
  60.         CallEvent(OnClick)(this,0);                     //呼叫OnClick,原型为: OnClick(this,0)
  61.     }
  62. };
  63.        
  64. class Test
  65. {
  66.     Button *button;
  67.        
  68. public:
  69.        
  70.     void OnButtonClick(Button *but,int)
  71.     {
  72.         printf("Test::OnButtonClick,this=%p,but=%p\n",this,but);
  73.     };
  74.        
  75. public:
  76.        
  77.     Test()
  78.     {
  79.         printf("Test this=%p\n",this);
  80.        
  81.         button=new Button;
  82.        
  83.         SetEventCall(button->OnClick,this,OnButtonClick);               //设定button->OnClick事件的处理函数为this->OnButtonClick
  84.        
  85.         button->TestButtonClick();
  86.     }
  87. };
  88.        
  89. void main(int,char **)
  90. {
  91.     Test *test;
  92.        
  93. #ifdef __BORLANDC__
  94.     printf("Compiler: Borland C/C++ or Turbo C/C++ %d.%d%d\n",(__BORLANDC__>>8),((__BORLANDC__&0xF0)>>4),(__BORLANDC__&0x0F));
  95. #endif
  96. #ifdef _MSC_VER
  97.     printf("Compiler: Microsoft C/C++ %.2f (Visual C/C++ %.2f)\n",_MSC_VER/100.f,_MSC_VER/100.f-6);
  98. #endif//
  99.        
  100.     printf("Compile Time: %s %s\n\n",__DATE__,__TIME__);
  101.        
  102.     test=new Test;
  103.        
  104.     delete test;
  105. }
复制代码

15

主题

363

帖子

390

积分

中级会员

Rank: 3Rank: 3

积分
390
发表于 2007-2-27 18:03:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

顶一个,有一点,表示指针应该需要考虑一下64位指针的问题吧?毕竟64位越来越近了……用__int32会不会有点……

2万

主题

2万

帖子

6万

积分

论坛元老

Rank: 8Rank: 8

积分
66494
QQ
 楼主| 发表于 2007-2-27 19:44:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

在32位编译器下指针还都是32位。

64位下将__int32改为__int64,将eax之类改为rax就可以了。

8

主题

111

帖子

163

积分

注册会员

Rank: 2

积分
163
发表于 2007-2-28 09:16:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

http://www.codeproject.com/cpp/FastDelegate.asp
codeproject上有一个fastdelegate的项目,好像做得更完善一点.

25

主题

304

帖子

311

积分

中级会员

Rank: 3Rank: 3

积分
311
发表于 2007-2-28 09:53:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

我以前用的是下面的这种方法
namespace xlibplus
{

template < class TRet, class T >
inline TRet ThisCall0( T func, LPVOID pThis )
{       
        TRet lpRet;
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        __asm mov lpRet, eax
        return lpRet;
}

template < class TRet, class T, class Tp1 >
inline TRet ThisCall1( T func, LPVOID pThis, Tp1 lpParam1 )
{       
        TRet lpRet;
        __asm push dword ptr[lpParam1]
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        __asm mov lpRet, eax
        return lpRet;
}

template < class TRet, class T, class Tp1, class Tp2 >
inline TRet ThisCall2( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2 )
{       
        TRet lpRet;
        __asm push dword ptr[lpParam2]
        __asm push dword ptr[lpParam1]
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        __asm mov lpRet, eax
        return lpRet;
}

template < class TRet, class T, class Tp1, class Tp2, class Tp3  >
inline TRet ThisCall3( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
{
        TRet lpRet;
        __asm push dword ptr[lpParam3]
        __asm push dword ptr[lpParam2]
        __asm push dword ptr[lpParam1]
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        //__asm push eax
        __asm mov lpRet, eax
        return lpRet;
}

template < class TRet, class T, class Tp1, class Tp2, class Tp3, class Tp4 >
inline TRet ThisCall4( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
{       
        TRet lpRet;
        __asm push dword ptr[lpParam4]
        __asm push dword ptr[lpParam3]
        __asm push dword ptr[lpParam2]
        __asm push dword ptr[lpParam1]
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        __asm mov lpRet, eax
        return lpRet;
}

template < class TRet, class T, class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
inline TRet ThisCall5( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
{       
        TRet lpRet;
        __asm push dword ptr[lpParam5]
        __asm push dword ptr[lpParam4]
        __asm push dword ptr[lpParam3]
        __asm push dword ptr[lpParam2]
        __asm push dword ptr[lpParam1]
        __asm mov ecx, pThis;
        //__asm push eax
        __asm call dword ptr[func];
        __asm mov lpRet, eax
        return lpRet;
}

template < class T >
inline LPVOID        F2P( T func )
{
        __asm mov eax, dword ptr[func];
}

template< class TRet = LPVOID >
class xThisCallCustom
{
        typedef xThisCallCustom<TRet> xThisClass;
public:
        xThisCallCustom()
        {
                m_lpThis = NULL;
                m_lpFunc = NULL;
        }

        xThisCallCustom(const xThisClass & thiscall )
        {
                m_lpThis = thiscall.m_lpThis;
                m_lpFunc = thiscall.m_lpFunc;
        }

        template <class T>
        xThisCallCustom(LPVOID lpThis, T func)
        {
                m_lpThis = lpThis;
                m_lpFunc = F2P(func);
        }

        LPVOID getThisPtr()const{ return m_lpThis;}
        VOID        setThisPtr( LPVOID lpThis ){ m_lpThis = lpThis;}

        LPVOID getFuncPtr()const{ return m_lpFunc;}
        template <class T>        VOID        setFuncPtr( T func ){ m_lpFunc = F2P( func );}

        TRet call()
        {
                if( !Assigned() )return NULL;
                return ThisCall0<TRet>( m_lpFunc, m_lpThis );
        }

        template < class Tp1 >
        TRet call( Tp1 lpParam1 )
        {
                if( !Assigned() )return NULL;
                return ThisCall1<TRet>( m_lpFunc, m_lpThis, lpParam1 );
        }
        template < class Tp1, class Tp2 >
        TRet call( Tp1 lpParam1, Tp2 lpParam2 )
        {
                if( !Assigned() )return NULL;
                return ThisCall2<TRet>( m_lpFunc, m_lpThis, lpParam1, lpParam2 );
        }
        template < class Tp1, class Tp2, class Tp3 >
        TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
        {
                if( !Assigned() )return NULL;
                //LPVOID lpRet = NULL;
                return ThisCall3<TRet>( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3 );
                //__asm pop lpRet;
                //return lpRet;
        }
        template < class Tp1, class Tp2, class Tp3, class Tp4 >
        TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
        {
                if( !Assigned() )return NULL;
                return ThisCall4<TRet>( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3, lpParam4 );
        }
        template < class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
        TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
        {
                if( !Assigned() )return NULL;
                return ThisCall5<TRet>( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3, lpParam4, lpParam5 );
        }

        template < class TTHIS >
        TRet callWithThis(TTHIS * pThis)
        {
                if( !Assigned() )return NULL;
                return ThisCall0<TRet>( m_lpFunc, pThis );
        }       
        template < class TTHIS, class Tp1 >
        TRet callWithThis( TTHIS * pThis, Tp1 lpParam1 )
        {
                if( !Assigned() )return NULL;
                return ThisCall1<TRet>( m_lpFunc, pThis, lpParam1 );
        }
        template < class TTHIS, class Tp1, class Tp2 >
        TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2 )
        {
                if( !Assigned() )return NULL;
                return ThisCall2<TRet>( m_lpFunc, pThis, lpParam1, lpParam2 );
        }
        template < class TTHIS, class Tp1, class Tp2, class Tp3 >
        TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
        {
                if( !Assigned() )return NULL;
                return ThisCall3<TRet>( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3 );
        }
        template < class TTHIS, class Tp1, class Tp2, class Tp3, class Tp4 >
        TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
        {
                if( !Assigned() )return NULL;
                return ThisCall4<TRet>( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3, lpParam4 );
        }
        template < class TTHIS, class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
        TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
        {
                if( !Assigned() )return NULL;
                return ThisCall5<TRet>( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3, lpParam4, lpParam5 );
        }


        xThisClass & operator =( const xThisClass & thiscall )
        {
                this->m_lpFunc = thiscall.m_lpFunc;
                this->m_lpThis = thiscall.m_lpThis;
                return *this;
        }

        BOOL        Assigned(){ return (m_lpFunc != NULL);}
protected:
        LPVOID m_lpThis;
        LPVOID m_lpFunc;
};

typedef xThisCallCustom<> xThisCall;
typedef xThisCallCustom<> xEventCall;

typedef xThisCallCustom<int> xCompareCall;

};

25

主题

304

帖子

311

积分

中级会员

Rank: 3Rank: 3

积分
311
发表于 2007-2-28 09:55:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

针对CALLBACK的解决方案

#pragma once
template < class T >
inline LPVOID        F2P( T func )
{
        __asm mov eax, dword ptr[func];
}

class CCallbackAdapter
{
public:
        template <class T>
        CCallbackAdapter(LPVOID lpThis, T Func)
        {
                LPVOID lpFunc = F2P( Func );
                _Build( lpThis, lpFunc );
        }
        virtual ~CCallbackAdapter(void);
        template <class T>
        VOID        Build( LPVOID lpThis, T Func )
        {
                LPVOID lpFunc = F2P( Func );
                _Build( lpThis, lpFunc );
        }
        LPVOID        GetCallBack(){ return (LPVOID)m_cbCode;}
protected:
        VOID        _Build( LPVOID lpThis, LPVOID lpFunc );
        BYTE        m_cbCode[12];
};


CCallbackAdapter::~CCallbackAdapter(void)
{
}

VOID CCallbackAdapter::_Build( LPVOID lpThis, LPVOID lpFunc )
{
        m_cbCode[0] = 0xb9;
        *(LPVOID*)(m_cbCode+1) = lpThis;
        m_cbCode[5] = 0xe9;
        LONG lOffset = (LONG)lpFunc - (LONG)(&m_cbCode[10]);
        *(LONG*)(m_cbCode+6) = lOffset;
}

0

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2007-3-1 10:29:00 | 显示全部楼层

Re:修正的第三版 非静态类成员函数指针 解决方案

和第2版有什么区别?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-4-13 14:05

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表