0%

Windows程序设计 - 视窗和讯息

最近在学习 Win32编程,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习Win32开发的童鞋们提供一份参考。

本系列博文均根据学习《Windows程序设计》一书总结而来;

运行环境:

  • 操作系统: Windows 7家庭版
  • 编译器:Visual Studio 2013

视窗和实训

自己的窗口

建立窗口很简单,使用CreateWindow函数即可;

总体

程序建立每一个窗口都有自己的消息处理函数;在Windows开始执行的时候,Windows为其建立一个消息队列,这个消息队列用于存储程序可能建立各种不同的窗口,在程序中有一段代码称为回调函数;

Hello程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <Windows.h>
#include <tchar.h>
#pragma comment(lib, "winmm")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, LPSTR szCmdline, INT iCmdShow)
{
static TCHAR szAppName[] = TEXT("HelloWin");
HWND hwnd;
MSG msg;
//创建窗口类
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; //窗口回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance; //窗口句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); //图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW); //鼠标样式
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //画刷
wc.lpszMenuName = NULL; //菜单
wc.lpszClassName = szAppName; //窗口名
if (!RegisterClass(&wc)) //注册窗口类
{
MessageBox(NULL, TEXT("无法注册窗口"), szAppName, MB_OK); //弹框
return 0;
}
hwnd = CreateWindow(szAppName, //会产生WM_CREATE消息,该消息不进入队列,直接调用窗口过程,初始化窗口
TEXT("The Hello Program"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, //父窗口
NULL, //菜单
hInstance, //应用程序实例化句柄
NULL
);
ShowWindow(hwnd, iCmdShow); //显示窗口(此时窗口仍然是无效的,因为只显示了窗口,但没在上面画些有用的东西)产生WM_size消息
UpdateWindow(hwnd); //更新窗口(产生WM_PAINT消息,使得窗口有效,也是直接调用窗口过程,不进入队列)

while (GetMessage(&msg,NULL,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_CREATE:
PlaySound(TEXT("HelloWin.wav"), NULL, SND_FILENAME | SND_ASYNC); //音频
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //获取设备描述表句柄,和特定的硬件平台有关(显示器)
GetClientRect(hwnd, &rect); //客户区大小
DrawText(hdc, TEXT("Hello,This Is Win7"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //绘制窗口
EndPaint(hwnd, &ps); //结束绘制
return 0;
case WM_DESTROY:
PostQuitMessage(0); //参数0作为返回消息wParam参数
return 0;

default:
break;
}
return DefWindowProc(hwnd, message, wParam, lParam); //默认处理函数,处理一些其它消息
}

大写字母识别字

CS —— Class Stye 类风格选项

CW —— Create Window 创建窗体选项

DT —— Draw Text 绘制文本选项
IDI —— ID of Icon 图标ID号

IDC —— ID of Cursor 光标ID号

MB —— MessageBox 消息框选项
SND —— Sound 声音选项

WM —— Window Message 窗口消息

WS —— Window Style 窗口风格

结构体

MSG 消息结构

WNDCLASS 窗口结构

PAINTSTRUCT 绘图结构

RECT 矩形结构

句柄

HINSTANCE —— Handle of Instance 实例句柄

HWND —— Handle of Window 窗口句柄

HDC —— Handle of Device Content 32bit 设备描述句柄

注册窗口

RegisterClass之后根据WndClass中的classname来CreateWindow;

UpdateWindow(hwnd)向hwnd发送WM_PAINT消息。

WM_Quit导致GetMessage返回0,消息循环结束。而PostQuitMessage通常用于响应WM_Destroy来向消息队列发送WM_Quit消息。为何不直接发送WM_Quit消息?如果这样的话在程序关闭之前你无法做任何其他操作。WM_Destroy响应函数可用于程序清理工作。

TraslateMsg进行键盘转换,DispatchMsg将消息交给窗口,而窗口将其交给适合的消息处理函数。

Windows程序所做的一切都是处理响应发送给窗口过程的消息。

Windows会在创建之后给窗口发送WM_CREATE消息,而不是之前一直潜意识中误解的WM_CREATE消息的响应函数来负责Create Windows。

消息循环和窗口过程并非并发进行

DefWndProc也是你窗口的一部分

消息机制补充:

  • 消息队列是FIFO的形式
  • WM_PiANT、WM_TIMER、WM_QUIT这三个消息特殊,操作系统回把他们放到消息队列后面处理
  • 消息队列分为队列化消息和非队列化消息