窗口创建过程
创建一个完整的窗口,需要经过下面几个操作步骤:
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; }
运行初始结果