win32应用程序创建流程(消息处理)
窗口创建过程
创建一个完整的窗口,需要经过下面几个操作步骤:
1.编写WinMain函数(可以查看MSDN)。
2.设计窗口类(WNDCLASS)。
3.注册窗口类。
4.创建窗口。
5.显示并更新窗口。
6.编写消息循环。
7.编程窗口过程函数。
编写WinMain函数
WinMain是Windows程序的入口点函数,当操作系统启动一个程序时,它就调用该程序的WinMain函数。它和DOS程序的入口点函数main是一样的作用。
WinMain函数的原型声明如下:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd );
参数说明:
- hInstance 表示该程序当前运行的实例句柄,这是一个数值,操作系统会为每个运行中的实例分配句柄值。
- hPrevInstance 当前实例的前一个句柄的实例。
- lpCmdLine 指定给应用程序的命令行参数。
- nShowCmd 指定程序的窗口应该如何显示。
设计窗口类
一个完整的窗口类具有许多特征,包括光标(鼠标进入该窗口时的形状)、图标、背景颜色等,在创建一个窗口前,需要对一个窗口进行设计,在windows中,窗口的特征有WNDCLASS结构体来定义,WNDCLASS结构体的定义如下:
typedef struct { UINT style; //这一类型窗口的样式 WNDPROC lpfnWndProc; //指向窗口过程的函数指针 int cbClsExtra; //类附加内存 int cbWndExtra; //窗口附加内存 HINSTANCE hInstance; //实例句柄 HICON hIcon; //窗口类的图标句柄 HCURSOR hCursor; //窗口类的光标句柄 HBRUSH hbrBackground; //窗口类的背景 LPCTSTR lpszMenuName; //菜单名字 LPCTSTR lpszClassName; //窗口类名字 } WNDCLASS;
注册窗口
设计完窗口类后,需要调用RegisterClass函数对其注册,注册成功后,才可以创建该类型的窗口。函数声明如下:
ATOM RegisterClass(const WNDCLASS* lpWndClass);
创建窗口
设计好窗口类并进行注册成功之后,就可以利用CreateWindow函数产生这种类型的窗口了,其函数声明如下:
HWND CreateWindow(LPCTSTR lpClassName, //指定窗口类的名称,需要和WNDCLASS的className一样。 LPCTSTR lpWindowName, //窗口的名字 DWORD dwStyle, //创建的窗口样式 int x, //窗口左上角的x坐标 int y, //窗口左上角的y坐标 int nWidth, //窗口宽度 int nHeight, //窗口高度 HWND hWndParent, //父窗口句柄 HMENU hMenu, //窗口菜单的句柄 HANDLE hInstance, //应用程序句柄 PVOID lpParam ); //附件参数,多文档窗口为CLIENTCREATESTRUCT结构体,其余多是NULL
显示窗口
窗口创建成功之后,我们要让它显示出来,调用函数ShowWindow来显示窗口,函数原型如下:
BOOL ShowWindow(HWND hWnd, int nCmdShow);
nCmdShow指定了窗口显示的状态,具体窗口状态可以查看MSDN
更新窗口
被调用ShowWindow函数之后,我们需要紧接调用UpdateWindow来刷新窗口。UpdateWindow函数声明如下:
BOOL UpdateWindow(HWND hWnd// handle to window);
其参数是创建成功后的窗口句柄,UpdateWindow函数通过发送一个WM_PAINT消息来刷新窗口,UpdateWindow将WM_PAINT消息直接发送给了窗口过程函数进行消息处理,而没有放到消息队列中去。
消息循环
在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。获取消息可以调用GetMessage()函数,消息循环常见代码如下:
MSG msgInfo; while (GetMessage(&msgInfo, NULL, 0, 0)) { TranslateMessage(&msgInfo); DispatchMessage(&msgInfo); }
更多内容见“windows消息处理机制”。
编程窗口过程函数
在完成上述步骤后,剩下的工作主要是编写一个窗口过程函数,用于处理发送给窗口的消息。一个Windows应用程序的主要代码部分就隐藏在窗口过程,其函数声明如下:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
窗口过程函数的名字是可随便命名的,但函数定义的形式必须和上述声明保持一致。WindowProc函数的4个参数分别对应消息的窗口句柄。消息代码、消息代码的两个附加参数。
一个程序可以有多个窗口,窗口过程函数的hwnd就标识了接收消息的特定窗口。在窗口过程函数内部使用switch/case语句来确定窗口过程接收消息类型以及消息的处理。例如:
//编写窗口过程函数 LRESULT CALLBACK WindProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CHAR: { char szMsg[20] = {0}; sprintf_s(szMsg,"char code is %d", wParam); MessageBox(hWnd,szMsg, "char", 0); break; } case WM_PAINT: ... case WM_CLOSE: ... case WM_DESTROY: ... default: return DefWindowProc(hWnd,uMsg,wParam,lParam); } }
完整代码
#include <Windows.h>
#include <stdio.h>
//窗口过程函数声明
LRESULT CALLBACK WndProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/****************************************************************
*函数名称:WinMain
*功 能:winddow应用程序入口
*作 者:Jin
*日 期:2016年8月10日
****************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
//设计窗口类
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = WndProcess;
wndcls.lpszClassName = "Jin";
wndcls.lpszMenuName = NULL;
//垂直和横轴大小发生变化,窗口重绘
wndcls.style = CS_HREDRAW | CS_VREDRAW;
//注册窗口
RegisterClass(&wndcls);
HWND hWnd = NULL;
//创建窗口
hWnd = CreateWindow("Jin", "Jin Win32", WS_OVERLAPPEDWINDOW, 0, 0,\
600, 400, NULL, NULL, hInstance, NULL);
//显示&刷新
ShowWindow(hWnd,SW_SHOWNORMAL);
UpdateWindow(hWnd);
//定义消息循环
MSG msgInfo;
while (GetMessage(&msgInfo, NULL/*所有窗口*/, 0, 0))
{
TranslateMessage(&msgInfo); //换字符消息
DispatchMessage(&msgInfo); //分发消息
}
return msgInfo.wParam;
}
/****************************************************************
*函数名称:WndProcess
*功 能:窗口过程消对应的消息处理
*作 者:Jin
*日 期:2016年8月21日
****************************************************************/
LRESULT CALLBACK WndProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CHAR:
{
char szChar[20] = {0};
sprintf_s(szChar,"char code is %d", wParam);
MessageBox(hWnd,szChar, "char", MB_OK);
break;
}
case WM_LBUTTONDOWN:
{
MessageBox(hWnd, "mouse clicked", "mouse", MB_OK);
HDC hDc;
hDc = GetDC(hWnd);
TextOut(hDc, 0, 50, "hello world", strlen("hello world"));
ReleaseDC(hWnd,hDc);
break;
}
case WM_PAINT:
{
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC,0,0,"CSDN", strlen("CSDN"));
EndPaint(hWnd, &ps);
break;
}
case WM_CLOSE:
{
if (IDYES == MessageBox(hWnd, "are you sure to exit?", "message", MB_YESNO))
{
DestroyWindow(hWnd);//窗口消失,产生WM_DESTROY新消息
}
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);//产生WM_QUIT消息,然后程序退出
break;
}
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
return 0;
}
运行初始结果
上一篇: java代码实现队列
下一篇: Jave实现排序算法:选择排序