对于从编程的角度解析,不要简单地认为是一个程序的窗口,而是如下面定义:
think of a window as a programming construct that:
是一个号码,操作系统使用这一的号码识别对象。操作系统有一个很大的表,包含了所有创建的windows的句柄,操作系统就是通过查找这一的表找到windows的。
记住句柄不是指针。
每个Windows程序都有一个入口点:WinMain 或者 wWinMain
为什么编译器知道激活wWinMain而不是main呢?因为Microsoft C runtime库(CRT)调用WinMain或者wMinMain函数,从而调用main。
这个是用户定义的函数,不过操作系统已经给好了接口,用户定义window的行为:外观,响应消息等等。
程序并不是直接调用这个函数的,操作系统是通过传递消息给这个函数来和我们的程序沟通的。
DispatchMessage函数使得系统激活WindowProc函数,每次去掉一个消息,由这个函数处理。
每一个窗口(window)都必须和一个window class关联。window class是一个提供给操作系统内部使用的数据结构。
分为:
1 用户事件
2 操作系统事件
操作系统使用消息传递模式和我们的程序沟通。一个消息其实就是一个数字代码指示着某一事件。
例如,如果用户点击鼠标右键,窗口接收到一个消息代码0x0201:
#define WM_LBUTTONDOWN 0x0201
用户关闭窗口的时候,会引发一系列消息。如果不处理的话,window就没有真正关闭。
到底有什么一系列的消息呢?听起来很可怕,呵呵。
有WM_CLOSE ,WM_DESTROY 和 WM_QUIT三个消息;
其中WM_QUIT是一个特别的消息,让GetMessage返回0,表示消息循环结束。也因为它是最后发生的消息,所以我们的消息处理程序永远也接受不到WM_QUIT这个消息,也就无法在WindProc中扑捉这个消息。
当用户关闭窗口的时候,windows自动发送WM_CLOSE和WM_DESTROY消息;但是需要我们手动调用PostQuitMessage(0),指明要发送WM_QUIT消息,才能Exit wWinMain,否则系统会停留在wWinMain中。
下面的图来自MSDN,实在把三个消息的关系画的一目了然,不忍割爱,故此贴上来了:
#include<Windows.h> //wParam and lParam contain additional data that pertains to the message. The exact meaning depends on the message code. /* For example, the documentation for the WM_SIZE message states that: wParam is a flag that indicates whether the window was minimized, maximized, or resized. lParam contains the new width and height of the window as 16-bit values packed into one 32- or 64-bit number. You will need to perform some bit-shifting to get these values. Fortunately, the header file WinDef.h includes helper macros that do this. */ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SIZE: { int width = (unsigned long)lParam & 0xff;//LOWORD(lParam); int height = ((unsigned long)lParam >>16)& 0xff;//HIWORD(lParam); } return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOWFRAME)); EndPaint(hwnd, &ps); } return 0; case WM_CLOSE: PostQuitMessage(0); return 0; //MessageBox(hwnd, L"Really quit?", L"My application", MB_OKCANCEL); } return DefWindowProc(hwnd, uMsg, wParam, lParam); } INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) { const wchar_t className[] = L"Fundamental Windows Programming"; //1. Register Class WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = className; RegisterClass(&wc); //2. Create Window HWND hwnd = CreateWindowEx( 0, className, L"Fundamental Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (hwnd == NULL) return 0; //The nCmdShow parameter can be used to minimize or maximize a window. ShowWindow(hwnd, nCmdShow); //Message Loop MSG msg = {}; //This function removes the first message from the head of the queue. If the queue is empty, the function blocks until another message is queued. while (GetMessage(&msg, NULL, 0, 0)) { //The TranslateMessage function is related to keyboard input; it translates keystrokes (key down, key up) into characters. You don't really need to know how this function works; just remember to call it right before DispatchMessage. TranslateMessage(&msg); //The DispatchMessage function tells the operating system to call the window procedure of the window that is the target of the message. In other words, the operating system looks up the window handle in its table of windows, finds the function pointer associated with the window, and invokes the function. DispatchMessage(&msg); } return 0; }