学习ATL的一个习作 : )

类别:VC语言 点击:0 评论:0 推荐:

#include "stdafx.h"

template<typename ObjectType>
class Delegate
{
// Type Definitions
public:
 typedef LRESULT (ObjectType::*CallType)(HWND, UINT, WPARAM, LPARAM);

// Constructor
public:
 Delegate(ObjectType* pObject, CallType pCallee) : m_pObject(pObject), m_pCallee(pCallee)
 {
 }

// Destrcutor
public:
 ~Delegate()
 {
 }

// Thunk Structure
public:
 /* Adjust pack size */
 #pragma pack(push,1)
 struct Thunk
 {
  /* push ebp */
  BYTE m_pushebp;
  /* mov ebp, esp */
  BYTE m_movebp;
  BYTE m_esp;

  /* mov eax, dword ptr [ebp + 8] */
  BYTE m_moveax1;
  BYTE m_ebpplus1;
  BYTE m_offset1;
  
  /* push eax */
  BYTE m_pusheax1;

  /* mov eax, dword ptr [ebp + 12] */
  BYTE m_moveax2;
  BYTE m_ebpplus2;
  BYTE m_offset2;
  
  /* push eax */
  BYTE m_pusheax2;

  /* mov eax, dword ptr [ebp + 16] */
  BYTE m_moveax3;
  BYTE m_ebpplus3;
  BYTE m_offset3;
  
  /* push eax */
  BYTE m_pusheax3;

  /* mov eax, dword ptr [ebp + 20] */
  BYTE m_moveax4;
  BYTE m_ebpplus4;
  BYTE m_offset4;
  
  /* push eax */
  BYTE m_pusheax4;

  /* mov eax, this*/
  BYTE m_moveax5;
  void* m_this;

  /* push eax */
  BYTE m_pusheax5;

  /* mov eax, helper*/
  BYTE m_moveax6;
  void* m_helper;

  /* call eax */
  BYTE m_call;
  BYTE m_calleax;

  /* pop ebp */
  BYTE m_popebp;
  /* ret 10h */
   BYTE m_ret;
  DWORD m_10h;
 };
 /* Reset pack size */
 #pragma pack(pop)

// Properties
protected:
 Thunk  m_Thunk;
 ObjectType* m_pObject;
 CallType m_pCallee;

// Methods
public:
 operator WNDPROC(void)
 {
  void*  pf;

  __asm
  {
   mov  eax, Delegate<ObjectType>::Helper
   mov  pf, eax
  }

  /* push ebp */
  m_Thunk.m_pushebp = 0x55;
  
  /* mov ebp, esp */
  m_Thunk.m_movebp = 0x8B;
  m_Thunk.m_esp  = 0xEC;
  
  /* mov eax dword ptr [ebp + 20] */
  m_Thunk.m_moveax1 = 0x8B;
  m_Thunk.m_ebpplus1 = 0x45;
  m_Thunk.m_offset1 = 20;

  /* push eax */
  m_Thunk.m_pusheax1 = 0x50;

  /* mov eax dword ptr [ebp + 16] */
  m_Thunk.m_moveax2 = 0x8B;
  m_Thunk.m_ebpplus2 = 0x45;
  m_Thunk.m_offset2 = 16;

  /* push eax */
  m_Thunk.m_pusheax2 = 0x50;

  /* mov eax dword ptr [ebp + 12] */
  m_Thunk.m_moveax3 = 0x8B;
  m_Thunk.m_ebpplus3 = 0x45;
  m_Thunk.m_offset3 = 12;

  /* push eax */
  m_Thunk.m_pusheax3 = 0x50;

  /* mov eax dword ptr [ebp + 8] */
  m_Thunk.m_moveax4 = 0x8B;
  m_Thunk.m_ebpplus4 = 0x45;
  m_Thunk.m_offset4 = 8;

  /* push eax */
  m_Thunk.m_pusheax4 = 0x50;

  /* mov eax, this */
  m_Thunk.m_moveax5 = 0xB8;
  m_Thunk.m_this  = this;

  /* push eax */
  m_Thunk.m_pusheax5 = 0x50;

  /* mov eax, Delegate::Helper */
  m_Thunk.m_moveax6 = 0xB8;
  m_Thunk.m_helper = pf;
  
  /*call eax*/
  m_Thunk.m_call  = 0xFF;
  m_Thunk.m_calleax = 0xD0;

  /* pop ebp */
  m_Thunk.m_popebp = 0x5D;
  
  /* ret 10h */
  m_Thunk.m_ret  = 0xC2;
  m_Thunk.m_10h  = 0x10;

  return (LRESULT(CALLBACK*)(HWND, UINT, WPARAM, LPARAM))&m_Thunk;
 }

 HRESULT CALLBACK Helper(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
 {
  return (m_pObject->*m_pCallee)(hWnd, uMessage, wParam, lParam);
 }
};

class CWindow
{
public:
 virtual LRESULT WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
 {
  if(uMessage==WM_DESTROY)
  {
   ::PostQuitMessage(0);
  }

  return ::DefWindowProc(hWnd, uMessage, wParam, lParam);
 }
};

class CMyWindow : public CWindow
{
public:
 virtual LRESULT WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
 {
  if(uMessage==WM_LBUTTONDOWN)
  {
   ::MessageBox(hWnd, "ok", "ok", MB_OK);
  }

  return CWindow::WndProc(hWnd, uMessage, wParam, lParam);
 }
};

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
 CMyWindow theWindow;

 CWindow* pWindow = &theWindow;

 Delegate<CWindow> theDelegate(pWindow, CWindow::WndProc);

 WNDCLASSEX wcex;

 wcex.cbSize   = sizeof(WNDCLASSEX);
 wcex.cbClsExtra  = 0;
 wcex.cbWndExtra  = 0;
 wcex.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
 wcex.hCursor  = ::LoadCursor(NULL, IDC_ARROW);
 wcex.hIcon   = ::LoadIcon(NULL, IDI_APPLICATION);
 wcex.hIconSm  = wcex.hIcon;
 wcex.hInstance  = ::GetModuleHandle(NULL);

 // Replaced with a member function delegation
 wcex.lpfnWndProc = theDelegate;

 wcex.lpszClassName = "TestClass";
 wcex.lpszMenuName = NULL;
 wcex.style   = CS_VREDRAW | CS_HREDRAW;

 ::RegisterClassEx(&wcex);


 HWND hWnd = ::CreateWindow("TestClass",
          "TestWindow",
          WS_OVERLAPPEDWINDOW | WS_VISIBLE,
          0, 0,
          320, 240,
          NULL, NULL,
          ::GetModuleHandle(NULL), NULL);

 ::UpdateWindow(hWnd);


 MSG msg;

 while(::GetMessage(&msg, NULL, 0, 0))
 {
  ::TranslateMessage(&msg);
  ::DispatchMessage(&msg);
 }

 ::ExitProcess(0);
}

本文地址:http://com.8s8s.com/it/it2126.htm