class myClass{
    static LRESULT CALLBACK MYPROC(HWND,UINT,WPARAM,LPARAM);
    ......
public:
    myClass(hwnd)
    {
        SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)MYPROC);
    }
protected:
    virtual LRESULT trueProc(HWND,UINT,WPARAM,LPARAM);
}
现在我写这样的类,我如何把STATIC MYPROC 转换到 非static trueProc;
我看了不少资料,但调试不成功,总提示无法转换到LONG错误.附带:我找的些资料THUNK技术.
/**************************************************************************
 *   ACCallback.h
 *   Helper class of Member function callback mechanism
 **************************************************************************/
#include "stdafx.h"
#include "windows.h"#pragma pack(push, 1)
struct _ACCallbackOpCodes
{
 unsigned char tag;  // CALL e8
 LONG_PTR offset;  // offset (dest - src - 5, 5=sizeof(tag + offset))
 LONG_PTR _this;   // a this pointer
 LONG_PTR _func;   // pointer to real member function address
};
#pragma pack(pop)static __declspec( naked ) int STDACJMPProc()
{
 _asm
 {
  POP ECX  
  MOV EAX, DWORD PTR [ECX + 4] // func
  MOV ECX, [ECX]     // this  
  JMP EAX
 }
}static LONG_PTR CalcJmpOffset(LONG_PTR Src, LONG_PTR Dest)
{
 return Dest - (Src + 5);
}/*
 * NOTE: _TPStdFunc: a type of function pointer to API or Callbacks, *MUST* be _stdcall
         _TPMemberFunc: a type of function pointer to class member function, 
         *MUST* be the *DEFAULT* calling conversation, *NO* prefix should be added,
          that is, using ECX for "this" pointer, pushing parameters from right to left, 
          and the callee cleans the stack.
          _TClass: the class who owns the callback function. The caller should only own the _stdcall function pointer
   LIFE TIME:  It is important to keep the ACCallback object alive until the CALLBACK is not required!!!
 */
template<typename _TPStdFunc, class _TClass, typename _TPMemberFunc>
class ACCallback
{
public:
 _TClass *m_pThis;
 _TPMemberFunc m_pFunc;private:
 _TPStdFunc m_pStdFunc; void MakeCode()
 {
  if (m_pStdFunc) ::VirtualFree(m_pStdFunc, 0, MEM_RELEASE);
  m_pStdFunc = (_TPStdFunc)::VirtualAlloc(NULL, sizeof(_ACCallbackOpCodes), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  _ACCallbackOpCodes *p = (_ACCallbackOpCodes *)m_pStdFunc;
  p->_func = *(LONG_PTR *)&m_pFunc;
  p->_this = (LONG_PTR)m_pThis;
  p->tag = 0xE8;
  p->offset = CalcJmpOffset((LONG_PTR)p, (LONG_PTR)STDACJMPProc);
 }public:
 ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>()
 {
 }
 ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>(_TClass* pThis,
  _TPMemberFunc pFunc
  )
 {
  m_pFunc = pFunc;
  m_pThis = pThis;
  m_pStdFunc = NULL;
  MakeCode();
 }
 void Assign(_TClass* pThis,
  _TPMemberFunc pFunc
  )
 {
  m_pFunc = pFunc;
  m_pThis = pThis;
  m_pStdFunc = NULL;
  MakeCode();
 }
 ~ACCallback<_TPStdFunc, _TClass, _TPMemberFunc>()
 {
  ::VirtualFree(m_pStdFunc, 0, MEM_RELEASE);
 }
 operator _TPStdFunc()
 {
  return m_pStdFunc;
 }
};/********************************** EXAMPLE **********************************
class CClass1
{
public:
 TCHAR m_Buf[255];
 BOOL EnumWindowProc(HWND hwnd, LPARAM lp)
 {
  GetWindowText(hwnd, m_Buf, 255);
  printf("Enum window=%s\n", m_Buf);
  return TRUE;
 }
 typedef BOOL (CClass1::*CLASSWNDENUMPROC)(HWND, LPARAM);
};TO USE:
 CClass1 c1;
 ACCallback<WNDENUMPROC, CClass1, CClass1::CLASSWNDENUMPROC> cb(&c1, &CClass1::EnumWindowProc);
 EnumWindows(cb, 0);************************* END OF EXAMPLE *********************************/
模板的三个参数分别是:API函数指针的类型,类名字,类成员函数指针的类型(两种函数指针在参数和返回值上应该一样,只是前者声明为_stdcall,后者不加任何调用修饰,即默认的__thiscall方式)
该项头文件的注释中给了一个调用API函数EnumWindows的例子。现在偶们来试试调用SetTimer。class CTestCallback
{
private:
 /* A callback of SetTimer, mirrored into member OnTimer */
 typedef void (CTestCallback::*CLASSTIMERPROC)(HWND, UINT, UINT_PTR, DWORD);
 void OnTimer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
 ACCallback<TIMERPROC, CTestCallback, CLASSTIMERPROC> m_DOnTimer;
}调用时,只要这样写:
/* 初始化回调结构 */
m_DOnTimer.Assign(this, &CTestCallback::OnTimer);
m_uid = ::SetTimer( NULL, 0, 1000, m_DOnTimer);

解决方案 »

  1.   

    我在VC版信誉是105啊.忘了说了,特别说明:代码是WIN32 API实现,不不任何其他类库,比如MFC,ATL,BO0STE.....
    但是THUNK技术可以用.我为什么总是调试失败.
      

  2.   

    谁可以解决,可以针对主题的类,和SETWINDOWLONG函数,写个小例子,万分感谢.上帝不会忘记你
    :)
      

  3.   

    http://www.evget.com/articles/evget_1678.html
      

  4.   

    http://www.shengfang.org/blog/index.php?job=art&articleid=a_20060622_163325
      

  5.   

    5星大虾说的成员函数指针,是不是在类外定义个
    EXTERN myClass *pmyClass;
    class myClass{
    private:
    wchar_t name[128];
    public:
        wchar_t* getStr()
        {
            return name;
        }
        static LRESULT CALLBACK MYPROC(HWND,UINT,WPARAM,LPARAM)
        {
            pmyClass->getStr();
        }
    public:
        myClass(HWND hwnd)
        {
            name="abc";
            SETWINDOWLONG(hwnd,GWL_WNDPROC,(LONG)MYPROC);
        }
    protected:
        virtual LRESULT trueProc(HWND,UINT,WPARAM,LPARAM)=0;
    };你说的不行的,我要重载继承trueProc函数呢.
    必须要把MYPROC转换到非静态的trueProc才可以的.
      

  6.   

    不光是指针问题,重要的棘手问题是有个STATIC 静态成员函数问题.需要把他转换到非静态函数,然后好做重载.让派生类也可以用到这个母类函数.
      

  7.   

    需要重载,就是派生类也可以用到这个母类成员函数.再个就是方便访问类中成员.
    子类:
    class childClass:public myClass
    {
    public:
        childClass();
        ~childClass();
    protected:
        virtual LRESULT trueProc(HWND,UINT,WPARAM,LPARAM)
        {
            //we can do somthing to this
        }
    };
      

  8.   

    没做用过!
    http://www.shengfang.org/blog/index.php?job=art&articleid=a_20060622_163325
      

  9.   

    -____-b  作者来了,作者来了,呵呵
    SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)MYPROC);
    这句改成SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)(WNDPROC)MYPROC);试试吧
      

  10.   

    以下代码已经过测试:
    class myClass{
    typedef LRESULT (CALLBACK *MYPROC)(HWND,UINT,WPARAM,LPARAM);     
    typedef LRESULT (myClass::*MYCLASSPROC)(HWND,UINT,WPARAM,LPARAM);
    protected:
        LRESULT trueProc(HWND,UINT,WPARAM,LPARAM)
    {
    return 0;
    }
    public:
    ACCallback<MYPROC, myClass, myClass::MYCLASSPROC> cb;
        myClass(HWND hwnd)
        {
    cb.Assign(this, &myClass::trueProc);
            SetWindowLong(hwnd,GWL_WNDPROC,(LONG)(MYPROC)cb);
        }};
      

  11.   

    说明一下,这种转换的原理实际上是在内存里生成了一段代码,如下:
    静态函数的指针:
       CALL 标准跳转函数
    DD 类的this指针每一个转换的函数都会分配一段这样的代码,其中各自的this指针不一样。执行call指令时,它会把该指令的下一条指令的地址入栈,因此,在标准跳转函数中,只要POP出栈首,再拿到它指向的值,就可以取得this指针了。这种方式在STL的窗口类和Delphi的窗口类以及WebService类中都有用到。要注意的是这段代码一定要有足够长的生存周期。
    最近在写多线程的Hook时遇到了麻烦,每个线程都需要设置Hook,需要有不同的上下文,并且每个线程都应当保持它自己的HHOOK OldHook,用了这个类后才解决问题。
      

  12.   

    如果楼主只有一个实例,这个问题是很好解决的。class myClass{
        static LRESULT CALLBACK MYPROC(HWND,UINT,WPARAM,LPARAM);
        static myClass* instance;
        ......
    public:
        myClass(hwnd);
    protected:
        virtual LRESULT trueProc(HWND,UINT,WPARAM,LPARAM);
    }
    //初始化
    myClass* myClass::instance = 0;
    myClass::myClass(hwnd)
    {
        if(!myClass::instance)
        {
            myClass::instance = this;
            SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)MYPROC);
        }
    }myClass::~myClass
    {
        if (myClass::instance == this)
        {
            myClass::instance = 0;
        }
    }LRESULT CALLBACK myClass::MYPROC(HWND,UINT,WPARAM,LPARAM)
    {
        myClass::instance->trueProc(UINT, WPARAM, LPARAM);
    }
      

  13.   

    不只一个实例.
    终于解决了,我利用THUNK技术,总是调试失败,原来犯个低级小错误.
    trueProc()函数,必须要加括号.象这样
    lresult trueProc(.....)
    {//不能少
        return 0;//那怕一行代码不能少,当然就这行代码,让你的程序显不出来,呵呵,加其他逻辑吧
    }//不能少你单单声明此函数,试试,别加括号,这些,保证你编译通不过,提示什么EXTERN错误.加了我标住的就没错,
    真实奇怪.原来就因为这个错误.哎!郁闷了2天.
    -----
    谢谢楼上各位的精彩回复.我从来没有见过如此精彩绝伦的回帖.让我长了见识,扩充了视野.对于大家的辛苦劳动,充分得到楼主肯定.为响应3个代表,8荣8耻,大家可谓鞠躬尽瘁,任劳任怨.为构建我们有特色的和谐社会,大家做出了卓越贡献!特此,在楼主再三思索下,决定发分.请没有领到分的同志,排队领分.恩,保持队型,以确保发分效率........
      

  14.   

    静态与非静态关系好理解,但不好解决.MFC WTL等这么牛气的库都离不开THUNK技术.我们也离不开啊.
      

  15.   

    我还在学习静态成员函数以及hook,这帖子太好了。
      

  16.   

    苏泊尔 我记的是电饭锅,呵呵.我煮米常用...superarhow(苏泊尔耗) 写出了 (LONG)(MYPROC)强制类型转换,我的代码里一直是(LONG),在大虾帮助下编译通过了,但是我C++基础真的不怎么样,说起来也是学习过C++的人,都是拖泥带水,一知半解,惭愧!以后加强学习,常来看看,错了,手误,常来问问.@_o我的问题解决了.THUNK技术的重要性只有怀揣梦想渴望拥有自己强大\个性\可伸缩性GUI类库的人,才渴望获得.另外,我写的基础类在一个.h文件中,所有类,和类的实现都在这一个文件中,为了其他程序调用方便,大量代码挤到一个文件中,实现时候挺麻烦.呵呵
      

  17.   

    另外提示thunk技术,可以应用到所有CALLBACK函数.一个小小的thunk类,可以解决很大问题,让你能够封装CALLBACK,呵呵
    楼上的问有啥用.
    主要用途就是实现wapper callback with class