windows消息机制

作者: const27 分类: Windows相关, 发布时间: 2020-10-25 06:03

事件驱动

Windows是基于事件驱动的.
一般来讲, 服务器处理模型有三种:
1每收到一个请求,创建一个新的进程,来处理该请求;
2每收到一个请求,创建一个新的线程,来处理该请求;
3每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求

1 开销较大:每处理一个事件就要新建一个进程,开销太大,但是实现起来很简单
2 死锁问题:多线程调节容易遇到死锁问题,程序直接卡死
3 逻辑复杂

那么事件驱动的优势在哪里呢。
打个比方,我们要获取一个鼠标点击的动作。
如果我们通过创建线程或者进程的方法,去循环扫描当前是否有鼠标点击事件那么可能会造成资源浪费(鼠标一直不点击,但仍在进行扫描),响应缓慢(扫描的设备有很多,会造成响应缓慢的问题)等问题。
但是事件驱动就不一样了,它的核心原理是以消息队列为核心,当捕获到一个事件(如鼠标点击)时把他放进消息队列,然后当该事件从队列中被取出时,根据事件类型调用不同的函数来进行处理,其中每个事件一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数 。

消息机制

事件驱动在Windows下的具象化就是消息机制。
事件队列对应过来就是消息队列.

它会为每一个应用程序新开一个对应的消息队列,用于捕获其消息。

我们以一个简单的窗口实现来看看消息机制。 注意下方注释处即可。

#include<Windows.h>


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);


int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInStance, LPSTR lpCmdLine, int nShowCmd) {

	static TCHAR szAppName[] = TEXT("窗口类名称");
	HWND         hwnd;
	MSG          msg;
	WNDCLASSEX   wndclass = { 0 };

	//设计窗口类
	wndclass.cbSize = sizeof(WNDCLASSEX);
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hinstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;


	if (!RegisterClassEx(&wndclass))
	{
		MessageBox(NULL, TEXT("RegisterClassEx failed!"),TEXT("title"), MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
		szAppName,
		TEXT("窗口名称"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hinstance,
		NULL);

	ShowWindow(hwnd, nShowCmd);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, hwnd, 0, 0)) {  #从消息队列中获取消息,若存在消息待处理,则进行窗口过程。同时通过句柄得到需要捕捉消息的应用程序。
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;

	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		GetClientRect(hwnd, &rect);
		DrawText(hdc, TEXT("FUCK"), -1, &rect, DT_CENTER);
		EndPaint(hwnd, &ps);
		return 0;

	case WM_LBUTTONUP:
		MessageBox(NULL, TEXT("老子被点了"), TEXT("tick"), 0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}

对于消息机制,有几个点需要特别关注。

1.WM_PAINT,WM_TIMER,WM_QUIT 这几个消息永远被放在消息队列最后。
究其原因很简单,就拿WM_QUIT举例,他是意思是退出,若不放在最后,WM_QUIT后面的消息也就无法处理了。
2.也有部分消息是非队列消息,可以无视队列顺序首先被处理。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

12 − 6 =

标签云