第一个 Windows 程序
* 纯净版
#include<Windows.h>
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iShowCmd
)
{
MessageBox(NULL, TEXT("Hello, Windows!"), TEXT("HelloMsg"), 1);
return 0;
}
* 注释版
#include<Windows.h>
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄,唯一标识了我们这个程序(在Windows程序中,句柄就是一个数值,用来标识某个东西)
HINSTANCE hPrevInstance, // 前一个实例的句柄(在Win32中,此概念已弃用,因此该参数总是NULL)
LPSTR lpCmdLine, // 命令行参数
int iShowCmd // 指明程序最初如何显示(正常显示、最大化到全屏、最小化到任务栏)
)
{
MessageBox( // 函数作用:弹出一个小窗口,主要用来显示一些短消息
NULL, // 窗口句柄,唯一标识这个窗口
TEXT("Hello, Windows!"),// 要在信息框里面出现的文本字符串
TEXT("HelloMsg"), // 要在标题栏上显示的文本字符串
1 // 选择按钮的类型
);
return 0;
}
/*
Windows API 中"类型"的命名规则:
HINSTANCE: H + INSTANCE == handle + instance == 实例句柄
LPSTR: L + P + STR == long + pointer + str == 长字符指针
i == int
sz == 以零结尾的字符串
c == const == 常量
s == static == 静态
*/
编码问题
早期 Windows 使用 ASCII 进行编码,对于美国自己来用,基本上足够了
随着计算机的发展,世界各国都想要自己的文字能够在计算机上表示
为了统一世界各国的字符编码问题,Unicode 诞生了
它是通过增加位的方式来扩充,由原来的7位,变成现在的16位(方案不同,会有所出入,但只会更多,不会更少)
可容纳的符号,由原来的27=128,变成现在的216=65536(方案不同,会有所出入,但只会更多,不会更少)
使用 Unicode 也有缺点:就是用 Unicode 写的字符占用的空间,会比用 ASCII 写的字符所占用的空间大2倍
为此,人们希望最好能够创建两个版本的程序,让不同需求的人,拿最适合自己的那一个版本即可
于是,有了以下的设计:
使用 TCHAR.H 头文件,这个头文件提供了一系列的类型或函数的替代名称
一个命名为 _UNICODE
的标识符被定义了,在生成代码时
TCHAR
就自动变成 wchar_t
,_tprintf
就自动变成 wprintf
(w:width)
一个名为 _UNICODE
的标识符没有被定义,在生成代码时
TCHAR
就自动变成 char
,_tprintf
就自动变成 printf
同样的道理,对于字符串而言,使用 _T("hello world")
或 _TEXT("hello world")
也能自动变化
#include<Windows.h>
#include<tchar.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MessageBox(NULL, _T("你好,窗口!"), _T("信息窗口"), 0);
return 0;
}
创建窗口
运行代码的时候:
- 打开项目属性。
- 导航到“链接器”>“输入”>“附加依赖项”。
- 在“附加依赖项”字段中添加
winmm.lib
(如果列表中还没有的话)
* 纯净版
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdShow
)
{
static TCHAR szAppName[] = TEXT("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
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_APPSTARTING);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windwos!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(
szAppName,
TEXT("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
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, Windows!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
* 注释版
#include<Windows.h>
/* ------------------------------------------------------------------
要创建窗口,首先需要注册一个窗口类,而窗口类又需要"窗口过程"来处理窗口消息
名词解释:窗口过程,是一个函数,用于处理发送到类的所有窗口或发布到所有窗口的所有消息
窗口过程是给 Windows 回调用的,它必须遵循规定的格式
对窗口过程的子程序名并没有规定,对 Windows 来说,窗口过程的地址才是惟一需要的
------------------------------------------------------------------ */
// 声明"窗口过程"(窗口处理函数),用于处理窗口消息
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 窗口过程的名字,是可以自定义命名的
// Windows 程序的入口点
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄
HINSTANCE hPrevInstance, // 前一个实例的句柄(在Win32中,此参数总是NULL)
PSTR szCmdLine, // 命令行参数
int iCmdShow // 控制窗口如何显示
)
{
static TCHAR szAppName[] = TEXT("HelloWin"); // 窗口类名
HWND hwnd; // 窗口句柄
MSG msg; // 消息结构体
WNDCLASS wndclass; // 窗口类结构体
// 设置窗口类的属性
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_APPSTARTING); // 加载默认光标
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 背景画刷
wndclass.lpszMenuName = NULL; // 菜单名(这里没有使用)
wndclass.lpszClassName = szAppName; // 窗口类名
// 注册窗口类
if (!RegisterClass(&wndclass))
{
MessageBox(
NULL,
TEXT("This program requires Windwos!"),
szAppName,
MB_ICONERROR
);
return 0;
}
// 创建窗口
hwnd = CreateWindow(
szAppName, // 窗口类名
TEXT("The Hello Program"), // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, // x坐标(使用默认值)
CW_USEDEFAULT, // y坐标(使用默认值)
CW_USEDEFAULT, // 宽度(使用默认值)
CW_USEDEFAULT, // 高度(使用默认值)
NULL, // 父窗口句柄(无父窗口)
NULL, // 菜单句柄(无菜单)
hInstance, // 应用实例句柄
NULL // 创建参数(这里不使用)
);
// 显示并更新窗口
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
// 消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg); // 翻译消息(如键盘消息到字符消息)
DispatchMessage(&msg); // 分发消息到窗口过程(窗口处理函数)
}
return msg.wParam;
}
// 实现窗口过程(窗口处理函数)
LRESULT CALLBACK WndProc(
HWND hwnd, // 窗口句柄
UINT message, // 消息ID
WPARAM wParam, // 消息参数(对于某些消息,它表示特定的信息)
LPARAM lParam // 消息参数(对于某些消息,它通常是一个指向结构体的指针)
)
{
HDC hdc; // 设备上下文句柄,用于绘图操作
PAINTSTRUCT ps; // 绘图结构体,用于 BeginPaint 和 EndPaint 函数
RECT rect; // 矩形区域,用于描述窗口的绘图区域
switch (message)
{
case WM_CREATE: // 窗口创建消息
PlaySound( // 播放声音文件
TEXT("hellowin.wav"), // 声音文件的路径
NULL,
SND_FILENAME | SND_ASYNC // SND_FILENAME表示通过文件名播放声音,SND_ASYNC表示异步播放(不阻塞程序)
);
return 0;
case WM_PAINT: // 窗口绘图消息
hdc = BeginPaint(hwnd, &ps); // 开始绘图
GetClientRect(hwnd, &rect); // 获取窗口客户区大小
DrawText(
hdc,
TEXT("Hello, Windows!"), // TEXT("Hello, Windows!"): 要绘制的文本字符串
-1, // -1: 字符串中的字符数。如果为-1,则函数会自动计算字符串长度
&rect, // &rect: RECT结构体的指针,指定文本绘制的区域。文本将在这个矩形区域内被格式化
DT_SINGLELINE | DT_CENTER | DT_VCENTER
// DT_SINGLELINE | DT_CENTER | DT_VCENTER: 文本绘制选项
// DT_SINGLELINE 表示文本将被格式化为单行
// DT_CENTER 表示文本将在指定的矩形区域内水平居中
// DT_VCENTER 表示文本将在指定的矩形区域内垂直居中
);
EndPaint(hwnd, &ps); // 结束绘图
return 0;
case WM_DESTROY: // 窗口销毁消息
PostQuitMessage(0); // 发出退出消息到消息队列
return 0;
}
// 如果消息没有被窗口过程(WndProc)显式处理,则调用默认的窗口处理函数(DefWindowProc)来处理它
return DefWindowProc(
hwnd, // hwnd: 窗口句柄,表示哪个窗口接收到了消息
message, // message: 消息ID,标识了要处理的消息类型
wParam, // wParam: 消息的参数之一,它的具体含义取决于消息类型
lParam // lParam: 消息的参数之二,它的具体含义也取决于消息类型
);
}
常见的标识符前缀
前缀 | 常量 |
---|---|
CS | 类风格选项 |
CW | 创建窗口选项 |
DT | 文本绘制选项 |
IDI | 图标的 ID 号 |
IDC | 光标的 ID 号 |
MB | 消息框选项 |
SND | 声音选项 |
WM | 窗口消息 |
WS | 窗口风格 |
常用的变量名前缀
前缀 | 数据类型 |
---|---|
c | char 或 WCHAR 或 TCHAR |
by | BYTE(无符号字符) |
n | short |
i | int |
x, y | int, 表示 x 坐标和 y 坐标 |
cx, cy | int, 表示 x 或 y 的长度,c 表示 count (计数) |
B 或 f | BOOL(int); f 表示 flag |
w | WORD(无符号短整型) |
l | LONG(长整型) |
dw | DWORD(无符号长整型) |
fn | 函数 |
s | 字符串 |
sz | 以零结束的字符串 |
h | 句柄 |
p | 指针 |