一 窗口注册和创建
1 Win32窗口程序创建步骤
1.1 WinMain入口函数的定义
1.2 WindowProc函数的定义
1.3 注册窗口类
RegisterClass/RegisterClassEx
1.4 创建窗口
CreateWindow/CreateWindowEx
1.5 窗口的显示和刷新
ShowWindow/UpdateWindow
1.6 消息处理
GetMessage/DispatchMessage
1.7 窗口退出
WM_DESTROY/PostQuitMessage
2 窗口的注册
2.1 窗口类的分类
2.1.1 系统全局的窗口类.比如按钮("BUTTON")、文本编辑框("EDIT")等。
2.1.2 应用程序的全局窗口类。可以在一个应用程序中EXE、DLL等所有模块中使用的窗口类。
2.1.3 局部窗口类。只能在本模块中使用的窗口类。
2.2 实现窗口类的注册
2.2.1 系统全局的窗口类,无需注册直接使用。使用CreateWindow函数,在CLASSNAME中指定系统已经定义好的窗口类型名称即可。
#include <windows.h> #include "stdio.h" HINSTANCE g_hInst = NULL; LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch(nMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, nMsg, wParam, lParam); } HWND CreateButton() { HWND hWnd = CreateWindow("BUTTON", "Button", WS_OVERLAPPEDWINDOW, 0, 0, 500, 600, NULL, NULL, g_hInst, NULL); return hWnd; } void DisplayWnd(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } void Message() { MSG msg = {0}; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInt, LPSTR lpCmdLine, int nShowCmd) { g_hInst = hInst; HWND hWndBtn = CreateButton(); DisplayWnd(hWndBtn); Message(); return 0; }
2.2.2 应用程序的全局窗口类,需要用代码实现注册,在注册时需要增加CS_GLOBALCLASS定义。
实现方式:
WNDCLASS wc = {0}; wc.style = CS_GLOBALCLASS|CS_HREDRAW..; .... RegisterClass( &wc );
2.2.3 局部窗口类,不是增加CS_GLOBALCLASS定义。使用RegisterClass和RegisterClassEx注册
typedef struct _WNDCLASSEX { UINT cbSize; //结构体的大小 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; //小图标 } WNDCLASSEX;
2.2.4 窗口类风格
CS_HREDRAW 窗口水平变化,重新绘制窗口。
CS_VREDRAW 窗口垂直变化,重新绘制窗口。
CS_DBCLICK 窗口可以接收鼠标双击消息
CS_GLOBALCLASS 创建应用程序全局窗口类。
CS_BYTEALIGNWINDOW 窗口对齐方式,以8的倍数对齐
CS_BYTEALIGNCLIENT 窗口客户区对齐方式,以8的倍数对齐
CS_CLASSDC 所有这种类型的窗口使用同一个DC(设备描述表,绘图使用)
CS_OWNDC 每个窗口拥有自己的DC
CS_PARENTDC 使用父窗口的DC
CS_SAVEBITS 是用位图保存窗口界面,可以提高窗口界面的刷新性能
CS_NOCLOSE 禁止关闭命令.
#include <windows.h> #include "stdio.h" HINSTANCE g_hInst = NULL; LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch(nMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, nMsg, wParam, lParam); } BOOL RegisterWnd(LPSTR pszClassName) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.style = CS_VREDRAW|CS_HREDRAW; wce.lpfnWndProc = WndProc; wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hCursor = NULL; wce.hIcon = NULL; wce.hbrBackground = HBRUSH(COLOR_BTNFACE+1); wce.lpszClassName = pszClassName; wce.lpszMenuName = NULL; wce.hInstance = g_hInst; ATOM nAtom = RegisterClassEx(&wce); if(0 == nAtom) { MessageBox(NULL, "registerError", "Error", MB_OK); return FALSE; } return TRUE; } HWND CreateWnd(LPSTR pszClassName) { HWND hWnd = CreateWindow(pszClassName, "MyWnd", WS_OVERLAPPEDWINDOW, 0, 0, 400, 500, NULL, NULL, g_hInst, NULL); return hWnd; } void DisplayWnd(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } void Message() { MSG msg = {0}; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInt, LPSTR lpCmdLine, int nShowCmd) { g_hInst = hInst; RegisterWnd("MyWnd1"); HWND hMyWnd = CreateWnd("MyWnd1"); DisplayWnd(hMyWnd); Message(); return 0; }
2.2.5 窗口类的附加数据 cbClsExtra
在窗口类的数据信息中添加自己信息.
cbClsExtra 用于添加信息的内存的大小
SetClassLong 将信息保存到内存中
GetClassLong 将信息从内存中取出
DWORD SetClassLong( HWND hWnd,//窗口的句柄 int nIndex, //值的索引号 LONG dwNewLong //值 ); DWORD GetClassLong( HWND hWnd,//窗口的句柄 int nIndex, //值的索引号 );
cbClsExtra的长度一般是4字节的倍数
2.2.6 窗口附加数据 cbWndExtra
在窗口的数据信息中添加自己信息.
cbWndExtra 用于添加信息的内存的大小
SetWindowLong 将信息保存到内存中
GetWindowLong 将信息从内存中取出
#include <windows.h> #include "stdio.h" HINSTANCE g_hInst = NULL; LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch(nMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, nMsg, wParam, lParam); } BOOL RegisterWnd(LPSTR pszClassName) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.style = CS_VREDRAW|CS_HREDRAW; wce.lpfnWndProc = WndProc; wce.cbClsExtra = 100; wce.cbWndExtra = 100; wce.hCursor = NULL; wce.hIcon = NULL; wce.hbrBackground = HBRUSH(COLOR_BTNFACE+1); wce.lpszClassName = pszClassName; wce.lpszMenuName = NULL; wce.hInstance = g_hInst; ATOM nAtom = RegisterClassEx(&wce); if(0 == nAtom) { MessageBox(NULL, "registerError", "Error", MB_OK); return FALSE; } return TRUE; } HWND CreateWnd(LPSTR pszClassName) { HWND hWnd = CreateWindow(pszClassName, "MyWnd", WS_OVERLAPPEDWINDOW, 0, 0, 400, 500, NULL, NULL, g_hInst, NULL); return hWnd; } void SetExtra(HWND hWnd) { SetClassLong(hWnd, 1, 100); SetWindowLong(hWnd, 1, 200); } void GetExtra(HWND hWnd) { DWORD nClass = GetClassLong(hWnd, 1); DWORD nWnd = GetWindowLong(hWnd, 1); CHAR szText[256] = {0}; sprintf(szText, "CLS:%d WND:%d", nClass, nWnd); MessageBox(NULL, szText, "Extra", MB_OK); } void DisplayWnd(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } void Message() { MSG msg = {0}; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInt, LPSTR lpCmdLine, int nShowCmd) { g_hInst = hInst; RegisterWnd("MyWnd1"); HWND hMyWnd1 = CreateWnd("MyWnd1"); HWND hMyWnd2 = CreateWnd("MyWnd1"); SetExtra(hMyWnd1); GetExtra(hMyWnd1); GetExtra(hMyWnd2); DisplayWnd(hMyWnd1); Message(); return 0; }
2.3 窗口类的相关函数
RegisterClass/RegisterClassEx 注册
UnregisterClass 注销
GetClassInfo/GetClassInfoEx 获取信息
GetClassName 获取窗口的窗口类名称
GetClassLong/SetClassLong 窗口类附加数据的设置和获取
GetWindowLong/SetWindowLong 窗口的附加数据的设置和获取
2.4 创建窗口时如何定位窗口类
2.4.1 查找应用程序局部的窗口类。如果找到,执行2.4.2,否则执行2.4.3
2.4.2 如果找到名称一致的窗口类,会比较HISNTANCE句柄。如果相等,就使用找到的窗口类信息创建窗口,如果不同,继续查找,执行2.4.3。
2.4.3 如果未找到名称一致的窗口类,会继续在应用程序全局窗口类中查找。如果找到,执行2.4.4,否则执行2.4.5
2.4.4 全局窗口类找到一致的,使用找到的窗口类信息创建窗口。
2.4.5 系统全局窗口类中查找。如果找到,创建窗口,否则返回失败。
3 窗口创建
3.1 窗口创建函数
CreateWindow/CreateWindowEx HWND CreateWindowEx( DWORD dwExStyle,//窗口的扩展样式 LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam ); // pointer to window-creation data
3.2 窗口风格和扩展风格
窗口风格: WS_XXXX定义的风格,是窗口的基本风格.
扩展风格: WS_EX_XXXXX 定义的风格,是窗口的扩展风格.比如: ToolWindow窗口等等.
在CreateWindow可以使用基本窗口风格,扩展的窗口风格,需要使用CreateWindowEx设置.
WS_OVERLAPPED窗口,层叠式窗口
WS_POPUP窗口,弹出式窗口
WS_CHILD窗口,子窗口
3.3 父窗口和子窗口
3.3.1 CreateWindow时,指定父窗口
3.3.2 将窗口的风格增加WS_CHILD
3.3.3 可以使用SetParent和GetParent函数设置和获取指定窗口的父窗口.
其他: MoveWindow 移动窗口.
3.4 MDI窗口的创建
3.4.1 创建主窗口
注册主窗口类型,创建主窗口.
HWND hWnd = CreateWindowEx( 0, pszClassName, "MainWnd", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInst, NULL );
3.4.2 MDICLIENT窗口
1 添加CLIENTCREATESTRUCT结构,作为附加数据
CLIENTCREATESTRUCT cs = { 0 };
cs.idFirstChild = 1000;//MDI第一个子窗口的ID
2 创建时,使用"MDICLIENT"窗口类型.
3 它的父窗口是主窗口
HWND hWnd = CreateWindowEx( 0, "MDICLIENT", "MainWnd", WS_CHILD|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, g_hInst, &cs );
3.4.3 创建一个MDI子窗口
1 注册主窗口类型,创建子窗口
2 它的父窗口为MDICLIENT窗口
3 增加WS_EX_MDICHILD的风格
HWND hWnd = CreateWindowEx( WS_EX_MDICHILD, pszClassName, "ChildWnd", WS_CHILD|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, g_hInst, NULL );
// WinMDI.cpp : Defines the entry point for the application. // #include "stdafx.h" HINSTANCE g_hInst = NULL; HWND g_hMDIClient = NULL; //主窗口的窗口处理函数 LRESULT CALLBACK MainProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) { switch( nMsg ) { case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefFrameProc( hWnd, g_hMDIClient, nMsg, wParam, lParam ); } //子窗口的窗口处理函数 LRESULT CALLBACK ChildProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) { return DefMDIChildProc( hWnd, nMsg, wParam, lParam ); } //窗口注册函数 BOOL RegisterWnd( LPSTR pszClassName, WNDPROC Proc, int nBrush ) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof( wce ); wce.style = CS_HREDRAW|CS_VREDRAW; wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.lpfnWndProc= Proc; wce.hInstance = g_hInst; wce.hCursor = NULL; wce.hIcon = NULL; wce.hbrBackground = HBRUSH(nBrush); wce.lpszClassName = pszClassName; wce.lpszMenuName = NULL; wce.hIconSm = NULL; ATOM nAtom = RegisterClassEx( &wce ); if( nAtom == 0 ) { return FALSE; } return TRUE; } //显示窗口 void DisplayWnd( HWND hWnd ) { ShowWindow( hWnd, SW_SHOW ); UpdateWindow( hWnd ); } //消息循环 void Message( ) { MSG msg = { 0 }; while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); } } //创建主窗口 HWND CreateMainWnd( LPSTR pszClassName ) { HWND hWnd = CreateWindowEx( 0, pszClassName, "MainWnd", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInst, NULL ); return hWnd; } //创建MDICLIENT窗口 HWND CreateMDIClient( HWND hParent ) { CLIENTCREATESTRUCT cs = { 0 }; cs.idFirstChild = 1000; HWND hWnd = CreateWindowEx( 0, "MDICLIENT", "MainWnd", WS_CHILD|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, g_hInst, &cs ); return hWnd; } //创建MDI子窗口 HWND CreateChildWnd( LPSTR pszClassName, HWND hParent ) { HWND hWnd = CreateWindowEx( WS_EX_MDICHILD, pszClassName, "ChildWnd", WS_CHILD|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, g_hInst, NULL ); return hWnd; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //注册主窗口 RegisterWnd( "MainWnd", MainProc, COLOR_BTNFACE+1 ); //注册子窗口 RegisterWnd( "ChildWnd", ChildProc, COLOR_WINDOW ); //创建MDI主窗口 HWND hMain = CreateMainWnd( "MainWnd" ); //创建MDICLIENT窗口 g_hMDIClient = CreateMDIClient( hMain ); MoveWindow( g_hMDIClient, 0, 0, 500, 500, TRUE ); //创建MDI子窗口 CreateChildWnd( "ChildWnd", g_hMDIClient ); CreateChildWnd( "ChildWnd", g_hMDIClient ); CreateChildWnd( "ChildWnd", g_hMDIClient ); //显示和消息处理 DisplayWnd( hMain ); Message( ); return 0; }
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" HINSTANCE g_hInst = NULL; // 父窗口的处理函数 LRESULT CALLBACK WndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) { switch( nMsg ) { case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, nMsg, wParam, lParam ); } //子窗口的处理函数 LRESULT CALLBACK ChildProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) { return DefWindowProc( hWnd, nMsg, wParam, lParam ); } //消息处理函数 void Message( ) { MSG msg = { 0 }; while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); } } //显示窗口 void DisplayWnd( HWND hWnd ) { ShowWindow( hWnd, SW_SHOW ); UpdateWindow( hWnd ); } //创建窗口 HWND CreateWnd( LPSTR pszClassName, DWORD nStyle, HWND hParent ) { HWND hWnd = CreateWindowEx( 0, pszClassName, "MyWnd", nStyle, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent,NULL,g_hInst,NULL ); return hWnd; } //注册窗口 BOOL RegisterWnd( LPSTR pszClassName, WNDPROC proc, int nBrush ) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof( wce ); wce.style = CS_HREDRAW|CS_VREDRAW; wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.lpfnWndProc = proc; wce.hIcon = NULL; wce.hCursor = NULL; wce.hbrBackground = HBRUSH( nBrush ); wce.hInstance = g_hInst; wce.lpszClassName = pszClassName; wce.lpszMenuName = NULL; wce.hIconSm = NULL; ATOM nAtom = RegisterClassEx( &wce ); if( 0 == nAtom ) { return FALSE; } return TRUE; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_hInst = hInstance; //注册父窗口类 RegisterWnd( "MyWnd", WndProc, COLOR_BTNFACE+1 ); //注册子窗口类 RegisterWnd( "Child", ChildProc, COLOR_WINDOW ); //创建父窗口 HWND hWnd = CreateWnd( "MyWnd", WS_OVERLAPPEDWINDOW, NULL ); //创建子窗口 HWND hChild1 = CreateWnd( "Child", WS_CHILD|WS_VISIBLE|WS_BORDER| WS_THICKFRAME|WS_CAPTION|WS_SYSMENU| WS_MINIMIZEBOX|WS_MAXIMIZEBOX, hWnd ); HWND hChild2 = CreateWnd( "Child", WS_POPUP|WS_VISIBLE| WS_THICKFRAME|WS_CAPTION|WS_SYSMENU, hWnd ); HWND hChild3 = CreateWnd( "Child", WS_CHILD|WS_VISIBLE|WS_BORDER, hWnd ); //移动窗口位置 MoveWindow( hChild1, 100, 100, 200, 200, TRUE ); MoveWindow( hChild2, 100, 200, 200, 200, TRUE ); MoveWindow( hChild3, 100, 300, 200, 200, TRUE ); //显示父窗口 DisplayWnd( hWnd ); Message( ); return 0; }