Win32:更多"object oriented"窗口消息处理系统
Win32: More "object oriented" window message handling system
在Win32 API中,一个窗口有一个指针,指向一个用户定义的WndProc函数的版本,用来处理它的消息。
有一些方法可以用MFC消息映射等解决方案来覆盖这种低级机制。
在我的小应用程序中,我正在寻找一种方法来封装这个低级的东西与面向对象的解决方案。
我试图用HWND键和"MyWindowClass"项目创建一个c++地图,当我创建MyClass的对象时,我向地图添加了一对,然后通过HWN寻找MyWindowClass对象。但是问题是在CreateWindowEx调用Win32内部发送WM_CREATE消息到刚刚创建的窗口之后,所以我不能在此消息之前在映射中添加pair,也不能通过将其传递给实例化的WndProc对象来控制WM_CREATE。
代码是:
#ifndef NOTIFYWINDOW_H
#define NOTIFYWINDOW_H
#include "Bacn.h"
class NotifyWindow
{
private:
HWND m_hWnd;
Gdiplus::Graphics* m_graphics;
protected:
static std::map<HWND, NotifyWindow*> s_NotifyWindows;
static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void s_WndMessageLoop();
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void Initialize();
void OnPaint();
void OnCreate();
public:
NotifyWindow();
~NotifyWindow();
};
#endif //NOTIFYWINDOW_H
及其实现:
#include "NotifyWindow.h"
using namespace Gdiplus;
using namespace std;
map<HWND*, NotifyWindow> NotifyWindow::s_NotifyWindows;
LRESULT CALLBACK NotifyWindow::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
map<HWND, NotifyWindow*>::iterator search = s_NotifyWindows.find(hWnd);
if (search != s_NotifyWindows.end())
{
search->second->WndProc(uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void NotifyWindow::s_WndMessageLoop()
{
}
LRESULT NotifyWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
OnCreate();
break;
case WM_PAINT:
OnPaint();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
break;
case WM_SETFOCUS:
break;
case WM_KILLFOCUS:
break;
case WM_MOUSEMOVE:
break;
default:
return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}
return 0;
}
void NotifyWindow::Initialize()
{
WNDCLASSEX wc;
const wchar_t *className = L"BacnNotifyWindowClass";
const wchar_t *windowName = L"BacnNotifyWindow";
HINSTANCE hInstance = GetModuleHandle(NULL);
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpszClassName = className;
wc.lpfnWndProc = NotifyWindow::s_WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClassEx(&wc);
DWORD dwExtStyle = WS_EX_TOPMOST;
DWORD dwStyle = WS_POPUP | WS_SYSMENU;
m_hWnd = CreateWindowEx(
dwExtStyle,
className,
windowName,
dwStyle,
300,
300,
100,
100,
NULL,
NULL,
hInstance,
NULL);
s_NotifyWindows.insert(pair<HWND, NotifyWindow*>(m_hWnd, this));
ShowWindow(m_hWnd, SW_SHOW);
}
NotifyWindow::NotifyWindow()
{
Initialize();
}
NotifyWindow::~NotifyWindow()
{
}
void NotifyWindow::OnPaint()
{
}
void NotifyWindow::OnCreate()
{
}
建议:在你的窗口基类中设置WndProc
为虚拟的。请求Windows为每个窗口实例分配足够大的内存来存储一个指针(使用cbWndExtra
)。当创建一个窗口时,使用SetWindowLongPtr
将一个指向你的窗口类对象的指针放入与每个窗口实例相关的额外内存中。在static sWndProc
中,使用GetWindowLongPtr
检索该指针并调用窗口基类函数virtual WndProc
。在我看来,这比拥有一个专门用于调度WndProc
调用的整个额外map对象更简洁。
编辑:另外,你确实意识到,在你的代码中,你试图注册Windows窗口类每次你创建你的窗口类的对象?如果您只创建一个窗口,我想这在技术上是可以的,但即使这样,它也是容易出错的设计。Windows窗口类应该只注册一次,而不是每次用这个Windows窗口类创建一个窗口。
编辑:同样,在你的代码中,如果你没有在WndProc
中处理Windows消息,你的代码将为这个消息调用DefWindowProc
两次:第一次在switch
子句中的成员函数中,第二次在static sWndProc
中。DefWindowProc
不应该在同一条消息上被调用两次。
编辑:对不起,我之前不知怎么错过了你的实际问题,我以为你的帖子是关于设计的,而不是关于WM_CREATE
的。为了以统一的方式处理WM_NCCREATE
、WM_NCCALCSIZE
或WM_CREATE
,您可以在调用CreateWindowEx
时将lpParam
设置为指向窗口类对象的指针。该参数将传递给static sWndProc
,作为CREATESTRUCT
与WM_NCCREATE
和WM_CREATE
的成员。你可以在static sWndProc
中处理WM_NCCREATE
(第一个要发送的消息),获得指向对象的指针,使用SetWindowLongPtr
将其放入窗口实例的额外内存中,然后使用它来调用成员函数WndProc
(如果从其构造函数调用CreateWindowEx
,请注意调用未完全创建的窗口类对象)。这样,您就不需要担心程序中其他地方的"低级"Windows消息调度。当然,您仍然需要成员函数WndProc
来将消息分派给实际的函数调用。
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- MFC 中的窗口消息管理:添加基类调用是否是强制性的?
- clang++ 是否以更轻松的方式处理系统标头?
- 为什么初始化 Wintab 扩展后没有收到WT_PACKETEXT窗口消息?
- 静态链接如何处理系统文件?
- 为什么调用单例类 Qt 消息处理程序成员函数会出现错误:缺少参数列表
- MFC编辑控制消息处理访问文档对象
- 使用非静态消息处理程序获取GSTREAMER总线消息
- 当我最大化子窗口时,系统菜单消失
- MFC单选按钮组消息处理程序
- 如何使用 c++ 在窗口中获取系统信息
- 资源窗口在其他系统上无法正常工作 (Visual Studio 2012)
- 窗口后台处理程序究竟如何确定它将发送到打印处理器的数据类型?
- 窗口如何处理加载两个不同版本的 DLL
- 在Internet Explorer_Server(IE9)中处理窗口消息
- 如何在 wndproc 消息处理程序中在窗口下触发 jit 调试器
- 处理系统键关闭消息时禁用烦人的声音
- Win32:更多"object oriented"窗口消息处理系统
- 消息处理程序未调用窗口过程
- 在 COleControl 中未处理的 LButtonUp 窗口消息