Duilib interface library message flow analysis

Compared with the duilib source code, we mainly look at the processing of message distribution in the CWindowWnd class and the CPaintManagerUI class.

1. MessageLoop function of CPaintManagerUI class

void CPaintManagerUI::MessageLoop()  
{  
    MSG msg = { 0 };  
    while( ::GetMessage(&msg, NULL, 0, 0) ) {    //获取消息  
        if( !CPaintManagerUI::TranslateMessage(&msg) ) { //消息过滤  
            ::TranslateMessage(&msg);  
            ::DispatchMessage(&msg); //分发到窗口的消息处理窗口中. 也就是调用CWindowWnd类的__WndProc函数或是__ControlProc函数.  
        }  
    }  
}

The message is first received by the TranslateMessage message of the CPaintManagerUI class.

2. Call CWindowWnd::Create to create a window

Create mainly completes the following operations:

  • If you want to subclass the control of Window (that is, the control of the system, not the analog control of duilib), set the __ControlProc function as the message callback function.
  • Without subclassing, register the window class. At this time, set __WndProc as the window message processing callback function.
  • Create a window with the CreateWindowEx API function.

Note:
__WndProc function definition:

LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
    CWindowWnd* pThis = NULL;  
    if( uMsg == WM_NCCREATE ) { //要在此消息中把类于窗口进行绑定  
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); //来自于CreateWindowEx函数的最后一个参数( 也就是CWindowWnd对象指针了 )  
        pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);  
        pThis->m_hWnd = hWnd;  
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); //设置到窗口的用户数据中  
    }   
    else {  
        pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));  
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {  
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);  //收到窗口能处理到的最后一个消息了, 要进行收尾工作了.  
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);  //取消类对象与窗口的绑定关系  
            if( pThis->m_bSubclassed ) pThis->Unsubclass();  
            pThis->m_hWnd = NULL;  
            pThis->OnFinalMessage(hWnd);  
            return lRes;  
        }  
    }  
    if( pThis != NULL ) {  
        return pThis->HandleMessage(uMsg, wParam, lParam);  //在此调用继承类的消息处理函数  
    }   
    else {  
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam); //未绑定类对象, 就调用默认的窗口消息处理函数  
    }  
}

The message is received by __WndProc for the second time, and then passed to the HandlerMessage function of the CWindowWnd class.

3. The implementation of the HandlerMessage virtual function by the window inheritance class of the CWindowWnd class

LRESULT CMainWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )  
{  
    LRESULT lRes = 0;        //消息处理返回值.  
    BOOL    bHandled = TRUE; //消息是否要继续往下传.  
    switch ( uMsg )  
    {  
    case WM_CREATE: 
        lRes = OnInitResource( bHandled );  //进行初始化工作. 比如最重要的XML加载解析工作. 
        break;  
    default:  
        bHandled  = FALSE;  
        break;
    }  

    if ( bHandled )  
    {  
        return lRes;  
    }  

    //传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作  
    if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) )    
    {  
        return lRes;  
    }  

    //没处理过的就调用CWindowWnd类的默认消息处理函数吧. 
    return CWindowWnd::HandleMessage( uMsg, wParam, lParam );   
}

Here, the user needs to perform specific processing according to the message. Then it will be passed to the MessageHandler function of the CPaintManagerUI class object. The unprocessed message will be returned to the default message handler function of the CWindowWnd class for processing.

4. TranslateMessage, MessageHandler function of CPaintManagerUI class

BOOL CPaintManagerUI::TranslateMessage(const LPMSG pMsg)  
{  
    HWND hwndParent = ::GetParent(pMsg->hwnd); //获取消息接收窗口的父窗口  
    UINT uStyle = GetWindowStyle(pMsg->hwnd); //获取窗口的样式  
    LRESULT lRes = 0;  
    for( int i = 0; i < m_aPreMessages.GetSize(); i++ ) { //这个m_aPreMessage保存着CPaintManagerUI类对象.   
        CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);  
        if( pMsg->hwnd == pT->GetPaintWindow() //消息是否属于当前CPaintManagerUI绑定的窗口  
         || (hwndParent == pT->GetPaintWindow() && ((uStyle & WS_CHILD) != 0)) ) //消息是否为当前窗口中窗口的消息, (如ActiveX控件 )  
        {  
            if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return TRUE; //此时就调用PreMessageHandler过滤函数.  
        }  
    }  
    return FALSE;  
}

m_aPreMessage is a static member variable, which is added to this variable when CPaintManagerUI::Init binds the window to this class.

5. CPaintManagerUI::PreMessageHandler message filter function

BOOL CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)  
{  
    // 遍历当前的消息过滤列表. m_aPreMessageFilter的元素为IMessageFilterUI接口.只一个虚函数MessageHandler.   
    // 用户可以添加此接口的继承类变量到m_aPreMessageFilters列表中. ( 调用AddMessageFilter函数实现 )  
    for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ )   
    {  
        BOOL bHandled = FALSE;  
        LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);  
        if( bHandled ) {  
            return TRUE;  
        }  
    }  
    // 以下是对几个按键消息的过滤.  
    // WM_KEYDOWN     检查是否为VK_TAB键, 要进行控件焦点的移动.  
    // WM_SYSCHAR     获取与wParam中的字符加速键匹配的控件, 并激活它.  
    // WM_SYSKEYDOWN  生成控件事件( 用TEventUI来模拟 )  
}

6. CPaintManagerUI::MessageHandler function

  1. Traverse the IMessageFilterUI interface in the m_aMessageFilters list, and call the MessageHandler function to perform the related message filtering function again. (Similar to m_aPreMessageFilters above)

  2. The window's WM_PAINT message is handled here. The appearance and status of all controls are displayed.

  3. Handle mouse events, implement control activation and related events.

  4. To process the WM_TIMER message, all controls use the functions of SetTimer and KillTimer of CPaintManagerUI to implement the timer function.

  5. Process the custom messages of the CPaintManagerUI class, WM_APP + 1 and +2,
    WM_APP + 1 is used for the control to delay the destruction of the control object
    WM_APP + 2 to destroy the asynchronous message processing.
    (The asynchronous control message uses the CPaintManagerUI::SendNotify function to add the message object To the m_aAsyncNotify list, then PostMessage function WM_APP + 2)

  6. Processing of other basic window-related messages.
    CPaintManagerUI calls the Event function of the CControlUI class in the form of TEventUI structure to deliver the events inside DUILIB.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324520624&siteId=291194637