跟我一起学Windows界面封装(三) 之 前奏篇:窗口过程函数(上)

窗口过程函数 

         好,终于进入正题了。

         在用MFC的时候,我们会发现MFC里面有消息映射,这么每个窗口类可以处理响应窗口消息,ATL也同样有自己的消息分发机制。由于窗口过程函数是全局函数(或静态函数),我们不可能吧一个程序的所有消息都在一个函数里面写,同时这个全局函数也没法和所有具体的窗口实例想绑定,即想调用具体类的成员函数都没办法实现,这样完成一个具有复杂功能的窗口程序也是不可能的了,我们上面的封装也一点意义都没了。为此,我们必须建立一个消息分发机制。

(1)方法1:映射表

         在窗口过程函数参数中,我们看到有一个HWND参数,这是能让我们知道是哪个窗口发来的。由于HWND句柄是全局唯一不重复的,也和我们窗口实例有着一一对应的关系。由此,我们就想到可以维护一个全局的Map,如Map,这样将HWND和窗口实例对象This指针建立一个映射表,进而就能够将消息分发到具体的窗口类了。

         MFC就采用该方式,其维护了一个全局的哈希表来实现,代码就不再深究了。

         在不计效率的情形下实现方法可如下:

  • _XWinModule中定义map 成员;
  • XWindowImpl的Create中首先将this指针保存到全局的临时指针中;
  •  然后Create会调用CreateWindow,CreateWindow执行过程中会发送WM_CREATE、WM_NCCREATE等消息,我们窗口过程函数起始位置将HWND和之前临时区的this指针一起存到map中即可。有的朋友会说,你怎么知道this和hwnd是对应的,我想说我们的窗口过程是单线程的,而且保存完this后会马上执行createwindow,进而进入窗口过程函数中,这样改HWND肯定是和this是对应的。
  • 后面就可以在窗口过程函数里面将消息分发到具体的实例中了。

 

部分代码如下:

XMoudle增加:

std::map m_MapObject;   // 保存映射关系的map
void* pTempThis;		    // 保存临时this的指针
void* AddXObject(void* pThis, HWND hWnd/* == nullptr*/)
    {
        if (hWnd == nullptr)
        {
            pTempThis = pThis;
            return pTempThis;
        }
        else
        {
            ATLASSERT(pTempThis != nullptr);
            m_MapObject.insert(std::make_pair(hWnd, pTempThis));
            void* p = pTempThis;
            pTempThis = nullptr;
            return p;
        }
    }
    void* GetXObject(HWND hWnd)
    {
        std::map::iterator it = m_MapObject.find(hWnd);
        if (it != m_MapObject.end())
        {
            return it->second;
        }
        else
        {
            return nullptr;
        }
    }

注:实例中暂时不考虑多线程,否则就需要假如Thread ID等来保证线程安全。

然后再在XWindowImpl的Create第一行代码将this添加到module中去。

BOOL Create(int nCmdShow)
    {
        _XModule.AddXObject(this, nullptr);
       … …
    }
随后接收到消息中会进入WndProc,同时也会在第一条消息时将hwnd添加进去并和之前的this相对应,这样之后所有的消息都可以通过map查找到this并调用消息处理成员函数ProcessMessage
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        void* p = _XModule.GetXObject(hWnd);
        if (p == nullptr)
        {
            p = _XModule.AddXObject(nullptr, hWnd);
            ATLASSERT(p != nullptr);
        }

        XWindowImpl* pXWin = (XWindowImpl*)p;
        return pXWin->ProcessMessage(hWnd, message, wParam, lParam);
    }

LRESULT ProcessMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_CLOSE:
            DestroyWindow();
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return ::DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }

//注意:ProcessMessage()已经是类的成员函数了,不再是static函数了,因此进来的消息都是和自己相关的,不是自己的消息不会进入该函数。

 
 

你可能感兴趣的:(C/C++,Windows开发)