2013.8.7 学习笔记《windows核心编程》(十) 消息队列与键盘消息

《windows核心编程》(十)-----------2013.8.7

一、概念

消息队列
       消息队列用于存放消息的一个队列,消息在队列中先入先出。所有窗口程序都具有消息队列。程序可以从队列中获取消息。
消息队列的类型
        系统消息队列-由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘等。
       程序消息队列-属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。
消息队列的关系
       1 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
       2 系统会根据存放的消息,找到对应窗口的消息队列。
       3 将消息投递到程序的消息队列中。

消息和消息队列
•根据消息和消息队列之间使用关系,将消息分成两类:
        队列消息 - 消息的发送和获取,都是通过消息队列完成。
        非队列消息 - 消息的发送和获取,是直接调用消息的窗口处理完成。
•队列消息-消息发送后,首先放入队列,然后通过消息循环,从队列当中获取。
        GetMessage - 从消息队列中获取消息
        PostMessage - 将消息投递到消息队列
        常见队列消息:WM_PAINT、键盘、鼠标、定时器。
•非队列消息-消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处理函数,完成消息。
        SendMessage - 直接将消息发送给窗口的处理函数,并等候处理结果。
        常见消息:WM_CREATE、WM_SIZE等。

消息的获取
•消息循环
       GetMessage /PeekMessage从程序的消息队列当中,获取到消息。
       TranslateMessage 检查获取到的消息,如果发现是按键消息,产生一个字符消息,并放入程序的消息队列。
       DispatchMessage 根据消息,找到窗口处理函数,调用窗口处理函数,完成消息的处理。

GetMessage/PeekMessage次序
       1 在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列取出消息返回。
       2 如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序消息队列
       3 如果系统消息队列也没有消息,检查当前窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息,取得消息返回处理。
       4 如果没有重新绘制区域,检查定时器如果有到时的定时器,产生WM_TIMER,返回处理执行。
       5 如果没有到时的定时器,整理程序的资源、内存等等。
       6 GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。
       注意:GetMessage如果获取到是WM_QUIT,函数会返回FALSE

消息的发送
       1 SendMessage
       发送消息到指定的窗口,并等候对方将消息处理,然后消息执行结果,用于非队列消息的发送。
       2 PostMessage
       将消息放到消息队列中,立刻返回,用于队列消息的发送。
       无法获知消息是否被对方处理。

绘图消息-WM_PAINT
•WM_PAINT
    当窗口需要绘制的时候,会发送窗口处理函数。
•窗口无效区域
    被声明成需要重新绘制的区域。
BOOL InvalidateRect(
      HWND hWnd,  //窗口句柄
      CONST RECT* lpRect,  //区域的矩形坐标
      BOOL bErase  //重绘前是否先擦除
);
•在程序中,如果需要绘制窗口,调用函数声明窗口无效区域。
•WM_PAINT参数
   WPARAM - 不使用
   LPARAM - 不使用
•消息处理步骤
   1 开始绘图处理
   HDC BeginPaint(
      HWND hwnd, //绘图窗口
      LPPAINTSTRUCT lpPaint //绘图参数的BUFF
   ); 返回绘图设备句柄HDC
   2 绘图
   3 结束绘图处理
   BOOL EndPaint(
       HWND hWnd, //绘图窗口
      CONST PAINTSTRUCT *lpPaint  //绘图参数的指针BeginPaint返回
   );

示例: 在主窗口中绘制一个字符串:
代码如下:
// WinCreate.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "windows.h"
HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄
HANDLE g_hOutput = 0;
#define WM_MYMESSAGE WM_USER + 10001//定义一个用户自定义消息
void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps = {0};//声明一个PAINTSTRUCT的结构体
	HDC hdc = BeginPaint(hWnd,&ps);//进行开始绘图处理
	TextOut(hdc,100,100,"Hello",strlen("Hello"));//绘制一个字符串
	EndPaint(hWnd,&ps);
}
//窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,
						 WPARAM wParam,LPARAM lParam)
{
	switch(nMsg)
	{
	case WM_PAINT:
		OnPaint(hWnd);
		break;
	case WM_MYMESSAGE:
		MessageBox(NULL,"WM_MYMESSAGE","Infor",MB_OK);
		break;
	case WM_CREATE:
		//SendMessage(hWnd,WM_MYMESSAGE,1,2);
		PostMessage(hWnd,WM_MYMESSAGE,1,2);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		//SendMessage(hWnd,WM_QUIT,0,0);
		//PostMessage(hWnd,WM_QUIT,0,0);

		break;
	}
	return DefWindowProc(hWnd,nMsg,wParam,lParam);
}
//注册窗口类
BOOL Register(LPSTR lpClassName,WNDPROC wndproc)
{
	WNDCLASSEX wce = {0};
	wce.cbSize = sizeof(wce);
	wce.cbClsExtra = 0;
	wce.cbWndExtra = 0;
	wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wce.hCursor = NULL;
	wce.hIcon = NULL;
	wce.hIconSm = NULL;
	wce.hInstance = g_hInstance;
	wce.lpfnWndProc = wndproc;
	wce.lpszClassName = lpClassName;
	wce.lpszMenuName = NULL;
	wce.style = CS_HREDRAW | CS_VREDRAW;
	ATOM nAtom = RegisterClassEx(&wce);
	if(nAtom == 0)
	{
		return FALSE;
	}
	return TRUE;
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName)
{
	HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,
		WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		NULL,NULL,g_hInstance,NULL);
	return hWnd;
}
//显示窗口
void Display(HWND hWnd)
{
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
}
//消息循环
void Message()
{
	MSG nMsg = {0};
	/*
	while (GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);
	}
	*/
	while(true)
	{
		if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE))
		{
			if(GetMessage(&nMsg,NULL,0,0))
			{
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);
			}
			else
			{
				return;
			}
		}
		else
		{
			//当没有消息时
			WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL);
		}
	}
}
int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR     lpCmdLine,
					 int       nCmdShow)
{
	// TODO: Place code here.
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	g_hInstance = hInstance;
	Register("Main",WndProc);
	HWND hWnd = CreateMain("Main","Window");
	Display(hWnd);
	Message();
	return 0;
}

运行结果:


接受点击鼠标左键消息示例,把点击结果输出在命令行中:
代码如下:
// WinCreate.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "windows.h"
HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄
HANDLE g_hOutput = 0;
#define WM_MYMESSAGE WM_USER + 10001//定义一个用户自定义消息
void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps = {0};//声明一个PAINTSTRUCT的结构体
	HDC hdc = BeginPaint(hWnd,&ps);//进行开始绘图处理
	TextOut(hdc,100,100,"Hello",strlen("Hello"));//绘制一个字符串
	EndPaint(hWnd,&ps);
}
//窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,
						 WPARAM wParam,LPARAM lParam)
{
	switch(nMsg)
	{
	case WM_LBUTTONDOWN:
		WriteConsole(g_hOutput,"WM_LBUTTONDOWN\n",strlen("WM_LBUTTONDOWN\n"),NULL,NULL);
		break;
	case WM_PAINT:
		OnPaint(hWnd);
		break;
	case WM_MYMESSAGE:
		MessageBox(NULL,"WM_MYMESSAGE","Infor",MB_OK);
		break;
	case WM_CREATE:
		//SendMessage(hWnd,WM_MYMESSAGE,1,2);
		PostMessage(hWnd,WM_MYMESSAGE,1,2);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		//SendMessage(hWnd,WM_QUIT,0,0);
		//PostMessage(hWnd,WM_QUIT,0,0);

		break;
	}
	return DefWindowProc(hWnd,nMsg,wParam,lParam);
}
//注册窗口类
BOOL Register(LPSTR lpClassName,WNDPROC wndproc)
{
	WNDCLASSEX wce = {0};
	wce.cbSize = sizeof(wce);
	wce.cbClsExtra = 0;
	wce.cbWndExtra = 0;
	wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wce.hCursor = NULL;
	wce.hIcon = NULL;
	wce.hIconSm = NULL;
	wce.hInstance = g_hInstance;
	wce.lpfnWndProc = wndproc;
	wce.lpszClassName = lpClassName;
	wce.lpszMenuName = NULL;
	wce.style = CS_HREDRAW | CS_VREDRAW;
	ATOM nAtom = RegisterClassEx(&wce);
	if(nAtom == 0)
	{
		return FALSE;
	}
	return TRUE;
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName)
{
	HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,
		WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		NULL,NULL,g_hInstance,NULL);
	return hWnd;
}
//显示窗口
void Display(HWND hWnd)
{
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
}
//消息循环
void Message()
{
	MSG nMsg = {0};
	while(true)
	{
		if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE))
		{
			if(GetMessage(&nMsg,NULL,0,0))
			{
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);
			}
			else
			{
				return;
			}
		}
		else
		{
			//当没有消息时
		}
	}
}
int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR     lpCmdLine,
					 int       nCmdShow)
{
	// TODO: Place code here.
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	g_hInstance = hInstance;
	Register("Main",WndProc);
	HWND hWnd = CreateMain("Main","Window");
	Display(hWnd);
	Message();
	return 0;
}

运行结果:



键盘消息
•1 键盘消息
WM_KEYDOWN - 按键被按下时产生
WM_KEYUP - 按键被放开时产生
(可以有多个WM_KEYDOWN消息和一个WM_KEYUP消息,不可能有多个WM_KEYUP消息只有一个WM_KEYDOWN消息)
WM_SYSKEYDOWN - 系统键按下时产生  比如ALT、F10
WM_SYSKEYUP - 系统键放开时产生
WM_CHAR - 字符消息-translatemessage 函数发送
•2 消息参数
按键消息:
            WPARAM - 按键的Virtual Key
LPARAM - 按键的参数,例如按下次数
WM_CHAR消息:
            WPARAM - 输入的字符
LPARAM - 按键的相关参数
•消息的使用
1 KEYDOWN可以重复出现,KEYUP只能在按键松开时出现1次
2 TranslateMessage在转换WM_KEYDOWN消息时,对于可见字符可以产生WM_CHAR,不可见字符无此消息。
3 WM_KEYDOWN/UP的wParam是表示的按键虚拟键码,WM_CHAR是表示输入的字符ASC码。

测试键盘消息,并输出Virtual Key参数:
代码如下:
// WinCreate.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄
HANDLE g_hOutput = 0;
void OnDown(HWND hWnd,WPARAM wParam)
{
	char szText[256] = {0};
	sprintf(szText,"WM_KEYDOWN:%08X\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}

void OnUp(HWND hWnd,WPARAM wParam)
{
	char szText[256] = {0};
	sprintf(szText,"WM_KEYUP:%08X\n",wParam);
	WriteConsole(g_hOutput,szText,strlen(szText),NULL,NULL);
}
//窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,
						 WPARAM wParam,LPARAM lParam)
{
	switch(nMsg)
	{
	case WM_KEYDOWN:
		OnDown(hWnd,wParam);
		break;
	case WM_KEYUP:
		OnUp(hWnd,wParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd,nMsg,wParam,lParam);
}
//注册窗口类
BOOL Register(LPSTR lpClassName,WNDPROC wndproc)
{
	WNDCLASSEX wce = {0};
	wce.cbSize = sizeof(wce);
	wce.cbClsExtra = 0;
	wce.cbWndExtra = 0;
	wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wce.hCursor = NULL;
	wce.hIcon = NULL;
	wce.hIconSm = NULL;
	wce.hInstance = g_hInstance;
	wce.lpfnWndProc = wndproc;
	wce.lpszClassName = lpClassName;
	wce.lpszMenuName = NULL;
	wce.style = CS_HREDRAW | CS_VREDRAW;
	ATOM nAtom = RegisterClassEx(&wce);
	if(nAtom == 0)
	{
		return FALSE;
	}
	return TRUE;
}
//创建主窗口
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName)
{
	HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,
		WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		NULL,NULL,g_hInstance,NULL);
	return hWnd;
}
//显示窗口
void Display(HWND hWnd)
{
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
}
//消息循环
void Message()
{
	MSG nMsg = {0};
	while (GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);
	}
}
int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR     lpCmdLine,
					 int       nCmdShow)
{
	// TODO: Place code here.
	AllocConsole();
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	g_hInstance = hInstance;
	Register("Main",WndProc);
	HWND hWnd = CreateMain("Main","Window");
	Display(hWnd);
	Message();
	return 0;
}

运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值