这里使用的Duilib库为Duilib_Ultimate
查考: https://blog.youkuaiyun.com/bureau123/article/details/122127080?spm=1001.2014.3001.5506
我推荐的视频duilib视频教程 迪大学院 duilib: http://www.didacollege.com/site-List/show-12-26.html
我的 QQ: 2402398917
WinMain
函数的内容如下
int WINAPI _tWinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPTSTR lpCmdLine, // command line
int nCmdShow) // show state
{
::CoInitialize(NULL);
CPaintManagerUI::SetInstance(hInstance);
MainWnd* pMainWnd = new MainWnd();
pMainWnd->Create(NULL, _T("我是标题"),
UI_WNDSTYLE_FRAME, NULL, /* 窗口风格 */
0, 0, 300, 300); // 看这里
pMainWnd->CenterWindow();
// pMainWnd->ShowModal();
CPaintManagerUI::MessageLoop();
CPaintManagerUI::Term();
::CoUninitialize();
return 0;
}
我们用ctrl看看Create的实现
pMainWnd->Create(NULL, _T("我是标题"),
UI_WNDSTYLE_FRAME, NULL, /* 窗口风格 */
0, 0, 300, 300);
Create的实现如下, 这里我们主要看RegisterWindowClass
HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
if( GetSuperClassName() == NULL && !RegisterWindowClass() /*看这里*/ ) return NULL;
if(m_bUnicode) {
#ifndef UNICODE
LPWSTR lpClassName = a2w((char*)GetWindowClassName());
LPWSTR lpName = a2w((char*)pstrName);
#else
RegisterWindowClass
的实现如下, 这里我们主要看__WndProc
bool CWindowWnd::RegisterWindowClass()
{
WNDCLASS wc = { 0 };
wc.style = GetClassStyle();
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hIcon = NULL;
wc.lpfnWndProc = CWindowWnd::__WndProc; // 看这里
wc.hInstance = CPaintManagerUI::GetInstance();
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = GetWindowClassName();
ATOM ret = ::RegisterClass(&wc);
ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}
__WndProc
的实现如下, 这里我们主要看HandleMessage
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);
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);
}
}
下面是CWindowWnd
的HandleMessage
实现
LRESULT CWindowWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
}
由m_oldWndProc名称可知, 其为一个成员变量, 双击ctrl+q查看其使用, 可以发现其其实就是DefWindowProc
HandleMessage
是一个虚函数, WindowImplBase
也有基本实现
WindowImplBase
的基本实现如下, 这里的实现可以让我们通过HandleCustomMessage
或 OnCreate
来接管处理原生win32api消息
这里的重点是渲染器m_PaintMessager
的MessageHandler
if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes))
return lRes;
其实现的代码量很大,我们可以通过IDE的搜索功能发现其会调用Notify
, 也就是INotifyUI
接口
WindowImplBase
实现了INotifyUI
接口, 下面是其的具体实现
void WindowImplBase::Notify(TNotifyUI& msg)
{
return CNotifyPump::NotifyPump(msg);
}
这个消息泵的实现代码量很大,其作用是为消息做分发, 从而让我们WindowImplBase
的派生类可以使用下面的消息宏
// MainWnd.h
DUI_DECLARE_MESSAGE_MAP()
void OnSetFocus(TNotifyUI& msg);
// MainWnd.cpp
DUI_BEGIN_MESSAGE_MAP(MainWnd, WindowImplBase)
DUI_ON_MSGTYPE(DUI_MSGTYPE_SETFOCUS, OnSetFocus)
DUI_END_MESSAGE_MAP()
void MainWnd::OnSetFocus(TNotifyUI& msg)
{
if (msg.pSender->GetName() == _T("main-btn")) {
::MessageBox(GetHWND(), _T("设置焦点成功"), _T("我是标题"), MB_OK);
}
}
WindowImplBase
也有这个消息映射宏, 浏览代码时可以通过ctrl+k+o
在.cpp
和.h
中切换, 其作用是用于对名为closebtn
的按钮做默认处理的