前言

Win32窗口程序基础教程,前期项目设置:

右键打开项目属性:

image-20211003120811205

按图配置:

image-20211003120845033

image-20211003120933746

这里Debug和Release模式要分开设置;

image-20211003121015404

image-20211003121034016

因为我的项目不需要太高的精度;

image-20211003121105663

image-20211003121136069

image-20211003121247536

WinMain

WinMain是windows的关键字,类似控制台程序的mian函数,都窗口程序的入口;

1
2
3
4
HINSTANCE hInstance				//应用程序当前实例的句柄
HINSTANCE hPrevInstance //应用程序的先前实例的句柄,总是null
LPSTR lpCmdLine //参数,只能是string
int nCmdShow //窗口样式

创建窗口关键api(这里使用Ex版本):

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
WNDCLASSEX wc;					//windows类,包含所有窗口的信息

RegisterClassEx(&w); //注册窗口

HWND hWnd = CreateWindowExA( //创建窗口
DWORD dwExStyle, //窗口样式 0
LPCSTR lpClassName, //窗口类名
LPCSTR lpWindowName, //窗口名称title
DWORD dwStyle, //窗口样式
int X, //在屏幕坐标
int Y,
int nWidth, //窗口宽高
int nHeight,
HWND hWndParent, //父窗口句柄 nullptr
HMENU hMenu, //子窗口标识符,唯一 nullptr
HINSTANCE hInstance, //WinMain的参数 hInstance
LPVOID lpParam //(重要)指向要通过WM_CREATE消息的lParam参数指向的CREATESTRUCT结 //构(lpCreateParams成员)传递给窗口的值的指针;不需要可为nullptr
);

ShowWindow(
HWND hWnd, //窗口句柄
int nCmdShow //显示方式 SW_SHOW
);
GetMessage(
LPMSG lpMsg, //OUT 接受参数的指针 MSG msg 指针&msg
HWND hWnd, //窗口句柄
UINT wMsgFilterMin, //过滤消息
UINT wMsgFilterMax
);

TranslateMessage( //将虚拟键消息转换为字符消息,下次GetMessage可读取
const MSG *lpMsg //MSG msg 指针&msg
);

DispatchMessage( //向窗口过程发送消息
const MSG *lpMsg
);

WinMain的完整代码:

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
int __stdcall WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, //只接受string
int nCmdShow)
{
//创建窗口结构体
const auto pClassName = "littlePerilla";
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC;
wc.lpfnWndProc = WindowProc; //重要,函数指针,下面的WindowProc函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = nullptr;
wc.lpszMenuName = nullptr;
wc.lpszClassName = pClassName;
wc.hIconSm = nullptr;
//注册窗口
RegisterClassEx(&wc);
//创建窗口
HWND hWnd = CreateWindowExA(
0, pClassName,
"Happy National Day",
WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
200, 200, 800, 600,
nullptr, nullptr, hInstance, nullptr
);
//显示窗口
ShowWindow(hWnd, SW_SHOW);

MSG msg;
BOOL gResult;
//获取消息
while ((gResult = GetMessage(&msg, nullptr, 0, 0)) > 0)
{
//翻译按键字符串
TranslateMessage(&msg);
//传递消息
DispatchMessage(&msg);
}

if (gResult == -1)
return -1;

return msg.wParam;
}

Windows消息机制

WindowProc之前,先了解Windows的消息机制;

  1. 系统中发生了某个事件。

  2. Windows把这个事件翻译为消息,然后把它放到消息队列中。

  3. 应用程序从消息队列中接收到这个消息,把它存放在Msg记录中。

  4. 应用程序把消息传递给一个适当的窗口的窗口过程。

  5. 窗口过程响应这个消息并进行处理。

image-20211003141729354

WindowProc

只是个函数名,不固定,可以更改,只要赋值给窗口结构体的lpfnWndProc即可;

msg: 代表系统消息事件的种类,多达上千种?

每种不同的msg,对应的wParam和lParam参数的作用不一样,可查看MSDN了解具体作用;

在WndProc中拦截不同的消息做相应的处理;

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
LRESULT __stdcall WindowProc(
HWND hWnd, //产生消息的窗口
UINT msg, //消息类型
WPARAM wParam, //消息附加参数 1
LPARAM lParam) //消息附加参数 2
{
switch (uMsg)
{
case WM_CLOSE: //关闭消息
PostQuitMessage(69);
break;
case WM_KEYDOWN: //键盘按下
if (wParam == 'F')
{
SetWindowText(hWnd, "RESPECT");
}
break;
case WM_KEYUP: //键盘抬起
if (wParam == 'F')
{
SetWindowText(hWnd, "FUCKYOU");
}
break;
case WM_CHAR: //获取输入
{
static std::string title;
title.push_back((char)wParam);
SetWindowText(hWnd, title.c_str());
}
break;
case WM_LBUTTONDOWN: //鼠标左键按下
{
POINTS pt = MAKEPOINTS(lParam);
std::ostringstream oss;
oss << "(" << pt.x << "," << pt.y << ")";
SetWindowText(hWnd, oss.str().c_str());
}
break;
case WM_DESTROY: //销毁程序
PostQuitMessage(96);
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}