用win32API+C分析Windows消息运行原理
author:chinanetboy
blog:http://blog.csdn.net/chinayaosir
writedate:09/14/2007晚上8:00
------------------------------------------------------------------------------
API+ C角度实现窗口程序的,来看Window的消息运行原理
window32程序设计总结:
1.处理消息是window程序的灵魂+2.制作界面是window程序的肉体
自然对各种消息的接受,处理,分发就成了window下的程序主要的任务
编辑和制作资源文件就成window程序界面的主要任务.(window是以窗口的形式来让人们使用的,而窗口的各种元素都是包含在资源文件中)
实际上大部分的C++制作的游戏,都是在这个框架下+DX或者+opengl实现的,而不是去用MFC来实现。
一个完整的win32窗口程序要能正常的运行,它就必须包括下面3个部分
1.主程序函数WinMain() 主要工作:注册一个窗口结构和加载各种资源,把窗口显示出来,并进入窗口消息循环
2. 程序消息函数CALLBACK WndProc() 主要工作:对各种消息进行分析和处理
3. window的消息队列中心 主要工作:对windows操作上的一切消息进行处理
为什么主程序函数WinMain()里面没有调用WndProc的任何语句,但是WndProc函数却依然能为主程序函数WinMain()工作呢?
答:这就是还有第三者在它们之间互传递消息,起到一个桥的作用,它就是window的消息队列中心,也就是window的内核.
消息处理的情况介绍如下
下面进行简称
window的消息队列中心简称 <W消息中心>
主程序函数WinMain()简称 <窗口主程序>
程序消息函数CALLBACK WndProc()简称 <消息函数>
1.当键盘或者鼠标有动作的时候,窗口程序怎么来处理这些消息?
首先由<W消息中心>接收到用户的消息,并把它们放入到系统的消息队列中,<窗口主程序>的GetMessage()总是经常的去消息队列中查找是否有自己的消息,
(这就是著名的windows 的6毫秒的时间片实现的多用户处理操作系统,性能还是远比不上UNIX这样子的多用户系统的,如同手机的一直会过一段时间就会发送消息到电信中心一样,),
如果有,经过<窗口主程序>的TranslateMessage(&msg)对消息进行分解,用DispatchMessage(&msg)把消息分发到<W消息中心>的消息中心进行排队,
然后由<W消息中心>的消息中心根据窗口ID(窗口句柄)发送到指定窗口,窗口的<消息函数>自动进行消息判断并分别进行不同的处理!
2.当点击一个窗口的菜单,却能打开另一个窗口程序,这个消息又是怎么处理的呢?
其实这有多个方法:
1.直接把这个消息发送到窗口的<消息函数>,经常用API函数SendMessage(),PostMessage()直接发送
2.把消息发送到<W消息中心>,然后<窗口主程序>取得消息,<消息函数>来处理消息
//所有消息总分为4种 (事件消息,控件消息,重绘窗口消息,关闭窗口的消息)
WM_COMMAND:包括事件消息,控件消息,默认窗口处理消息,它又细分为事件消息和控件ID消息
WM_PAINT:这是重绘窗口消息,主要是窗口外观上变化的各种消息
WM_DESTROY:处理关闭窗口的消息,用PostQuitMessage()告诉<W消息中心>,注销这个窗口的所有消息和数据默认的windows消息
A.<窗口主程序> WinMain()的主要流程1-5步
1.注册好窗体结构,用API函数MyRegisterClass()装入窗口程序要用到的各种资源
2.建立窗口对象,用API函数CreateWindow把上一步的窗体结构建立一个对象
3.显示窗口对象,用API函数ShowWindow();
4.更新窗口对象,用API函数UpdateWindow()
5.进入窗口消息循环(GetMessage, TranslateMessage, DispatchMessage)
循环程序体如下
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
完整代码参考如下
// WIN32.cpp : Defines the entry point for the application.
#include "stdafx.h"
#include "resource.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{ return FALSE; }
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WIN32);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
// FUNCTION: MyRegisterClass()
// PURPOSE: Registers the window class.
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_WIN32);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_WIN32;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
// FUNCTION: InitInstance(HANDLE, int)
// PURPOSE: Saves instance handle and creates main window
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
B.<消息函数> WndProc()的主要流程
用如程序方式来表达,处理方法见如下代码
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
…
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
…
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}