win32API+C分析Windows消息运行原理

来源:互联网 发布:三国志13自创武将数据 编辑:程序博客网 时间:2024/04/30 14:30

用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);

   }

 

原创粉丝点击