Win32 No-MFC中的消息映射

who*_*hoi 5 winapi message map

我怎么能创建类似的结构来处理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()
Run Code Online (Sandbox Code Playgroud)

BEGIN_MESSAGE_MAP宏处理此行为.怎么做纯Win32?

jus*_*sij 13

以下是我在Zeus程序员编辑器中使用的代码的简要总结:

步骤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);
Run Code Online (Sandbox Code Playgroud)

第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);
};
Run Code Online (Sandbox Code Playgroud)

步骤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);        \                              
     }                                         \                              
   };
Run Code Online (Sandbox Code Playgroud)

第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);
}
Run Code Online (Sandbox Code Playgroud)

步骤5:定义静态窗口过程方法(注意:首次注册类时,此方法需要用作窗口类的Window过程):

LRESULT CALLBACK xWindow::wndProc(HWND hwnd, UINT msg, 
                                  WPARAM wParam, 
                                  LPARAM lParam)
{
  LRESULT lResult = 0;

  //-- look for the creation message
  if (msg == WM_NCCREATE)
  {
    CREATESTRUCT *pCreateData = (CREATESTRUCT*)lParam;

    //-- get the window object passed in
    xWindow *pWindow = (xWindow)pCreateData->lpCreateParams;

    if (pWindow)
    {
      //-- attach the window object to the hwnd
      SetWindowLong(hwnd, pWindow);

      //-- let the window object dispatch the message
      pWindow->dispatch(hwnd, msg, wParam, lParam, lResult);
    }
    else
    {
      //-- leave the message to windows
      lResult = DefWindowProc(hwnd, msg, wParam, lParam);
    }
  }
  else if (hwnd)
  {
    //-- get the object attached to the hwnd
    xWindow *pWindow = (xWindow *)GetWindowLong(hwnd);

    //-- check to see if we have an object window attached to the handle
    if (pWindow)
    {
      //-- let the window object dispatch the message
      pWindow->dispatch(hwnd, msg, wParam, lParam, lResult);
    }
    else
    {
      //-- leave the message to windows
      lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
    }
  }

  return lResult;
}
Run Code Online (Sandbox Code Playgroud)

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

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)
};
Run Code Online (Sandbox Code Playgroud)

编辑:此代码的工作原理.

秘密理解这个代码是如何工作的是要记住的WndProcXwindow的类也不过是Win32的传递给窗口过程RegisterClassEx当Win32的窗口登记.

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

调度方法甚至因为它无非就是包装的Windows消息转换成简单,移动方便结构,然后把它发送到dispatchToMsgMap方法.

现在看看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)
Run Code Online (Sandbox Code Playgroud)

此代码仅使用前面定义的宏.如果你仔细看看这些宏,你会发现上面的代码实际上是在创建一个dispatchToMsgMap方法.这与dispatch方法调用的dispatchToMsgMap方法完全相同.

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

  • 好吧,你的答案似乎最好的所有功能,谢谢 (4认同)
  • 上面发布的帖子中的代码来自我在编写Zeus for Windows编辑器时创建的Win32库.我只复制了一个非常大的库代码的一小部分,所以我不希望这个代码编译.例如,上面显示的xWindow类实际上是大约2000多行代码,所以自然它已经大大减少了.但我试图发布的是关于如何将Windows消息映射到C++方法的基本概念. (3认同)
  • 我编辑了帖子并添加了一些单词,试图更好地描述这段代码的实际工作方式. (2认同)