首页
社区
课程
招聘
[旧帖] [原创]VS2005 动态按钮响应动态事件(交流) 0.00雪花
发表于: 2013-2-1 17:08 1074

[旧帖] [原创]VS2005 动态按钮响应动态事件(交流) 0.00雪花

2013-2-1 17:08
1074
来看雪这么久,一直是临时会员身份,也没有发表任何文章,真是惭愧。
前天通过邮箱找回了忘记的密码,希望以后再看雪这个大家庭中能够快速的成长。也希望各位兄弟姐妹能够多多帮助。最近研究驱动方面,希望在这个大

家庭中能够互相帮助,共同成长。

不罗嗦,直入主题:
此方法只在VS2005上测试通过,其他版本按照思路适当修改即可。
本人没有看过相关的文章,只是在分析MFC消息时候发现的,感觉用处也挺多的就做了分析,如有哪位大牛发过类似的文章,小弟深感抱歉。

1.动态按钮
其实这部分很简单,就是动态创建个按钮(其他控件类似,只那按钮开讲)。
关键是按钮可以动态的相应函数,这里我们就需要对MFC的消息进行分析了。
2.动态事件
在对话框模式下,我们发现MFC的消息是通过两个宏定义出的。我们只有添加相应的消息即可。
BEGIN_MESSAGE_MAP(CSmallGameDlg, CDialog)
  //{{AFX_MSG_MAP(CSmallGameDlg)
  ON_WM_SYSCOMMAND()
  //...
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

我们来研究下这两个宏。
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
  PTM_WARNING_DISABLE \
  const AFX_MSGMAP* theClass::GetMessageMap() const \
    { return GetThisMessageMap(); } \
  const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
  { \
    typedef theClass ThisClass;\
    typedef baseClass TheBaseClass;\
    static const AFX_MSGMAP_ENTRY _messageEntries[] =  \
    {

#define END_MESSAGE_MAP() \
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
  }; \
    static const AFX_MSGMAP messageMap = \
    { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
    return &messageMap; \
  }\

我们发现,其实我们在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP直接添加的消息宏 都会被编译器编译到 _messageEntries 这个今天数组里。
并且这个数组是以 {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 结尾的。系统通过查询这个数组里面绑定的空间ID和入口函数就可以动态调用到相应的函

数了。(大家可以自己研究下这两个宏,其实也就是两个函数,MFC把它们定义成宏 是为了我们好自己添加消息处理)

那我们就来改写这个宏。
#pragma warning( push )
#pragma warning( disable : 4005 )
#define END_MESSAGE_MAP( lpEntry ) \
        {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
      }; \
      static AFX_MSGMAP_ENTRY *pEntry = NULL;\
      if (pEntry == NULL &&  lpEntry != NULL)\
      {\
        pEntry = lpEntry;\
        for (int i=0;i<sizeof(_messageEntries)/sizeof(AFX_MSGMAP_ENTRY);i++)\
        {\
          pEntry[i] = _messageEntries[i];\
        }\
      }\
      static const AFX_MSGMAP messageMap = \
      { &TheBaseClass::GetThisMessageMap, pEntry }; \
      return &messageMap; \
    }\
    PTM_WARNING_RESTORE
#pragma warning( pop )

这里我们传进来 一个 lpEntry  这是个AFX_MSGMAP_ENTRY类型的指针。我们可以初始化为它分配足够大的空间,方便我们往里面添加消息处理。
首先在GetThisMessageMap 这个函数被第一次调用的时候我们会把 原来_messageEntries 里面的消息映射都拷贝到 lpEntry 里面。
为了方便在外部我们把lpEntry定义成一个全局的指针,在类构造的时候初始化给他分配个空间。在类析构的时候释放这个空间。当然定义成类成员变量

也可以。

这样我们就方便对消息进行处理了,动态绑定ID 函数。

这里我写好了几个函数也分享个大家
//DynamicControl.h

/*
 *DynamicControl.h
 *Code by LeoSky 2012-12-12
 */
#ifndef _DYNAMIC_CONTROL_H_
#define _DYNAMIC_CONTROL_H_

#define MAX_ENTRY_SIZE 256

class CDynamicControl
{
private:
  static AFX_MSGMAP_ENTRY *m_pEntry;
  static int m_nSize;
public:
  static AFX_MSGMAP_ENTRY * InitMsgEntry(int nSize = MAX_ENTRY_SIZE);
  static BOOL FreeMsgEntry();
  static void AddMsgEntry(AFX_MSGMAP_ENTRY msgEntry);
  static BOOL DeleteMsgEntry(AFX_MSGMAP_ENTRY msgEntry);
};

#pragma warning( push )
#pragma warning( disable : 4005 )
#define END_MESSAGE_MAP(lpEntry) \
        {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
      }; \
      static AFX_MSGMAP_ENTRY *pEntry = NULL;\
      if (pEntry == NULL &&  lpEntry != NULL)\
      {\
        pEntry = lpEntry;\
        for (int i=0;i<sizeof(_messageEntries)/sizeof(AFX_MSGMAP_ENTRY);i++)\
        {\
          pEntry[i] = _messageEntries[i];\
        }\
      }\
      static const AFX_MSGMAP messageMap = \
      { &TheBaseClass::GetThisMessageMap, pEntry }; \
      return &messageMap; \
    }\
    PTM_WARNING_RESTORE
#pragma warning( pop )

//Namespace Dynamic Control
namespace DynamicControl
{
  AFX_MSGMAP_ENTRY * InitMsgEntry(int nSize = MAX_ENTRY_SIZE);
  BOOL FreeMsgEntry();
  void AddMsgEntry(AFX_MSGMAP_ENTRY msgEntry);
  BOOL DeleteMsgEntry(AFX_MSGMAP_ENTRY msgEntry);
}

using namespace DynamicControl;

#define _ADD_MSG_CVT(theClass,_msg) \
{\
  typedef theClass ThisClass;  \
  AFX_MSGMAP_ENTRY _messageEntries[] = \
  {\
    _msg\
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }\
  };\
  AddMsgEntry(_messageEntries[0]);\
}

#define _DEL_MSG_CVT(theClass,_msg) \
{\
  typedef theClass ThisClass;  \
  AFX_MSGMAP_ENTRY _messageEntries[] = \
  {\
    _msg\
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }\
  };\
  DeleteMsgEntry(_messageEntries[0]);\
}

#endif

//DynamicControl.cpp

#include "stdafx.h"
#include "DynamicControl.h"

AFX_MSGMAP_ENTRY *CDynamicControl::m_pEntry = NULL;
int CDynamicControl::m_nSize = 0;

AFX_MSGMAP_ENTRY * CDynamicControl::InitMsgEntry(int nSize)
{
  ASSERT(nSize > 0);
  m_pEntry = new AFX_MSGMAP_ENTRY[nSize];
  ASSERT(m_pEntry);
  m_nSize = nSize;
  memset(m_pEntry,0,nSize*sizeof(AFX_MSGMAP_ENTRY));
  return m_pEntry;
}
BOOL CDynamicControl::FreeMsgEntry()
{
  if (m_pEntry != NULL)
  {
    delete m_pEntry;
    m_pEntry = NULL;
    return TRUE;
  }
  return FALSE;
}
void CDynamicControl::AddMsgEntry(AFX_MSGMAP_ENTRY msgEntry)
{
  for (int i=0;i<m_nSize-1;i++)
  {
    if (m_pEntry[i].nMessage== msgEntry.nMessage && m_pEntry[i].nCode  == msgEntry.nCode  &&
      m_pEntry[i].nID    == msgEntry.nID     && m_pEntry[i].nLastID  == msgEntry.nLastID &&
      m_pEntry[i].nSig  == msgEntry.nSig   && m_pEntry[i].pfn    == msgEntry.pfn )
    {
      return;//Already exists
    }
    if (m_pEntry[i].nMessage== 0 && m_pEntry[i].nCode  == 0 &&
      m_pEntry[i].nID    == 0 && m_pEntry[i].nLastID  == 0 &&
      m_pEntry[i].nSig  == 0 && m_pEntry[i].pfn    == 0 )
    {
      m_pEntry[i] = msgEntry;
      break;
    }
  }
}

BOOL CDynamicControl::DeleteMsgEntry(AFX_MSGMAP_ENTRY msgEntry)
{
  for (int i=0;i<m_nSize-1;i++)
  {
    if (m_pEntry[i].nMessage== msgEntry.nMessage && m_pEntry[i].nCode  == msgEntry.nCode  &&
      m_pEntry[i].nID    == msgEntry.nID     && m_pEntry[i].nLastID  == msgEntry.nLastID &&
      m_pEntry[i].nSig  == msgEntry.nSig   && m_pEntry[i].pfn    == msgEntry.pfn )
    {
      memset(&m_pEntry[i],0,sizeof(AFX_MSGMAP_ENTRY));
      for (int j=i;j<m_nSize-1;j++)
      {
        m_pEntry[j] = m_pEntry[j+1];
      }
      return TRUE;
    }
  }
  return FALSE;
}

//Name Space
AFX_MSGMAP_ENTRY * DynamicControl::InitMsgEntry(int nSize)
{
  return CDynamicControl::InitMsgEntry(nSize);
}
BOOL DynamicControl::FreeMsgEntry()
{
  return CDynamicControl::FreeMsgEntry();
}
void DynamicControl::AddMsgEntry(AFX_MSGMAP_ENTRY msgEntry)
{
  CDynamicControl::AddMsgEntry(msgEntry);
}
BOOL DynamicControl::DeleteMsgEntry(AFX_MSGMAP_ENTRY msgEntry)
{
  return CDynamicControl::DeleteMsgEntry(msgEntry);
}

//////////////////////////////////////////////////////////////////////////////////////

这样我们就能动态绑定 按钮和函数了。
AFX_MSGMAP_ENTRY *G_LPENTRY = NULL;
const int  G_MAX_ENTRY_SIZE = 20;
#include "DynamicControl/DynamicControl.h"

CSmallGameDlg::CSmallGameDlg(CWnd* pParent /*=NULL*/)
  : CDialog(CSmallGameDlg::IDD, pParent)
{
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  G_LPENTRY = InitMsgEntry(G_MAX_ENTRY_SIZE);//初始化
  memset(&m_AppData,0,sizeof(m_AppData));
}
CSmallGameDlg::~CSmallGameDlg()
{
  FreeMsgEntry();//释放
}
//添加消息处理
_ADD_MSG_CVT(CSmallGameDlg,ON_BN_CLICKED(IDC_BUTTON_XXX, Fun));
//删除消息处理
_DEL_MSG_CVT(CSmallGameDlg,ON_BN_CLICKED(IDC_BUTTON_XXX, Fun));
是不是这样就完了呢? No、
我们发现,我们发现,这里的Fun是类成员函数。类型为__thiscall 类型。那我们又怎么绑定非类成员函数呢。

3.动态函数

MSDN有关于__thiscall的这样一句话
Arguments are pushed on the stack from right to left, with the this pointer being passed via register ECX, and not on the stack, on 

the x86 architecture. 
我们知道,this指针放在了ecx中。
那我们可以这么写了。 
void WINAPI OnTest() 
{
  CSmallGameDlg *pAppDlg = NULL;
  __asm
  {
    mov pAppDlg,ecx;
  }
  int nCounts = pAppDlg->m_nCounts;//获取类成员变量值.
}

AFX_PMSG pfn = NULL;
*(LPDWORD)&pfn = (DWORD)OnTest;
_ADD_MSG_CVT(CSmallGameDlg,ON_BN_CLICKED(IDC_BUTTON_SHOOT, pfn));

这样我们就可以直接使用这个pAppDlg指针了。
我在实践中,OnTest 动态分配在内存中都可以使用。但是要注意,“动态分配”时候不能用pAppDlg调用类成员函数的哦。只可以使用成员变量。
其实这些也就够了。我们取到窗口句柄,想怎么操作都行。发消息也是不错的选择。

至此全文结束。
ps:仅供交流。如有错误地方请指正,谢谢。代码仅供参考。欢迎指出错误。

[课程]Android-CTF解题方法汇总!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//