Winapi Win32 No MFC中的消息映射

Winapi Win32 No MFC中的消息映射,winapi,map,message,Winapi,Map,Message,如何创建类似的结构来处理Win32消息,就像在MFC中一样 在MFC中 BEGIN_MESSAGE_MAP(CSkinCtrlTestDlg, CDialog) //{{AFX_MSG_MAP(CSkinCtrlTestDlg) ON_BN_CLICKED(IDC_BROWSE, OnBrowse) ON_BN_CLICKED(IDC_DEFAULTSKIN, OnChangeSkin) ON_WM_DRAWITEM() ON_WM_MEASUREITEM

如何创建类似的结构来处理Win32消息,就像在MFC中一样

在MFC中

BEGIN_MESSAGE_MAP(CSkinCtrlTestDlg, CDialog)
    //{{AFX_MSG_MAP(CSkinCtrlTestDlg)
    ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
    ON_BN_CLICKED(IDC_DEFAULTSKIN, OnChangeSkin)
    ON_WM_DRAWITEM()
    ON_WM_MEASUREITEM()
    ON_WM_COMPAREITEM()
    ON_BN_CLICKED(IDC_CHECK3, OnCheck3)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP宏处理此行为。纯Win32怎么办

您可以使用类似std::map的东西。其中short是窗口消息,MessageFn是处理消息的函数。然后,您可以按如下方式处理消息:

if ( messageMap.find( uMsg ) != messageMap.end() )
{
   messageMap[uMsg]( wParam, lParam );
}
它不会很整洁,但是很容易实现,尽管您将在运行时而不是在编译时定义消息映射

另一个解决方案是通读MFC宏代码,看看微软是如何做到的

另一个解决方案是使用ATL,如果您想要类似MFC的行为而不需要额外的开销。您还可以查看ATL的宏定义,了解它们是如何实现的

编辑:您可以通过存储CommandMap和NotifyMap来解决WM_命令或WM_通知处理。然后将WM_命令处理程序设置为一个函数,该函数执行类似的操作,并通过CommandMap传递命令

您最大的问题是在消息中没有得到任何标识特定类实例的信息。如果您只需要hWnd,但可能需要存储hWnd到类实例的进一步全局映射,那么这不是问题


这只是一个解决方案。你可以用许多不同的方法来解决这个问题。我只是想为您提出一个想法。

MFC消息映射本身并不使用常规的WndProc。IIRC,它基于某种钩子机制

然而,我想将宏调整为普通的WndProc应该不是很难

想到的第一种方法是让宏创建消息id/处理程序函数对数组。更好的方法是:使用地图来提高性能

WndProc将在该数组中循环,以识别给定的
WM
,并执行相应的处理程序

您可能还希望
BEGIN_MESSAGE_MAP
宏模拟一个
switch
语句,其中,行上的每个
都是开关()内的一个
case


这应该太难了。

std::map这样的东西很难做到这一点。特别是,这要求映射中的每个项都具有相同的类型,但不同的消息具有采用不同数量参数的处理程序,因此指向它们的指针不是相同的类型

不过,您可能想看看windowsx.h中的消息破解宏(尤其是
HANDLE\u MSG
)。虽然这实际上只是为switch语句生成case's,但它仍然允许您编写类似于MFC消息映射的代码。

以下是我在程序员编辑器中用于执行此操作的代码的breif摘要:

步骤1:定义两个消息结构以保存Windows消息详细信息:

typedef struct
{
  MSG     msg;
  LRESULT lResult;
} xMessage;

struct xWM_COMMAND
{
  HWND hwnd;
  UINT Msg;
  WORD ItemID;
  WORD NotifyCode;
  HWND Ctl;
  LRESULT lResult;
};

//-- unpack a message buffer
#define MSG_UNPACK(var, id, msg) x##id *var = (x##id *)(msg);
步骤2:使用一些特殊方法定义一个基本窗口类:

class xWindow
{
protected:
  //-- windows callback function
  static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, 
                                  WPARAM wParam, 
                                  LPARAM lParam);

  //-- a message dispatch method
  void dispatch(HWND hwnd, UINT uMessageID, WPARAM wParam, 
                LPARAM lParam, LRESULT &Result);

  //-- method for command message dispatching
  virtual void dispatchToCmdMap(xMessage *pMessage);

  //-- method for windows message dispatching
  virtual void dispatchToMsgMap(xMessage *pMessage);
};
步骤3:定义几个宏来分派Windows消息:

#define BEGIN_MSG_MAP                          \
   protected:                                  \
   virtual void dispatchToMsgMap(xMessage *msg)\
   {                                           \
     if (msg->msg.message == WM_NULL)          \
     {                                         \
       return;                                 \
     }

#define MSG_HANDLER(meth, wm_msg)              \
     else if (msg->msg.message == wm_msg)      \
     {                                         \
       this->meth(msg);                        \
       return;                                 \
     }

#define END_MSG_MAP(base)                      \
     else if (msg->msg.message == WM_COMMAND)  \
     {                                         \                       
       this->dispatchToCmdMap(msg);            \                       
       return;                                 \                       
     }                                         \                       
     else if (msg->msg.message == WM_NOTIFY)   \                       
     {                                         \                       
       this->dispatchToNotifyMap(msg);         \                       
       return;                                 \                       
     }                                         \                       
                                               \                       
     base::dispatchToMsgMap(msg);              \                       
   };

#define BEGIN_CMD_MAP                          \
   virtual void dispatchToCmdMap(xMessage *msg)\
   {                                           \                              
     MSG_UNPACK(Cmd, WM_COMMAND, msg);         \                              
                                               \                              
     if (Cmd->ItemID == 0)                     \                              
     {                                         \                              
        /* not allowed */                      \                              
     }                                                                        

#define CMD_HANDLER(meth, cmd_id)              \
     else if (Cmd->ItemID == cmd_id)           \
     {                                         \                                
       this->meth(Cmd->ItemID);                \                                
     }                                                                          

#define END_CMD_MAP(base)                      \
     else                                      \                              
     {                                         \                              
       base::dispatchToCmdMap(msg);        \                              
     }                                         \                              
   };
步骤4:定义调度程序方法:

void xWindow::dispatch(HWND, UINT uMessageID, WPARAM wParam, 
                       LPARAM lParam, LRESULT &Result)
{
  xMessage message;

  //-- build up a message packet
  message.msg.message = uMessageID;
  message.msg.wParam  = wParam;
  message.msg.lParam  = lParam;
  message.lResult     = 0;

  //-- dispatch the message
  this->dispatchToMsgMap(&message);
}
第5步:定义静态窗口过程方法(注意:首次注册窗口类时,需要将此方法用作窗口类的窗口过程):

现在,使用这个基类可以定义一个新的窗口类,如下所示:

class MyWindow : public xWindow
{
protected:  
  //-- the WM_COMMAND message handlers
  virtual void onAdd(int);
  virtual void onDelete(int);

  //-- the WM_CLOSE message handler
  virtual void onClose(xMessage *pMessage);

  //-- the WM_SIZE message handler
  virtual void onSize(xMessage *pMessage);

public:
  //-- ctor and dtor
  MyWindow();
  virtual ~MyWindow();

  BEGIN_MSG_MAP
    //-- command message handlers
    CMD_HANDLER(onAdd   , IDPB_ADD   )
    CMD_HANDLER(onDelete, IDPB_DELETE)

    //-- other message handling
    MSG_HANDLER(onClose , WM_CLOSE)
    MSG_HANDLER(onSize  , WM_SIZE )
  END_MSG_MAP(xWindow)
};
编辑:此代码的工作原理。

理解这段代码如何工作的秘密在于记住xWindow类中的wndProc只不过是在注册Win32窗口时传递给RegisterClassEx的Win32窗口过程

现在,如果您查看wndProc代码,您将看到它进行了一些设置和检查,但通常它只会将Windows消息发送到dispatch方法

dispatch方法更简单,因为它只是将Windows消息打包成一个易于移动的结构,然后将其发送给DispatchTomsMap方法

现在查看MyWindow类,您将看到以下代码:

BEGIN_MSG_MAP    
   //-- command message handlers    
   CMD_HANDLER(onAdd   , IDPB_ADD   )    
   CMD_HANDLER(onDelete, IDPB_DELETE)    

   //-- other message handling    
   MSG_HANDLER(onClose , WM_CLOSE)    
   MSG_HANDLER(onSize  , WM_SIZE )  
END_MSG_MAP(xWindow)
这段代码只是使用前面定义的宏。如果仔细查看这些宏,您会发现上面的代码实际上是在创建DispatchTomsMap方法。这与dispatch方法调用的DispatchTomsMap方法完全相同


我知道这种处理Windows消息的方法确实有效,因为我在编辑器中使用了完全相同的方法。

为什么不查看页眉,看看那些宏扩展到什么?事实上,我很难查看和跟踪到根。我是Win32和MFCBut的初学者,这里缺少一些东西,例如,我想将一个函数绑定到特定的按钮单击事件。在你的建议中,每一个事件都指向一个单一的功能。应该有另一个参数,但我认为map还不够?好吧,你的答案似乎是所有功能中最好的,再次感谢你嗨,你编译了这个源代码吗?当我把这个加入到我的项目中时,我有很多错误吗?是否应该考虑编译问题?我上面帖子中的代码取自我在编写ZeusforWindows编辑器时创建的Win32库。我只复制了非常大的库代码的一小部分,所以我不希望编译此代码。例如,上面显示的xWindow类实际上是大约2000多行代码,因此它自然地被大大减少了。但我试图发布的是如何将Windows消息映射到C++方法的基本概念。我编辑了帖子并添加了几个单词,试图更好地描述该代码如何实际工作。这不是一个真正的问题;您可以将获得的原始WPARAM/LPARAM交给每个消息处理程序。这样,就可以将不同的强制转换移动到相应的消息处理程序。
BEGIN_MSG_MAP    
   //-- command message handlers    
   CMD_HANDLER(onAdd   , IDPB_ADD   )    
   CMD_HANDLER(onDelete, IDPB_DELETE)    

   //-- other message handling    
   MSG_HANDLER(onClose , WM_CLOSE)    
   MSG_HANDLER(onSize  , WM_SIZE )  
END_MSG_MAP(xWindow)