Windows顾名思义就是窗口,将窗口程序加入到操作系统中具有里程碑式的意义。掌握窗口程序的实现是学习Win32程序实现的重要环节。
一个Win32窗口程序的实现通常要经历下面3个步骤:
1、注册窗口(窗口的风格、图标、光标、大小等)
2、创建、显示窗口
3、消息循环。
同时需要一个入口函数WinMain和一个消息响应函数。
WinMain()函数是应用程序开始执行时的入口点,通常也是应用程序结束任务退出时的出口点。它与DOS程序的main()函数起同样的作用,不同的是,WinMain()函数必须带有四个参数,将在函数调用时传递给操作系统。
消息响应函数也可以叫做消息处理函数、窗口过程函数,它的作用就是处理该窗口的各种消息,比如鼠标的点击、键盘的输入、最大化、最小化、关闭等操作。与我们调用的函数不同,消息响应函数属于回调函数(由我们按系统的要求编写,然后被系统调用的函数),系统将在该窗口收到某条消息的时候使用我们提供的消息响应函数进行响应。
大体代码如下:
#include <windows.h> #include <tchar.h> LRESULT _stdcall WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hwnd; WNDCLASS wndcls; MSG msg; /*↓↓↓↓↓↓↓↓↓↓↓↓注册窗口↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/ wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)COLOR_WINDOW; wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION); wndcls.hInstance=hInstance; wndcls.lpfnWndProc=WndProc; wndcls.lpszClassName=_T("ClassName"); wndcls.lpszMenuName=_T("MenuName"); wndcls.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); /*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/ /*↓↓↓↓↓↓↓↓↓↓↓创建、显示窗口↓↓↓↓↓↓↓↓↓↓↓↓*/ hwnd=CreateWindow(_T("ClassName"),_T("WindowsName"),WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); /*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/ /*↓↓↓↓↓↓↓↓↓↓↓消息循环↓↓↓↓↓↓↓↓↓↓↓↓*/ while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } /*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/ return (int)msg.wParam; } /*↓↓↓↓↓↓↓↓↓↓↓窗口过程函数↓↓↓↓↓↓↓↓↓↓↓↓*/ LRESULT _stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: return DefWindowProc(hwnd, uMsg, wParam, lParam); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }
如果消息循环结束了,退出码存放在 MSG 中的 wParam中, 我们把它返回给windows。
我们也可以将注册窗口、创建显示窗口封装成函数,已让结构更加的清晰。
1 #include <windows.h> 2 #include <tchar.h> 3 4 LRESULT _stdcall WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); 5 ATOM RegistreClass(HINSTANCE hInstance); 6 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow); 7 8 int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 9 { 10 MSG msg; 11 RegistreClass(hInstance);// 12 InitInstance(hInstance, nCmdShow);// 13 while(GetMessage(&msg,NULL,0,0)) 14 { 15 TranslateMessage(&msg); 16 DispatchMessage(&msg); 17 } 18 return (int)msg.wParam; 19 } 20 21 ATOM RegistreClass(HINSTANCE hInstance) 22 { 23 WNDCLASS wndcls; 24 wndcls.cbClsExtra=0; 25 wndcls.cbWndExtra=0; 26 wndcls.hbrBackground=(HBRUSH)COLOR_WINDOW; 27 wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); 28 wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION); 29 wndcls.hInstance=hInstance; 30 wndcls.lpfnWndProc=WndProc; 31 wndcls.lpszClassName=_T("ClassName"); 32 wndcls.lpszMenuName=_T("MenuName"); 33 wndcls.style=CS_HREDRAW | CS_VREDRAW; 34 35 return RegisterClass(&wndcls); 36 } 37 38 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 39 { 40 HWND hWnd; 41 hWnd=CreateWindow(_T("ClassName"),_T("WindowsName"),WS_OVERLAPPEDWINDOW, 42 0,0,600,400,NULL,NULL,hInstance,NULL); 43 if (!hWnd) 44 { 45 return FALSE; 46 } 47 ShowWindow(hWnd,SW_SHOWNORMAL); 48 UpdateWindow(hWnd); 49 return TRUE; 50 } 51 52 LRESULT _stdcall WndProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam) 53 { 54 switch(uMsg) 55 { 56 case WM_COMMAND: 57 return DefWindowProc(hwnd, uMsg, wParam, lParam); 58 break; 59 case WM_DESTROY: 60 PostQuitMessage(0); 61 break; 62 default: 63 return DefWindowProc(hwnd, uMsg, wParam, lParam); 64 } 65 return 0; 66 }
WinMain和WndProc函数前面的stdcall是一种函数调用约定,不同于C语言默认的cdecl调用。采用stdcall的函数,在结束时,函数自身将清理“栈”,恢复到调用之前的状态。大多数API函数都是使用stdcall的方式。而采用cdecl的函数将由该函数的调用者对“栈”进行清理。