windows的消息机制

windows是基于“事件驱动,消息响应”的一个操作系统,用户使用外部设备对OS产生一个事件(例如:鼠标点击,键盘按键等),OS会把这个事件封装成一个消息(对应一个数据结构),然后由系统调用用户设置的该消息的响应函数(这个响应函数是一个回调函数)完成整个操作过程。可以看出,这个过程中用户只需要“产生事件”和“为这个事件对应的消息绑定一个回调函数,这个回调函数是给系统来调用的,这也是为什么叫“回调”的原因。

在进行windows SDK编程的过程中,我们再整个变成过程都是在按照这个过程在进行编程:为消息编写响应函数。例如创建一个菜单,为这个菜单的菜单项对应的”点击“事件对应的消息绑定回调函数,当这个菜单的某一个菜单项被点击的时候就会调用我们事先设计的回调函数了。

在我们使用windows MFC 来进行编程的时候,因为MFC的封装性,把我们在使用sdk编程过程中的API使用C++语言进行了封装,导致这个“事件驱动,消息响应”的过程不是那么明显了,但是实际上,MFC只是在sdk的基础上加上了一层而已,底层还是那些API最终完成我们的任务。

在最初使用MFC编程的时候,很多人都被vc向导生成的MFC代码吓到,一堆宏和不知代表什么意思的类。但是当我们慢慢进行编程的时候就会发现原来sdk编程的过程还是那么明显,只是更加方便了,不需要我们写更多重复的代码了。当我们需要对一个菜单增加消息响应的代码时,这个时候我们也要遵循MFC接口的规则(也可以说是接口)了,这些规则的目的就是就是完成我们sdk编程一样的目的。例如下图的代码:

在两个宏之间加了很多在MFC中称为“消息映射”的技术,这个技术把消息与响应函数结合下了一起,例如上面的

ON_BN_CLICKED(IDC_BUTTON_START_SERVER , OnButtonStartServer ) 这一句就是把一个按钮的单击事件与函数OnButtonStartServer结合在了一起,当这个按钮被敲击的时候系统就会调用这个函数。

关于消息映射这一技术当大家在深入学习MFC的时候会体会到其内在的秘密的,其实很简单,就是几个宏在作祟。


说了这么多,貌似跑题了,我们下面来说一下windows的消息响应的过程:

(1)操作系统接收到应用程序的窗口消息,将消息投递到消息队列中

(2)应用程序在

消息队列中调用GetMessage函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用

TransslateMessage产生新的消息。

(3)应用程序调用DispacheMessage,将消息传回给操作系统。消息是使用MSG结构来表示的,其中包含了接收消息的窗口的句柄。因此DisPacheMessage函数总能进行正确的投递。

(4)系统利用WNDCLASS结构体的lpfnWndProc成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理。

以上就是windows系统对消息的处理过程。


结合代码我们来进行分析:

使用vc/vs创建一个简单的win32 application的工程。

函数的入口是WimMain:

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)

在这个主函数中主要是一个消息循环,Message Loop。

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

在主函数中有一个窗机注册函数,这个函数主要是“私人定制”一个窗口的类型,包含所有特征,还包含了窗口处理过程,这是核心:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TEST_WINDOWS_MESSAGE);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= (LPCSTR)IDC_TEST_WINDOWS_MESSAGE;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	return RegisterClassEx(&wcex);
}

在注册这个窗口过程后就可以实例化这个窗口了:

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}



这个窗口过程函数如下:

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR szHello[MAX_LOADSTRING];
	LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

	switch (message) 
	{
		case WM_COMMAND:
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			// Parse the menu selections:
			switch (wmId)
			{
				case IDM_ABOUT:
				   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
				   break;
				case IDM_EXIT:
				   DestroyWindow(hWnd);
				   break;
				default:
				   return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			RECT rt;
			GetClientRect(hWnd, &rt);
			DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
			EndPaint(hWnd, &ps);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

初学者可能会对这个过程很费解,这里推荐给大家两本书学习:孙鑫《深入详解VC++》和侯捷《深入浅出MFC》。



Windows消息机制是指在Windows操作系统中,用于实现应用程序之间的通信和事件处理的机制。每个消息都由一个消息标识符和一些相关的参数组成。当系统中发生某个事件时,Windows会将这个事件转化为一个消息,并将其放入消息队列中。应用程序通过接收消息并将其传递给适当的窗口过程来处理这些消息。 在Windows消息机制中,每个线程都有自己的消息队列。GUI线程通常拥有一个消息循环,负责接收和处理消息消息循环会不断从消息队列中获取消息,并将其翻译和分发给对应的窗口过程进行处理。 除了通过消息队列派发消息到窗口过程外,有些消息也可以直接发送到窗口过程进行处理,绕过消息队列和线程消息队列。例如,当用户激活一个新的应用程序窗口时,系统会直接发送一系列消息到窗口,包括WM_ACTIVATE、WM_SETFOCUS和WM_SETCURSOR等消息,用于通知窗口被激活、键盘输入被定向到窗口以及鼠标光标移到窗口的边界内。 因此,Windows消息机制是通过将事件转化为消息并通过消息队列进行传递,以实现应用程序之间的通信和事件处理的机制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Windows消息机制](https://blog.csdn.net/King_weng/article/details/100072633)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值