1.注册窗口类函数
(1)RegisterClass/RegisterClassEx
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx);
注册成功后,返回一个非0数字标识,失败返回0。
(2)窗口类的风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8整倍数据对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8整倍数据对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
CS_CLASSDC - 该类型的窗口,都是有同一个绘图(DC)设备
CS_PARENTDC - 该类型的窗口,使用它的父窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都是用自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标双击
CS_NOCLOSE - 窗口没有关闭按钮
下面是简单的示例代码:
#include "stdafx.h" HINSTANCE g_hInstance = 0; void AppReg() { //注册窗口类 WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); //大小 wce.cbClsExtra = 0; //窗口类附加数据buffer的大小 wce.cbWndExtra = 0; //窗口的附加数据buffer的大小 wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); //背景为白色 wce.hCursor = NULL; //默认光标 wce.hIcon = NULL; //默认大图标 wce.hIconSm = NULL; //默认小图标 wce.hInstance = g_hInstance; //当前程序实例句柄 wce.lpfnWndProc = DefWindowProc; //系统默认窗口处理函数 wce.lpszClassName = "Main"; //窗口类名 wce.lpszMenuName = NULL; //窗口菜单 wce.style = CS_HREDRAW | CS_VREDRAW; //窗口风格 //将以上赋值写入操作系统 ATOM nAtom = RegisterClassEx(&wce); if (nAtom == 0) { MessageBox(NULL, "注册失败", "Info", MB_OK); return; } HWND hWnd = CreateWindow("Main", "Window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, g_hInstance, NULL); ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); MSG uMsg = { 0 }; while (GetMessage(&uMsg, NULL, 0, 0)) { TranslateMessage(&uMsg); DispatchMessage(&uMsg); } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int cCmdShow) { g_hInstance = hInstance; AppReg(); return 0; }
2.创建窗口
(1)创建窗口函数CreateWindow/CreateWindowEx
CreateWindowEx(
DWORD dwExStyle, //窗口的扩展风格,CreateWindow没有这个参数
LPCTSTR lpClassName, //窗口类名
LPCTSTR lpWindowName, //窗口标题栏名
DWORD dwStyle, //窗口基本风格
int x, //窗口左上角横坐标
int y, //窗口左上角纵坐标
int nWidth, //窗口宽度
int nHeight, //窗口高度
HWND hWndParent, //窗口的父窗口句柄
HMENU hMenu, //窗口菜单句柄
HINSTANCE hInstance, //应用程序实例句柄
LPVOID lpParam //窗口创建时附加参数
);创建成功返回窗口句柄
(2)子窗口的创建
创建子窗口时要设置父窗口句柄和WS_CHILD | WS_VISIBLE风格。
(3)内部执行过程
CreateWindow用其中两个参数用来确定窗口,CreateWindow("Main", ..., g_hInstance, ...),即窗口类名和当前程序实例句柄。
a.系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行b,否则执行c。
b.比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口在同一模块,创建窗口返回。否则执行c。
c.在应用程序全局窗口类中查找,如果找到,执行d,否则执行e。
d.使用找到的窗口类的信息,创建窗口返回。
e.在系统窗口类中查找,如果找到,创建窗口,否则窗口创建失败。
若创建窗口成功,那么CreateWindow就申请内存,将传入的参数写入到内存中,返回这块内存的句柄。
下面我们看一个比较完整的例子:
创建了两个子窗口,并解决前面的遗留问题(关闭窗口后,进程并没有退出)
相关代码:
#include "stdafx.h" HINSTANCE g_hInstance = 0; //接收当前程序实例句柄 //窗口处理函数 //CALLBACK即回调,我们定义函数我们不调用,操作系统调用,仅限windows系统 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); //能够使GetMessage返回0 break; } return DefWindowProc(hWnd, msg, wParam, lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbClsExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndProc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if (0 == nAtom) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); return hWnd; } //创建子窗口 HWND CreateChildWindow(LPSTR lpClassName, LPSTR lpWndName, HWND hParent) { HWND hChild = CreateWindowEx(0, lpClassName, lpWndName, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, hParent, NULL, g_hInstance, NULL); return hChild; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = { 0 }; while (GetMessage(&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } } //APIENTRY也是回调函数,APIENTRY和CALLBACK一样,都是__stdcall的别名 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; BOOL nBool = Register("Main", WndProc); if (nBool == FALSE) { MessageBox(NULL, "注册失败", "Info", MB_OK); } HWND hWnd = CreateMainWindow("Main", "window"); Display(hWnd); BOOL nChild = Register("Child", DefWindowProc); if (nChild == FALSE) { MessageBox(NULL, "注册失败", "Info", MB_OK); } HWND hChild1 = CreateChildWindow("Child", "c1", hWnd); HWND hChild2 = CreateChildWindow("Child", "c2", hWnd); MoveWindow(hChild1, 300, 100, 200, 200, TRUE); MoveWindow(hChild2, 500, 100, 200, 200, TRUE); Display(hChild1); Display(hChild2); Message(); return 0; }
运行结果为: