• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

ATL中的Thunk机制学习

发布: 2007-7-01 20:40 | 作者: admin | 来源: | 查看: 11次 | 进入软件测试论坛讨论

领测软件测试网

ATL利用一系列的类来管理窗口。为了使代码尽量紧凑而高效,ATL使用了一种有趣的技术来实现与窗口消息相关联的HWND和负责处理消息的对象的this指针之间的映射。具体过程如下:

 

在窗口注册时声明的窗口过程为此窗口对应的窗口类的静态成员函数StartWindowProc,当第一条消息到达此函数时,其处理如下:

 

template <class TBase, class TWinTraits>

LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

         CWindowImplBaseT< TBase, TWinTraits >* pThis =

(CWindowImplBaseT< TBase, TWinTraits >*)_Module.ExtractCreateWndData();

         ATLASSERT(pThis != NULL);

         pThis->m_hWnd = hWnd;

         pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);

         WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk);

         WNDPROC pOldProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);

#ifdef _DEBUG

         // check if somebody has subclassed us already since we discard it

         if(pOldProc != StartWindowProc)

                   ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));

#else

         pOldProc;  // avoid unused warning

#endif

         return pProc(hWnd, uMsg, wParam, lParam);

}

 

它先由全局变量_Module中取得此窗口对应的窗口类的this指针,然后通过m_thunk运用汇编指令改造此窗口类的窗口过程成员函数。m_thunk是CWndProcThunk的实例,每个窗口类各有一个。它的定义如下:

 

class CWndProcThunk

{

public:

         union

         {

                   _AtlCreateWndData cd;

                   _WndProcThunk thunk;

         };

         void Init(WNDPROC proc, void* pThis)

         {

#if defined (_M_IX86)

                   thunk.m_mov = 0x042444C7;  //C7 44 24 0C

                   thunk.m_this = (DWORD)pThis;

                   thunk.m_jmp = 0xe9;

                   thunk.m_relproc = (int)proc - ((int)this+sizeof(_WndProcThunk));

#elif defined (_M_ALPHA)

                   thunk.ldah_at = (0x279f0000 | HIWORD(proc)) + (LOWORD(proc)>>15);

                   thunk.ldah_a0 = (0x261f0000 | HIWORD(pThis)) + (LOWORD(pThis)>>15);

                   thunk.lda_at = 0x239c0000 | LOWORD(proc);

                   thunk.lda_a0 = 0x22100000 | LOWORD(pThis);

                   thunk.jmp = 0x6bfc0000;

#endif

                   // write block from data cache and

                   //  flush from instruction cache

                   FlushInstructionCache(GetCurrentProcess(), &thunk, sizeof(thunk));

         }

};

 

其Init()函数完成对WndProcThunk结构的初始化工作。WndProcThunk结构针对X86体系的定义如下:

 

struct _WndProcThunk

{

         DWORD   m_mov;          // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd)

         DWORD   m_this;         //

         BYTE    m_jmp;          // jmp WndProc

         DWORD   m_relproc;      // relative jmp

};

 

结构成员中保存的是一组汇编指令。在X86体系下,在Init()函数中这组汇编指令被初始化为下面的指令:

 

mov dword ptr [esp+0x4], pThis

jmp (int)proc - ((int)this+sizeof(_WndProcThunk))

 

它完成的功能是,用窗口类的指针pThis代替窗口句柄hWnd(esp+0x4中放的就是hWnd),然后跳转到传入的proc函数处((int)proc - ((int)this+sizeof(_WndProcThunk))是proc与thunk之间的距离)。

 

在调用完m_thunk.Init()函数之后,实际上就得到了经过改造的窗口过程(m_thunk.thunk),此窗口过程是窗口类的一个成员函数,它的第一个参数定义虽然是HWND,但实际上是它的类的this指针。最后使用SetWindowLong()用这个新的窗口过程替换掉原有的窗口过程(也就是StartWindowProc),以后的所有消息都会被路由给新的窗口过程。


文章来源于领测软件测试网 https://www.ltesting.net/


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备2023014753号-2
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网