龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > VC开发 >

MFC:thunk技术实现窗口类的封装[图](3)

时间:2009-12-30 15:42来源:未知 作者:admin 点击:
分享到:
这样m_thunk虽然是一个结构,但其数据是一段可执行的代码,而其类型又是WNDPROC,系统就会忠实地按窗口过程规则调用这段代码,m_thunk就把Window字段里记录

  这样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

  题外话:thunk的汇编代码全部写在注释里了,把这段汇编转成数据可费了不少劲,当时手头没有合适的工具,只有一本《8086/8088汇编语言程序设计》,根据附录中的指令码汇总表转成机器码数据,那里面根本没有EAX,ECX,ESP等的概念,只能连蒙带猜加调试,非法操作了n(n>10)回才得到那些数据,当时真是长出了一口气:TNND,终于搞定了!:-)

精彩图集

赞助商链接