目录
1.1 API和SDK
1.2 窗口和句柄
1.3 消息和队列
1.4 WinMain
1.4.1 WinMain函数的定义
1.4.2 窗口的创建
1.4.3 消息循环
1.4.4 窗口过程函数
1.1 API和SDK
API:Windows操作系统提供给应用程序编程的接口。
SDK(软件开发包):用于开发的所有资源的集合。
-
1箭头表示操作系统控制输出设备
-
2箭头表示操作系统可以得到输入设备信息
-
3箭头表示应用程序通知操作系统执行具体操作 操作系统提供给应用程序的接口 API
-
4箭头表示输入设备变化告诉应用程序
1.2 窗口和句柄
句柄:系统在创建资源时会为他们分配内存,并返回这些资源的标识号,即句柄。(类似于指针)
窗口句柄(HWND)、图标(HICON)、光标(HCURSOR)、画刷(HBRUSH)
1.3 消息和队列
typedef struct tagMSG {
HWND hwnd; //HWND:窗口变量,hwnd:消息所属的窗口
UINT message; //message消息标识符,数值定义为WM_XXX (P4)
WPARAM wParam;
LPARAM lParam; //指定消息的附加信息,ASCII等
DWORD time; //消息投递到消息队列中的时间
POINT pt; //当前鼠标的位置
} MSG, *PMSG;
1.4 WinMain
Win32实现的步骤:
- 定义WinMain函数;
- 创建窗口;
- 消息循环;
- 窗口过程函数。
1.4.1 WinMain函数的定义
winmain函数是程序入口函数,由系统调用。
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance,always NULL in Win32
LPSTR lpCmdLine, // 空终止的字符串,指定传递给应用程序的命令行参数
int nCmdShow // 指定窗口应该如何显示
);
1.4.2 窗口的创建
步骤:
- 设计窗口类;
- 注册窗口;
- 创建窗口;
- 显示及更新窗口;
1. 设计窗口类
typedef struct _WNDCLASS //窗口类
{
UINT style; /*(P7知识点方框)窗口样式;
CS_XXX(都只有一位是1,且1位各不相同:位标志);
多种特点组合用(|)号;
去掉style中的样式用(&~)*/
WNDPROC lpfnWndProc; //指向回调函数的指针;在特定的事件发生时,用于对该事件的响应
int cbClsExtra;
int cbWndExtra; //cbClsExtra和cbWndExtra两个附加内存,一般都为0
HINSTANCE hInstance; //实例句柄
HICON hIcon; //图标句柄;HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
HCURSOR hCursor; //光标句柄;HCURSOR LoadCursor(HINSTANCE hInstance,LPCTSTR lpCursorName);
HBRUSH hbrBackground; //画刷句柄,背景颜色;wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
LPCTSTR lpszMenuName; //菜单名字,NULL
LPCTSTR lpszClassName; //类名,和创建窗口CreateWindow函数中的lpClassName一致
} WNDCLASS, *PWNDCLASS;
2. 注册窗口
ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); // 注册窗口
3. 创建窗口
HWND CreateWindow(
LPCTSTR lpClassName, // registered class name,与窗口类WNDCLASS中的lpszClassName一致
LPCTSTR lpWindowName, // window name,
DWORD dwStyle, /*window style;和WNDCLASS中的style不同,style是指定具体窗口的样式,dwstyle是窗口都具有的样式
常用WS_OVERLAPPEDWINDOW*/
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height;
/*如果x设为CW_USEDEFAULT,系统为窗口选择左上角并忽略y;
nWidth设为CW_USEDEFAULT,系统为默认大小并忽略nHeight。
窗口之间的父子关系,子窗口必须有WS_CHILD*/
HWND hWndParent, // handle to parent or owner window(父窗口句柄);NULL
HMENU hMenu, // menu handle or child identifier;NULL
HINSTANCE hInstance, // handle to application instance;hInstance
LPVOID lpParam // window-creation data;NULL
);
注意:创建窗口成功,函数返回系统为该窗口分配的句柄,否则返回NULL。创建窗口之前应先定义一个窗口句柄变量来接收创建窗口之后返回的句柄值。
4. 显示及更新窗口
- 显示
BOOL ShowWindow(
HWND hWnd, //
int nCmdShow // 常用SW_SHOWNORMAL
);
- 更新窗口
BOOL UpdateWindow(
HWND hWnd // handle to window
);
1.4.3 消息循环
BOOL GetMessage(
LPMSG lpMsg, // 指向一个消息结构体MSG,GetMessage取出的消息放入该结构体对象中
HWND hWnd, // handle to window,设为NULL接收所用窗口
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax // last message;范围过滤,获得所有消息则设为0
);
注意:GetMessage函数除了接收到WM_QUIT(退出消息)外都返回非零值,出错返回-1。
通常编写的消息循环代码如下:
MSG msg;//声明消息结构体变量
while(GetMessage(&msg,NULL,0,0))//没接收到WM_QUIT时一致循环
{
TranslateMessage(&msg);//将WM_KEYDOWN和WM_KEYUP转化为WM_CHAR,不修改原消息
DispatchMessage(&msg);//将消息发送至操作系统,后者用窗口过程函数对消息响应; Dispatch:派遣
}
1.4.4 窗口过程函数
即回调函数
LRESULT CALLBACK WindowProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息代码
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
过程函数名WindowProc可以换,但要和声明保持一致。
使用switch/case来对不同消息作出不同反应。
如下方例子中的过程函数所示。
例子1.1
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <stdexcept>
/*******************函数声明****************************/
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
/*******************WinMain函数*************************/
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
/*设计一个窗口类*/
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = WinSunProc;
wndcls.lpszClassName="sunxin2021";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
/*创建窗口*/
HWND hwnd;
hwnd = CreateWindow("sunxin2021", "sx's home.", WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL);
/*显示及刷新窗口*/
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
/*消息循环*/
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//将WM_KEYDOWN和WM_KEYUP转化为WM_CHAR,不修改原消息
DispatchMessage(&msg);//将消息发送至操作系统,后者用窗口过程函数对消息响应
}
return msg.wParam;
}
/*******************窗口过程函数*************************/
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (uMsg)
{
case WM_CHAR:
char szChar[20];
sprintf(szChar, "char code is %d", wParam);
MessageBox(hwnd, szChar, "char", 0);
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd, "mouse clicked", "message", 0);
HDC hdc; //要在窗口中输出文字或显示图形,要用到设备描述表(DC)。DC是一个包含设备信息的结构体,所有的图形操作都是利用DC来完成。
//定义类型为HDC的变量hdc
hdc = GetDC(hwnd); //GetDC返回与特定窗口相关联的DC句柄
TextOut(hdc, 0, 50, "sx's home",strlen("sx's home"));
ReleaseDC(hwnd, hdc); //在使用完GetDC后一定要注意释放
break;
case WM_PAINT://窗口重绘
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hwnd, &ps);
TextOut(hDC, 0, 0, "http://www.sunxin.org", strlen("http://www.sunxin.org"));
EndPaint(hwnd, &ps);//WM_PAINT、BeginPaint、EndPaint一起用,而不能用GetDC
break;
case WM_CLOSE://关闭消息
if (IDYES == MessageBox(hwnd, "是否真的结束了?", "message", MB_YESNO))
{
DestroyWindow(hwnd);//销毁窗口
}
break;
//此时窗口销毁,但程序还在后台运行
case WM_DESTROY:
PostQuitMessage(0);//在响应消息后,投递一个退出的消息使用程序安全退出
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);//调用缺省的消息处理过程函数,对没有处理的其他消息以默认处理
}
return 0;
}