日期:2006-07-19 05:24:07 来源:www.cngr.cn
thunk技术实现窗口类的封装
thunk->Proc = CMyWnd::stdProc; //静态窗口过程
//pop ecx,Proc已压栈,弹出Proc到ecx
thunk->Code[0] = 0x59; //pop ecx
//mov dword ptr [esp+0x4],this
//Proc已弹出,栈顶是返回地址,紧接着就是HWND了。
//[esp+0x4]就是HWND
thunk->Code[1] = 0xC7; // mov
thunk->Code[2] = 0x44; // dword ptr
thunk->Code[3] = 0x24; // disp8[esp]
thunk->Code[4] = 0x04; // +4
thunk->Window = this;
//偷梁换柱成功!跳转到Proc
//jmp [ecx]
thunk->Jmp = 0xFF; // jmp [r/m]32
thunk->ECX = 0x21; // [ecx]
m_thunk = (WNDPROC)thunk;
return m_thunk;
}
这样m_thunk虽然是一个结构,但其数据是一段可执行的代码,而其类型又是WNDPROC,系统就会忠实地按窗口过程规则调用这段代码,m_thunk就把Window字段里记录的this指针替换掉堆栈中的hWnd参数,然后跳转到静态的stdProc:
//本回调函数的HWND调用之前已由m_thunk替换为对象指针
LRESULT WINAPI CMyWnd::stdProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
CMyWnd* w = (CMyWnd*)hWnd;
return w->WindowProc(uMsg,wParam,lParam);
}
这样就把窗口过程转向到了类成员函数WindowProc,当然这样还有一个问题,就是窗口句柄hWnd还没来得及记录,因此一开始的窗口过程应该先定位到静态的InitProc,CreateWindow的时候给最后一个参数,即初始化参数赋值为this指针:
CreateWindowEx(
dwExStyle,
szClass,
szTitle,
dwStyle,
x,
y,
width,
height,
hParentWnd,
hMenu,
hInst,
this //初始化参数
);,
在InitProc里面取出该指针:
LRESULT WINAPI CMyWnd::InitProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
if(uMsg == WM_NCCREATE)
{
CMyWnd *w = NULL;
w = (CMyWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;
if(w)
{
//记录hWnd
w->m_hWnd = hWnd;
//改变窗口过程为m_thunk
SetWindowLong(hWnd,GWL_WNDPROC,(LONG)w-CreateThunk());
return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
这样就大功告成。
窗口过程转发流程:
假设已建立CMyWnd类的窗口对象 CMyWnd *window,初始化完毕后调用window->Create,这时Create的窗口其窗口过程函数是静态CMyWnd::InitWndProc
InitWndProc 实现功能:window->Create创建窗口时已把对象this指针放入窗口初始化参数中,在此过程的WM_NCCREATE消息中把this指针取出来:CMyWnd *w = (CMyWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;记录HWND:w->m_hWnd = hWnd,然后设置窗口过程为w->m_thunk(thunk是一个WNDPROC类型的成员数据,所以可以设置)
└→ window->m_thunk 实现功能:跳转到静态CMyWnd::stdProc,在此之前替换系统的调用参数HWND为this指针
└→ stdProc 实现功能:把HWND转换为窗口类指针:
CMyWnd *w = (CMyWnd*)hWnd;
return w->WindowProc(uMsg,wParam,lParam)
└→ window->WindowProc 实现功能:执行实际的消息处理,窗口句柄已保存在m_hWnd
//pop ecx,Proc已压栈,弹出Proc到ecx
thunk->Code[0] = 0x59; //pop ecx
//mov dword ptr [esp+0x4],this
//Proc已弹出,栈顶是返回地址,紧接着就是HWND了。
//[esp+0x4]就是HWND
thunk->Code[1] = 0xC7; // mov
thunk->Code[2] = 0x44; // dword ptr
thunk->Code[3] = 0x24; // disp8[esp]
thunk->Code[4] = 0x04; // +4
thunk->Window = this;
//偷梁换柱成功!跳转到Proc
//jmp [ecx]
thunk->Jmp = 0xFF; // jmp [r/m]32
thunk->ECX = 0x21; // [ecx]
m_thunk = (WNDPROC)thunk;
return m_thunk;
}
这样m_thunk虽然是一个结构,但其数据是一段可执行的代码,而其类型又是WNDPROC,系统就会忠实地按窗口过程规则调用这段代码,m_thunk就把Window字段里记录的this指针替换掉堆栈中的hWnd参数,然后跳转到静态的stdProc:
//本回调函数的HWND调用之前已由m_thunk替换为对象指针
LRESULT WINAPI CMyWnd::stdProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
CMyWnd* w = (CMyWnd*)hWnd;
return w->WindowProc(uMsg,wParam,lParam);
}
这样就把窗口过程转向到了类成员函数WindowProc,当然这样还有一个问题,就是窗口句柄hWnd还没来得及记录,因此一开始的窗口过程应该先定位到静态的InitProc,CreateWindow的时候给最后一个参数,即初始化参数赋值为this指针:
CreateWindowEx(
dwExStyle,
szClass,
szTitle,
dwStyle,
x,
y,
width,
height,
hParentWnd,
hMenu,
hInst,
this //初始化参数
);,
在InitProc里面取出该指针:
LRESULT WINAPI CMyWnd::InitProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
if(uMsg == WM_NCCREATE)
{
CMyWnd *w = NULL;
w = (CMyWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;
if(w)
{
//记录hWnd
w->m_hWnd = hWnd;
//改变窗口过程为m_thunk
SetWindowLong(hWnd,GWL_WNDPROC,(LONG)w-CreateThunk());
return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
这样就大功告成。
窗口过程转发流程:
假设已建立CMyWnd类的窗口对象 CMyWnd *window,初始化完毕后调用window->Create,这时Create的窗口其窗口过程函数是静态CMyWnd::InitWndProc
InitWndProc 实现功能:window->Create创建窗口时已把对象this指针放入窗口初始化参数中,在此过程的WM_NCCREATE消息中把this指针取出来:CMyWnd *w = (CMyWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;记录HWND:w->m_hWnd = hWnd,然后设置窗口过程为w->m_thunk(thunk是一个WNDPROC类型的成员数据,所以可以设置)
└→ window->m_thunk 实现功能:跳转到静态CMyWnd::stdProc,在此之前替换系统的调用参数HWND为this指针
└→ stdProc 实现功能:把HWND转换为窗口类指针:
CMyWnd *w = (CMyWnd*)hWnd;
return w->WindowProc(uMsg,wParam,lParam)
└→ window->WindowProc 实现功能:执行实际的消息处理,窗口句柄已保存在m_hWnd
Tags:
作者:佚名评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论
