win32&mfc————win32消息机制

文章目录


win32&mfc————win32消息机制_第1张图片

文章目录

  • 文章目录
  • 前言
  • 一、`消息机制`是什么
  • 二、Windows消息机制
    • 1.产生消息
    • 2.消息传递
    • 3.消息处理
  • 三.基本消息
      • 1.窗口创建消息
      • 2.窗口销毁
      • 3.窗口激活
  • 重要消息
      • 1.按键消息
      • 2.字符消息
  • 源代码
  • 总结


前言

前面我们介绍了win32程序框架,并写了一个程序,而这个程序用的就是消息机制。消息机制作为win32程序开发中重要的部分,下面将通过一些案例来认识消息机制。


一、消息机制是什么

消息机制,顾名思义,从字面意思上来理解,就是对消息的处理方式。我们在使用手机的时候,打开一个软件,我们在点击某一个选项的时候,系统就会获取到你点击的信息,然后传送到处理中心,当然,仅仅只是获取你息还不能够完成操作,还需要消息的传送,然后做出与之对应的操作。这也就是
为什么我们点击一个选项的时候,不会出现错误打开的情况。当然,这只是简单的分析,手机的运行不仅仅是如此的简单。

二、Windows消息机制

windows消息机制:产生消息,传递消息,处理消息;

1.产生消息

①.GetMessage(); 只要不是退出消息,返回值就为true;
②.PeekMessage();只要是有消息参数,就返回true,否则返回false;
代码示例:

-- GetMessage()函数;
//参数设置:
BOOL GetMessage(

LPMSG 【LPMSG】,	//具有消息结构的地址
HWND 【的hWnd】,	//窗口的句柄
UINT 【wMsgFilterMin】,	//第一个消息
UINT 【wMsgFilterMax】	// last message
);	 
 while (GetMessage(&msg, nullptr, 0, 0))   //当获得的消息为真时,就返回true;
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  //判断是不是快捷键;
        {
            TranslateMessage(&msg);       
            DispatchMessage(&msg);
        }
    }

--  PeekMessage()
//参数设置
BOOL PeekMessage(

LPMSG 【LPMSG】,	//指向消息结构的指针
HWND 【的hWnd】,	//处理窗口
UINT 【wMsgFilterMin】,	//第一个消息
UINT 【wMsgFilterMax】,	// last message
UINT 【wRemoveMsg】	//删除标志
);	 
 MSG msg;  //使用peekMessage()
    ZeroMemory(&msg, sizeof(msg));  //初始化;
    /*
    VOID ZeroMemory(

PVOID 【目的地】,	//填写零的块地址
DWORD 【长度】	//以块的大小(以字节为单位)填充零
);	 
    */
    while (msg.message != WM_QUIT)  //如果不是退出的消息,就执行消息循环;
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))  //只要鼠标移动,就执行; PM_NOEMOVE是不移动;
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  //判断是不是快捷键;
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }



    }

可能有很多人很疑惑,同样是获取消息,那么为什么两个函数的使用方法会不一样,这个就是由于他们的特性决定的,GetMessage()函数,只要得到的不是退出的消息,就会返回true,而PeekMessage()函数只要有消息参数就返回true。如果在while中直接使用PeekMessage)函数,那么窗口就会直接闪退,你来不及操作,系统会认为你没有给他消息,于是就返回了false,也就会闪退;
由于他们的特性决定,在软件开发中一般使用的是GetMessage(),而在游戏开发中就是用的是PekMessage();

2.消息传递

SendMessage():该函数的消息传送是插队的,也就是说系统会将现在获取的消息优先执行;
PostMessage():该函数的消息传送是排队的,也就是按照消息产生的顺序传送,依次执行。
用一张图来解释:
win32&mfc————win32消息机制_第2张图片
代码演示:

-- SendMessage()
//参数设置
LRESULT SendMessage(

HWND 【的hWnd】,	//目标窗口的句柄
UINT 【消息】,	//要发送的消息
WPARAM 【wParam中】,	//第一个消息参数
LPARAM 【lParam的】	//第二个消息参数
);	 
HWND hwnd = FindWindowA(0, "我的Android手机");  //查找窗口;
                for (i = 0; i < 10; i++)
                {
                    SendMessage(hwnd, WM_PASTE, 0, 0);
                    SendMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
                }
-- PostMessage():
//参数设置
BOOL PostMessage(

HWND 【的hWnd】,	//目标窗口的句柄
UINT 【消息】,	//要发帖
WPARAM 【wParam中】,	//第一个消息参数
LPARAM 【lParam的】	//第二个消息参数
);	 
    HWND hwnd = FindWindowA(0, "我的Android手机");  //查找窗口;
                for (i = 0; i < 10; i++)
                {
                    PostMessage(hwnd, WM_PASTE, 0, 0);
                    PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
                }

3.消息处理

我们在获取消息后,根据获得的消息就可以实现自己的需求,比如我们在获得某一个消息的时候,与之对应的操作就会产生。比如产生一个弹窗,或者出现一句话。等等。
win32&mfc————win32消息机制_第3张图片
比如这里的操作就是我们在点击某一个选项后出现的。

case ID_32774:
            {
                int i = 0;
                HWND hwnd = FindWindowA(0, "我的Android手机");  //查找窗口;
                for (i = 0; i < 10; i++)
                {
                    PostMessage(hwnd, WM_PASTE, 0, 0);
                    PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
                }
                MessageBox(hwnd,_T("消息轰炸开始"),_T("提示"),0);  //消息处理
            }

三.基本消息

1.窗口创建消息

WM_CREATE()窗口创建前响应。

 case WM_CREATE:
        MessageBoxA(hWnd,"你是否要打开窗口","      提示",0);  //利用弹窗来显示窗口创建成功;
        break;

2.窗口销毁

WM_DESTROY

 case WM_DESTROY:
        MessageBoxA(hWnd, "你将会关闭窗口", "警告", MB_OKCANCEL);  //弹窗显示;
        PostQuitMessage(0);
        break;

3.窗口激活

WM_ACTIVATE
①.WA_ACTIVE 通过鼠标单击以外的某些方法激活(例如,通过调用SetActiveWindow功能或使用键盘界面选择窗口)。
②.WA_CLICKACTIVE 通过鼠标点击激活。
③.WA_INACTIVE 停用。
代码示例:

 case WM_ACTIVATE:   //窗口激活;
    {
        switch (wParam)
        {
        case WA_CLICKACTIVE:   //鼠标点击激活;
        {
            HDC hdc = GetDC(hWnd);
            static int j = 0;
            TextOutA(hdc, 0, j, "加油,未来可期", 7);
            j += 20;
        }
        break;
        case WA_ACTIVE:    //通过鼠标以外的方式激活;
        {
            HDC hdc = GetDC(hWnd);
            static int j = 0;
            TextOutA(hdc, 30, j, "加油,未来可期", 7);
            j += 20;
        }
            break;
        case WA_INACTIVE:  //停用;
        {
            MessageBoxA(hWnd, "停用", "提示", 0);
        }
        break;

        }
    }

代码的示例就是这样,win32中的消息很多,只能列举一些,这些我们不需要去死记硬背,不会的可以去查表。win32手册参考表;

重要消息

1.按键消息

windows为按键的一个真实键值准备了一个虚拟键值,对于ascii码中有的数据,用ASCII码就可以表示,如果没有,则为VK_·····;
win32&mfc————win32消息机制_第4张图片
我们在给软件设置快捷键的时候就会用到这里,但是一般不会用这里,一般在创建菜单的时候就会写。下一节我们讲.

2.字符消息

WM_CHAR用来判断字符,并根据需求来表现出相应的响应。
win32&mfc————win32消息机制_第5张图片

这里是写了一个关于回车键的字符消息,一般来说,我们在写快捷键的时候,如果是ALT加某一个字符,是不需要写alt的。

case WM_CHAR:  //字符消息;  
    {
        switch (wParam) 
        {
        case VK_RETURN:
            MessageBoxA(hWnd, "回车键", "提示", 0);
             break;
        case 'Z':
        {
            HDC hdc = GetDC(hWnd);
            TextOutA(hdc, 30, 30, "快捷键Alt+X", 8);
            ReleaseDC(hWnd, hdc);
        }
        break;
        }

    }

win32&mfc————win32消息机制_第6张图片
消息机制就介绍到这里。

源代码

// WindowsProject2.cpp : 定义应用程序的入口点。
//

/*
1.入口函数;
2.窗口注册函数
3.窗口创建函数
4.显示窗口
5.更新窗口
6.主消息循环
7.入口函数返回;
*/

#include "framework.h"
#include "WindowsProject2.h"

#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,      //入口函数;
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
   
    


    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT2, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT2));

   // MSG msg;
  /*  //窗口示例,如果需要就可以去掉;  
  if (MessageBox(0, _T("你是否要选择轰炸"), _T("提示"), MB_ABORTRETRYIGNORE) == IDABORT)
    {
        MessageBoxW(0, _T("对你要轰炸的对象操作"), _T("选择按钮"), 0);
    }*/
        //自己添加的消息提示
    // 主消息循环:
    //while (GetMessage(&msg, nullptr, 0, 0))   //当获得的消息为真时,就返回true;
    //{
    //    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  //判断是不是快捷键;
    //    {
    //        TranslateMessage(&msg);       
    //        DispatchMessage(&msg);
    //    }
    //}
    MSG msg;  //使用peekMessage()
    ZeroMemory(&msg, sizeof(msg));  //初始化;
    /*
    VOID ZeroMemory(

PVOID 【目的地】,	//填写零的块地址
DWORD 【长度】	//以块的大小(以字节为单位)填充零
);	 
    */
    while (msg.message != WM_QUIT)  //如果不是退出的消息,就执行消息循环;
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))  //只要鼠标移动,就执行; PM_NOEMOVE是不移动;
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  //判断是不是快捷键;
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }



    }

    return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex; //表示一个窗口类型的结构体变量;

    wcex.cbSize = sizeof(WNDCLASSEX);  //表示的是自身这个类型的大小;

    wcex.style          = CS_HREDRAW | CS_VREDRAW;  //风格;
    wcex.lpfnWndProc    = WndProc; //**非常重要(窗口消息处理函数)
    wcex.cbClsExtra     = 0;   //类的额外信息;
    wcex.cbWndExtra     = 0;   //窗口的额外信息;
    wcex.hInstance      = hInstance; //当前实例句柄;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT2)); //图标,菜单栏图标;
    wcex.hCursor        = LoadCursor(0, nullptr); //光标;
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  // 背景,一般不需要改变;
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT2); // 菜单;
    wcex.lpszClassName  = szWindowClass;  // 窗口类名;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));  //图标,窗口左上角的图标;

    return RegisterClassExW(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
//创建窗口函数;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass,  //窗口类名,注意,必须是已经注册的窗口类名;
       szTitle, //窗口标题名;
       WS_OVERLAPPEDWINDOW| WS_VSCROLL, // 窗口风格;

      CW_USEDEFAULT,   //窗口的坐标x
       0,  // 窗口的y坐标
       CW_USEDEFAULT, //窗口的宽度
       0, //窗口的高度
       nullptr,  //父窗口菜单句柄
       nullptr, // 窗口菜单句柄
       hInstance, //当前实例句柄
       nullptr); // 保留参数;

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CHAR:  //字符消息;  
    {
        switch (wParam) 
        {
        case VK_RETURN:
            MessageBoxA(hWnd, "回车键", "提示", 0);
             break;
        case 'Z':
        {
            HDC hdc = GetDC(hWnd);
            TextOutA(hdc, 30, 30, "快捷键Alt+X", 8);
            ReleaseDC(hWnd, hdc);
        }
        break;
        }

    }
    //case WM_ACTIVATE:   //窗口激活;
    //{
    //    switch (wParam)
    //    {
    //    case WA_CLICKACTIVE:   //鼠标点击激活;
    //    {
    //        HDC hdc = GetDC(hWnd);
    //        static int j = 0;
    //        TextOutA(hdc, 0, j, "加油,未来可期", 7);
    //        j += 20;
    //    }
    //    break;
        //case WA_ACTIVE:    //通过鼠标以外的方式激活;
        //{
        //    HDC hdc = GetDC(hWnd);
        //    static int j = 0;
        //    TextOutA(hdc, 30, j, "加油,未来可期", 7);
        //    j += 20;
        //}
        //    break;
        //case WA_INACTIVE:  //停用;
        //{
        //    MessageBoxA(hWnd, "停用", "提示", 0);
        //}
        //break;

  /*      }
    }*/
    case WM_CREATE:   //窗口创建;
        MessageBoxA(hWnd,"你是否要打开窗口","      提示",0);  //利用弹窗来显示窗口创建成功;
        break;
   
    
    case WM_COMMAND:      //菜单命令;
        {
            int wmId = LOWORD(wParam);
            // 分析菜单选择:
            switch (wmId)
            {
            
            break;
            case ID_32774:
            {
                int i = 0;
                HWND hwnd = FindWindowA(0, "我的Android手机");  //查找窗口;
                for (i = 0; i < 10; i++)
                {
                    PostMessage(hwnd, WM_PASTE, 0, 0);
                    PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
                }
                MessageBox(hwnd,_T("消息轰炸开始"),_T("提示"),0);
            }
            case IDB_BITMAP1:
                MessageBox(0, 0, 0, 0);
                break;
            case IDM_ABOUT:
           
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
               
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);  //消息默认处理函数;
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        MessageBoxA(hWnd, "你将会关闭窗口", "警告", MB_OKCANCEL);  //弹窗显示;
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

总结

win32中的消息机制是实现操作的重要的部分,但是软件开发不仅仅是这么的简单,设置一个窗口还需要学到菜单等知识,下一节会介绍。这一节就是介绍了一些常用的消息,主要的是学会查表。并能够实际操作。如果有兴趣的同学可以去我主页的资源中,里面有一个用窗口实现的表白资源包;

你可能感兴趣的:(mfc,windows,c++)