。。。。。。
最初想用lpCreateParams分发,但是后来发现WM_CREATE之前还有几个消息,不完美。
后来想到这几个消息都是用SendMessage发送的,而SendMessage在同一个线程之内是用直接调用WndProc的方式发送的,也就是说CreateWindow与WndProc被调用之间不会被其它窗口的消息打断,所以直接用【单线程技巧】使用静态变量传递this指针即可。
头文件:
<code class="language-cpp">// MessageWindow.h #pragma once #include <cstdint> #include <windows.h> namespace Win32 { using std::intptr_t; using std::uintptr_t; struct Win32Error { unsigned errcode; Win32Error(unsigned errcode = GetLastError()) { this->errcode = errcode; }; }; struct UnexpectedError { }; /////////////////////////////////////////////////////////////////// // 脏活开始 class HwndMessageSink { public: // 窗口句柄,由于常常需要在外部访问,因此定义为public HWND m_hwnd; public: // 可以转换为HWND operator HWND() { return m_hwnd; } // 构造函数 HwndMessageSink() : m_hwnd(nullptr) { } // 析构前我们需要尽可能地销毁窗口,以避免指针悬空 virtual ~HwndMessageSink() { if (m_hwnd) DestroyWindow(m_hwnd); } protected: // 消息分发目的函数 virtual intptr_t MessageHandler(unsigned msg, uintptr_t wParam, intptr_t lParam) = 0; // TODO public: // 获取静态WNDPROC/DLGPROC static void *GetMessageDispatcher() { return MsgDispatcher; } // 获取所需cbWndExtra大小 static int GetRequiredWindowExtra() { return DLGWINDOWEXTRA; } protected: // 设置静态变量 static void SetMessageDispatcherThisPointer(HwndMessageSink *obj) { RefStaticThisPointer() = obj; } private: // 静态变量定义(类中的静态变量其实是全局变量,因此这里只能定义在函数中) static HwndMessageSink *&RefStaticThisPointer() { __declspec(thread) static HwndMessageSink *s_pobj = nullptr; return s_pobj; } // 消息对象分发的核心函数,本程序中最脏的活 static intptr_t __stdcall MsgDispatcher( HWND hwnd, unsigned msg, uintptr_t wParam, intptr_t lParam) { // 本函数中用来当做this指针的变量,先试图从DWLP_USER取出 HwndMessageSink *pthis = (HwndMessageSink *)GetWindowLongPtr(hwnd, DWLP_USER); if (RefStaticThisPointer() != nullptr && pthis == nullptr) { // 如果没有设置DWLP_USER但设置了静态变量 // 试图从静态变量取出 pthis = RefStaticThisPointer(); // 然后将静态变量置零 RefStaticThisPointer() = nullptr; // 最后将pthis存入DWLP_USER SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pthis); } if (pthis) { // 如果这时候解决了pthis // 更新m_hwnd,保证分发之后可以立即使用m_hwnd pthis->m_hwnd = hwnd; // 调用MessageHandler intptr_t retval = pthis->MessageHandler(msg, wParam, lParam); if (msg == WM_DESTROY) { // 如果是WM_DESTROY,则表示窗口已经销毁 // 置空m_hwnd以防止悬空的句柄和重复销毁 pthis->m_hwnd = nullptr; } // 返回应该返回的值 return retval; } else { // 如果这时候还没有获取到有效的pthis,说明没有执行SetMessageDispatcherThisPointer throw UnexpectedError(); } } private: // 对象不允许被复制 HwndMessageSink(HwndMessageSink const&); HwndMessageSink &operator=(HwndMessageSink const&); }; // 脏活结束 ////////////////////////////////////////////// class Win32Window : public HwndMessageSink { public: static ATOM Register(unsigned dwClassStyle, HINSTANCE hInstance, HICON hIcon, HCURSOR hCursor, HBRUSH hbrBackground, const wchar_t *lpszMenuName, const wchar_t *lpszClassName, HICON hIconSm, int cbClsExtra = 0, int cbWndExtraAddition = 0) { WNDCLASSEX wcex = { sizeof wcex, dwClassStyle, (WNDPROC)GetMessageDispatcher(), cbClsExtra, GetRequiredWindowExtra() + cbWndExtraAddition, hInstance, hIcon, hCursor, hbrBackground, lpszMenuName, lpszClassName, hIconSm }; return RegisterClassEx(&wcex); } bool Create(unsigned dwExStyle, const wchar_t *lpszClassName, const wchar_t *lpszWindowName, unsigned dwWindowStyle, int x, int y, int cx, int cy, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, void *lpParam) { SetMessageDispatcherThisPointer(this); m_hwnd = CreateWindowEx(dwExStyle, lpszClassName, lpszWindowName, dwWindowStyle, x, y, cx, cy, hWndParent, hMenu, hInstance, lpParam); return m_hwnd != nullptr; } protected: virtual intptr_t MessageHandler(unsigned msg, uintptr_t wParam, intptr_t lParam) { return DefWindowProc(m_hwnd, msg, wParam, lParam); } }; class Win32Dialog : public HwndMessageSink { protected: bool m_ismodal; public: Win32Dialog() : m_ismodal(false) {} intptr_t DoModal(HINSTANCE hInstance, const wchar_t *lpTemplateName, HWND hWndParent, intptr_t dwInitParam) { m_ismodal = true; SetMessageDispatcherThisPointer(this); return DialogBoxParam(hInstance, lpTemplateName, hWndParent, (DLGPROC)GetMessageDispatcher(), dwInitParam); } intptr_t DoModal(HINSTANCE hInstance, unsigned short idTemplateName, HWND hWndParent, intptr_t dwInitParam) { m_ismodal = true; SetMessageDispatcherThisPointer(this); return DialogBoxParam(hInstance, MAKEINTRESOURCE(idTemplateName), hWndParent, (DLGPROC)GetMessageDispatcher(), dwInitParam); } bool Create(HINSTANCE hInstance, const wchar_t *lpTemplateName, HWND hWndParent, intptr_t dwInitParam) { m_ismodal = false; SetMessageDispatcherThisPointer(this); return nullptr == CreateDialogParam(hInstance, lpTemplateName, hWndParent, (DLGPROC)GetMessageDispatcher(), dwInitParam); } bool Create(HINSTANCE hInstance, unsigned short idTemplateName, HWND hWndParent, intptr_t dwInitParam) { m_ismodal = false; SetMessageDispatcherThisPointer(this); return nullptr == CreateDialogParam(hInstance, MAKEINTRESOURCE(idTemplateName), hWndParent, (DLGPROC)GetMessageDispatcher(), dwInitParam); } protected: virtual intptr_t MessageHandler(unsigned msg, uintptr_t wParam, intptr_t lParam) { if (msg == WM_CLOSE) { if (m_ismodal) EndDialog(m_hwnd, IDCANCEL); else DestroyWindow(m_hwnd); return true; } return false; } }; } </windows.h></cstdint></code>
主程序:
<code class="language-cpp">// main.cpp #include <windows.h> #include "MessageWindow.h" #include "resource.h" HINSTANCE hInst; class MyWindow : public Win32::Win32Window { intptr_t MessageHandler(unsigned msg, uintptr_t wParam, intptr_t lParam) { if (msg == WM_RBUTTONDOWN) { Win32::Win32Dialog dlg; dlg.DoModal(hInst, IDD_DIALOG1, m_hwnd, 0); } if (msg == WM_DESTROY) { PostQuitMessage(0); return 0; } return Win32::Win32Window::MessageHandler(msg, wParam, lParam); } }; int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE, char *szCmdLine, int nShowCmd) { hInst = hInstance; MyWindow wnd; wnd.Register(CS_VREDRAW|CS_HREDRAW, hInstance, LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW), (HBRUSH)GetStockObject(WHITE_BRUSH), nullptr, L"MainWndClass", LoadIcon(nullptr, IDI_APPLICATION)); wnd.Create(0, L"MainWndClass", L"Main Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr); ShowWindow(wnd, nShowCmd); UpdateWindow(wnd); Win32::Win32Dialog dlg; dlg.Create(hInst, IDD_DIALOG1, wnd, 0); ShowWindow(dlg, SW_SHOW); MSG msg = {}; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } </windows.h></code>
[修改于 8年0个月前 - 2016/12/19 03:01:11]
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。