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);
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);
解决方案 »
- 映射函数不见了
- 急``~请高手帮忙看哈,出现这种错误是我的vc++6.0那里出了问题~~~急...
- XP下如何切换窗口和按钮的样式?
- 用directshow如何知道一个影片播完需要多长时间?
- vc里面如何把粘贴板里面的图片内容另存为一幅bmp图片!
- 超级新手问题:VC6中,头文件引入.h加与不加有何区别
- 找vc入门电子书一本,最好提供例程源代码
- 能否推荐关于网络编程实例的好书
- 急问:如何在程序中关闭其它exe文件的窗口
- 怎样获得指定字体显示的字符串的点阵数组
- 我的程序在运行模式下正常,在调试模式下退出的时候总会产生错误:UnHandle exception int Testoutput.exe:0xC0000005:Access Violation.
- 在dialog中如何画一个坐标曲线图?请大侠指点
但是THUNK技术可以用.我为什么总是调试失败.
:)
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才可以的.
子类:
class childClass:public myClass
{
public:
childClass();
~childClass();
protected:
virtual LRESULT trueProc(HWND,UINT,WPARAM,LPARAM)
{
//we can do somthing to this
}
};
http://www.shengfang.org/blog/index.php?job=art&articleid=a_20060622_163325
SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)MYPROC);
这句改成SETWINDOWLONG(HWND,GWL_WNDPROC,(LONG)(WNDPROC)MYPROC);试试吧
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);
}};
静态函数的指针:
CALL 标准跳转函数
DD 类的this指针每一个转换的函数都会分配一段这样的代码,其中各自的this指针不一样。执行call指令时,它会把该指令的下一条指令的地址入栈,因此,在标准跳转函数中,只要POP出栈首,再拿到它指向的值,就可以取得this指针了。这种方式在STL的窗口类和Delphi的窗口类以及WebService类中都有用到。要注意的是这段代码一定要有足够长的生存周期。
最近在写多线程的Hook时遇到了麻烦,每个线程都需要设置Hook,需要有不同的上下文,并且每个线程都应当保持它自己的HHOOK OldHook,用了这个类后才解决问题。
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);
}
终于解决了,我利用THUNK技术,总是调试失败,原来犯个低级小错误.
trueProc()函数,必须要加括号.象这样
lresult trueProc(.....)
{//不能少
return 0;//那怕一行代码不能少,当然就这行代码,让你的程序显不出来,呵呵,加其他逻辑吧
}//不能少你单单声明此函数,试试,别加括号,这些,保证你编译通不过,提示什么EXTERN错误.加了我标住的就没错,
真实奇怪.原来就因为这个错误.哎!郁闷了2天.
-----
谢谢楼上各位的精彩回复.我从来没有见过如此精彩绝伦的回帖.让我长了见识,扩充了视野.对于大家的辛苦劳动,充分得到楼主肯定.为响应3个代表,8荣8耻,大家可谓鞠躬尽瘁,任劳任怨.为构建我们有特色的和谐社会,大家做出了卓越贡献!特此,在楼主再三思索下,决定发分.请没有领到分的同志,排队领分.恩,保持队型,以确保发分效率........
楼上的问有啥用.
主要用途就是实现wapper callback with class