Windows常用消息处理与自定义消息

Windows消息简介

windows消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来说,这个记录中包含了单击鼠标时的坐标。这个记录类型叫做TMsg。

Windows程序都是通过消息机制驱动运行的。

消息分类:

一般根据消息是否进入消息队列可分为两类:

不进队列消息:指由Windows直接调用消息处理函数,把消息直接交给其处理。如 WM_CREATE,WM_SIZE等。

    //WS: Window Style
    HWND hWnd = CreateWindow(
        szAppClassName,                                                            //窗口类型名
        TEXT("这是我的第一个Windows窗口程序"),                                        //窗口左上角标题
        WS_BORDER | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU,    //窗口的风格
        200, 300,                                                                //窗口左上角坐标
        800, 600,                                                                //窗口的宽和高
        NULL,                                                                    //父窗口句柄
        NULL,                                                                    //菜单句柄
        hInstance,                                                                //应用程序实例句柄
        (void*)100                                                                //创建窗口的附加参数,WM_CREATE消息,lParam来接受这个参数
    );

    if (hWnd == NULL)
    {
        MessageBox(NULL, TEXT("创建窗口失败"), TEXT("提示"), MB_OK);
        return 0;
    }
View Code
case WM_CREATE://窗口处理消息,发生在什么时候:窗口还没有显示的时候,通过调用CreateWindow函数或者CreateWindowEx函数,发出这个消息
    {
        MessageBox(NULL, L"这是WM_CREATE消息", L"提示", MB_OK);//阻塞函数,不点不往下走
        CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
        break;
    }
View Code

当执行完CreateWindow后才发出WM_CREATE消息,此时窗口还没显示出来。

 

 

 进队列消息:指Windows将消息放入到程序中的消息队列中取,并通过程序中的消息循环,循环把消息取出,经过一定处理(如例子中经过translate),然后由函数

DispathMessage函数将消息分发给消息处理函数处理,这一类消息为进队列消息。常见的击键的消息(WM_KEYDOWN、WM_KEYUP)键盘输入产生字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)、
鼠标键(WM_LBUTTONDOWN)、计时消息(WM_TIMER)、刷新消息(WM_PAINT)和退出消息(WM_QUIT),这类消息一般是由用户输入引发的。

按照功能划分,消息分为两大类:

系统定义消息

(1)标准消息

除WM_COMMAND之外,所有以WM_开头的消息都是标准消息,例如鼠标单击、移动,键盘左击、右击。

(2)命令消息

来自菜单,加速键或工具栏按钮的消息。这类消息都以WM——COMMAND形式呈现。WM_COMMAND, LOWORD(wParam)表示菜单项,工具栏按钮或一般控件的ID如编辑框,按钮等。如果是控件, HIWORD(wParam)表示控件消息类型

(3)通告消息

由复杂控件产生的消息。这类消息也是以WM——COMMAND形式呈现。 这是最灵活的消息格式, 其Message, wParam, lParam分别为:WM_NOTIFY, 控件ID,指向NMHDR的指针。NMHDR包含控件通知的内容, 可以任意扩展。

用户自定义消息

WM_USER ,1024以下的定义的是系统消息,1024以上的是用户自定消息。

消息发送

提供了两种方式来发送消息:SendMessage和PostMessage。

两者联系与区别:

1.系统定义消息和用户自定义消息均可发送。

2.SendMessage: 是一个阻塞函数,如果发送的消息没有没处理完,则不返回,处理完成,返回结果,并且结果就是SendMessage的返回值

  PostMessage:是一个非阻塞函数,只负责把消息发过去,不会等待消息的处理完成的结果。

3.SendMessage返回值为LRESULT长整型(long),PostMessage为bool值。

4.跨进程跨线程发送消息,推荐使用PostMessage。

 常用消息举例

消息名称 消息参数 备注说明
WM_CREATE消息

WPARAM: 没有使用的

LPARAM: CREATESTRUCT结构体指针

 
WM_CLOSE消息

WPARAM: 没有使用的

LPARAM: 没有使用的

 窗口关闭消息 , 此时还能还原出来窗口,发生在:点击关闭按钮的时候
WM_DESTROY消息  

表示窗口销毁消息, 凡是执行到了WM_DESTROY消息了,那么此时此时已经没有回头路了,不能还原窗口了,因为界面已经被销毁了

发生在什么时候:程序退出,进行清理工作了

WM_LBUTTONDOWN   鼠标左键点击客户区消息
WM_LBUTTONUP   鼠标左键抬起
WM_RBUTTONDOWN   鼠标右键按下
WM_RBUTTONUP   鼠标右键抬起
WM_LBUTTONDBLCLK   鼠标左键双击消息。createwindows的时候style属性要加上CS_DBLCLKS,不然就只是单纯的 两次单击,不会发送此消息
WM_MOUSEMOVE   鼠标移动消息
WM_KEYDOWN   键盘按下消息
WM_KEYUP   按键抬起消息
WM_CHAR   字符消息

Demo附录

#include <Windows.h>
#include "resource.h"
#define UM_TEST                WM_USER+1                

//窗口处理函数
//第一个参数:当前窗口句柄
//第二个参数:消息类型
//第三个参数:附加信息/附加参数
//第四个参数:附加信息/附加参数

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //创建一个窗口
    //流程
    //1.设计窗口类

    wchar_t szAppClassName[] = TEXT("WINDOWS");

    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;                    //窗口类的风格
    wc.lpfnWndProc = WindowProc;                                                //窗口回调函数/窗口处理函数 
    wc.cbClsExtra = 0;                                                        //窗口类的附加内存大小
    wc.cbWndExtra = 0;                                                        //窗口附加内存大小
    wc.hInstance = hInstance;                                                //当前应用程序实例句柄
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));        //图标句柄
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);    //光标句柄
    wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 0));                        //红,绿,蓝 0->255    0:最暗, 255:最亮, RGB(0,0,0):黑色, RGB(255,255,255):白色
    wc.lpszMenuName = NULL;                                                    //菜单名
    wc.lpszClassName = szAppClassName;                                            //窗口类型名 Spy++

    //2.注册窗口类
    //ATOM 
    //ATOM
    if (0 == RegisterClass(&wc))
    {
        MessageBox(NULL, TEXT("此程序不能运行在Windows NT平台."), TEXT("提示"), MB_OK);
        return 0;
    }

    //3.创建窗口
    //WS: Window Style
    HWND hWnd = CreateWindow(
        szAppClassName,                                                            //窗口类型名
        TEXT("这是我的第一个Windows窗口程序"),                                        //窗口左上角标题
        WS_BORDER | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU,    //窗口的风格
        200, 300,                                                                //窗口左上角坐标
        800, 600,                                                                //窗口的宽和高
        NULL,                                                                    //父窗口句柄
        NULL,                                                                    //菜单句柄
        hInstance,                                                                //应用程序实例句柄
        (void*)100                                                                //创建窗口的附加参数,WM_CREATE消息,lParam来接受这个参数
    );

    if (hWnd == NULL)
    {
        MessageBox(NULL, TEXT("创建窗口失败"), TEXT("提示"), MB_OK);
        return 0;
    }

    //4.显示窗口
    //SW_SHOW:原来在什么位置,就在什么位置显示
    //SW_SHOWMAXIMIZED:最大化显示
    //SW_SHOWMINIMIZED:最小化显示
    //SW_SHOWNORMAL:正常显示
    //SW_HIDE:隐藏运行

    ShowWindow(hWnd, SW_SHOW);
    //5.更新窗口 //窗口显示的时候,重新绘制一下
    UpdateWindow(hWnd);
    //6.消息循环

    //Windows程序都是通过消息机制驱动运行

    //GetMessage:什么时候返回FALSE 
    //当获取到WM_QUIT消息时,返回FALSE,退出循环,没有获取到这个消息,返回非0,不退出循环

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))  //0
    {
        //将虚拟键消息转化为字符消息 
        //一个按下消息+抬起消息=》字符消息,WM_KEYDOWN和WM_KEYUP=>WM_CHAR
        TranslateMessage(&msg);
        //将消息分发给窗口处理函数
        DispatchMessage(&msg);
    }

    return 0;
}

//窗口处理函数
//Windows Message缩写
//消息分为两类:
//不进队列消息 WM_CREATE
//进队列消息 :大部分消息时属于这一类

//WM_CREATE消息
//WPARAM: 没有使用的
//LPARAM: CREATESTRUCT结构体指针

//WM_CLOSE消息 窗口关闭消息 , 此时还能还原出来窗口
//发生在:点击关闭按钮的时候
//WPARAM: 没有使用的
//LPARAM: 没有使用的

//WM_DESTROY消息 表示窗口销毁消息, 凡是执行到了WM_DESTROY消息了,那么此时此时已经没有回头路了,不能还原窗口了,因为界面已经被销毁了
//发生在什么时候:程序退出,进行清理工作了

//WM_LBUTTONDOWN鼠标左键点击客户区消息
//WPARAM:
//LPARAM:

//WM_LBUTTONUP:鼠标左键抬起

//WM_RBUTTONDOWN:鼠标右键按下

//WM_RBUTTONUP:鼠标右键抬起

//WM_LBUTTONDBLCLK://鼠标左键双击消息

//WM_MOUSEMOVE:鼠标移动消息

//WM_KEYDOWN:键盘按下消息
//WPARAM:
//LPARAM:

//WM_KEYUP:按键抬起消息


//WM_CHAR:字符消息


//后续讲解
//WM_COMMAND消息
//WM_SYSCOMMAND消息

//消息的分类:0=>65535(消息范围)

//1、系统消息    , 刚才介绍的这一些都是系统消息
//WM_USER    1024以下的定义的是系统消息
//1024以上的是用户自定消息

//2、自定义消息
//如果自定义消息
//宏定义

//3.发送消息
//既可以发送系统消息,又可以发送用户自定义消息
//SendMessage: 是一个阻塞函数,如果发送的消息没有没处理完,则不返回,处理完成,返回结果,并且结果就是SendMessage的返回值
//PostMessage:是一个非阻塞函数,只负责把消息发过去,不会等待消息的处理完成的结果

//SendMessage:用于自己进程发送消息
//PostMessage:向进程外发送信息

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hDC;

    //wchar_t szMsg[200];
    ////sprintf字符串格式化函数,窄字符
    //wsprintf(szMsg, L"窗口句柄:0X%x\t消息:0X%x\twParam:%d\tlParam:%d\n", hWnd, uMsg, wParam,lParam);//字符串格式化函数,宽字符
    //OutputDebugString(szMsg);//仅限于调试

    switch (uMsg)
    {

    case WM_SIZE:
    {
        MessageBox(NULL, L"这是WM_SIZE消息,执行ShowWindow后创建该消息", L"提示", MB_OK);//阻塞函数,不点不往下走
        break;
    }
    case WM_CREATE://窗口处理消息,发生在什么时候:窗口还没有显示的时候,通过调用CreateWindow函数或者CreateWindowEx函数,发出这个消息
    {
        MessageBox(NULL, L"这是WM_CREATE消息", L"提示", MB_OK);//阻塞函数,不点不往下走
        CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
        break;
    }
    case WM_LBUTTONDOWN://鼠标左键点击客户区消息
    {
        //MessageBox(hWnd, L"WM_LBUTTONDOWN", L"提示", MB_OK);
        //int xPos = LOWORD(lParam); //WORD:字,unsigned short , 0-》65535
        //int yPos = HIWORD(lParam);

        //wchar_t szText[100];
        //wsprintf(szText, L"当前鼠标点击坐标(%d,%d)", xPos, yPos);
        //SetWindowText(hWnd, szText);

        //if (wParam & MK_CONTROL)
        //{
        //    wcscat(szText, L"按下了ctrl");
        //}
        //if (wParam & MK_MBUTTON)
        //{
        //    wcscat(szText, L"按下了鼠标中键");
        //}
        //if (wParam & MK_RBUTTON)
        //{
        //    wcscat(szText, L"按下了鼠标右键");
        //}
        //if (wParam & MK_SHIFT)
        //{
        //    wcscat(szText, L"按下了鼠标Shift键");
        //}
        //if (wParam & MK_LBUTTON)
        //{
        //    wcscat(szText, L"按下了鼠标左键;");
        //}
        //
        //////把坐标设置到窗口的标题
        //SetWindowText(hWnd, szText);

        //发送系统消息
        //SendMessage(hWnd, WM_CLOSE, 0, 0);


        //发送一个用户自定义消息
        int result = SendMessage(hWnd, UM_TEST, 45, 50);//阻塞
        BOOL b = PostMessage(hWnd, UM_TEST, 45, 50);//非阻塞
        int a = 20;

        /*HWND hNotepad = FindWindow(L"Notepad", L"无标题 - 记事本");
        if (hNotepad == NULL)
        {
            MessageBox(NULL, L"没有查找到窗口", L"提示", MB_OK);
            break;
        }*/

        //发送一个关闭消息
        //PostMessage(hNotepad, WM_CLOSE, 0, 0);
        //SendMessage(hNotepad, WM_CLOSE, 0, 0);


        break;
    }
    case WM_LBUTTONDBLCLK://createwindows的时候style属性要加上CS_DBLCLKS,不然就只是单纯的 两次单击,不会发送此消息)
    {
        SetWindowText(hWnd, L"双击");
        break;
    }
    case UM_TEST://用户自定义消息 
    {
        int a = (int)wParam;
        int b = (int)lParam;

        int result = a + b;
        return result;
    }

    case WM_MOUSEMOVE://鼠标移动消息
    {
        int xPos = LOWORD(lParam); //WORD:字,unsigned short , 0-》65535
        int yPos = HIWORD(lParam);

        wchar_t szText[100];
        wsprintf(szText, L"当前鼠标点击坐标(%d,%d)", xPos, yPos);

        if (wParam & MK_CONTROL) //按位&
        {
            wcscat(szText, L"按下了Ctrl;");
        }


        //把坐标设置到窗口的标题
        SetWindowText(hWnd, szText);

        break;
    }
    case WM_KEYDOWN://键盘按下消息
    {
        //MessageBox(hWnd, L"提示", L"OK", MB_OK);
        switch (wParam)
        {
        case VK_RETURN://回车键
            SetWindowText(hWnd, L"按下了回车键");
            break;
        }
        break;
    }
    case WM_CHAR://字符消息
    {
        char chCharCode = (TCHAR)wParam;

        wchar_t szText[100];
        wsprintf(szText, L"当前字符:%c", chCharCode);
        SetWindowText(hWnd, szText);
        break;
    }
    case WM_PAINT://客户区绘图消息, GDI绘图技术
    {
        //开始绘图
        HDC hDC = BeginPaint(hWnd, &ps);
        //Rectangle(hDC, 0, 0, 200, 200);矩形
        //绘制椭圆
        Ellipse(hDC, 0, 0, 300, 200);
        //结束绘图
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_CLOSE://窗口关闭消息
    {

        //ShowWindow(hWnd, SW_HIDE);//隐藏
        //return 1;//表示我已经处理了

        if (IDYES == MessageBox(hWnd, L"您确定要关闭吗?", L"温馨提示", MB_YESNO))
        {
            DestroyWindow(hWnd);    //销毁窗口, 干掉界面,不会发出WM_QUIT,会发出一个WM_DESTROY消息
        }
        else
        {
            //break;//还是执行了DefWindowProc系统默认处理,界面销毁,不会退出进程
            //return 0;//没有处理,没有人去处理
            return 1;//我已经处理了,
        }
        break;
    }
    case WM_DESTROY://窗口销毁消息
        //ShowWindow(hWnd, SW_SHOW);        //无力回天了
        PostQuitMessage(0);        //发出WM_QUIT
        break;

    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);//交给操作系统默认处理
}
View Code
 
posted @ 2021-10-07 15:44  liweiyin  阅读(901)  评论(0编辑  收藏  举报