Windows核心编程笔记(4)

1.消息循环的原理

1. 消息循环的阻塞
· GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,会等候下一个消息。
· PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。

BOOL PeekMessage(
LPMSG lpMsg,//message information
HWND hWnd,//handle to window
UINT wMsgFilterMin,//first message
UINT wMsgFilterMax,//last message
UINT wRemoveMsg//移除标识
PM_REMOVE/PM_NOREMOVE
)

2. 发送消息
· SendMessage - 发送消息,会等候消息处理的结果
· PostMessage - 投递消息,消息发出后立刻返回,不等候消息的执行结果。

BOOL SendMessage/PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg,//消息ID
WPARAM wParam,//消息参数
LPARAM lParam//消息参数
)

SendMessage会阻塞,PostMessage不会阻塞

3.消息分类
系统消息 - ID范围 0 - 0x03FF
由系统定义好的消息,可以在程序中直接使用。

用户自定义消息 - ID范围 0x0400 - 0x7FFF(31743)
由用户自己定义,满足用户自己的需求,由用户自己发出消息并响应处理。
自定义消息宏:WM_USER

#define MY_MESS WM_USER + 100

可以尝试,将自己定义的消息放入在窗口创建时发送出来:

case WM_CREATE:
        MyCreate(hwnd);
        break;


void MyCreate(HWND hwnd)
{
    PostMessage(hwnd, MY_MESS, 1, 2);
}

看下是否能抓住我们自己发送的消息:

 case MY_MESS:
        My_drive(hwnd, wParam, lParam);
        break;


void My_drive(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    wchar_t text[256] = { 0 };
    wsprintf(text, L"WPARAM的值为%d,LPARAM的值为%d", wParam, lParam);
    MessageBox(hwnd, text,L"infor",MB_OK);
}

全部代码:

#include <windows.h>
#include <stdio.h>
#define MY_MESS WM_USER + 100

HANDLE g_out = 0;
void onsize(HWND hwnd,LPARAM lParam)
{
    short nwidth = LOWORD(lParam);
    short nhight = HIWORD(lParam);
    wchar_t szText[256] = { 0 };
    wsprintf(szText, L"宽度%d,高度%d", nwidth, nhight);
    WriteConsole(g_out, szText, wcslen(szText), NULL, NULL);
}

void MyCreate(HWND hwnd)
{
    PostMessage(hwnd, MY_MESS, 1, 2);
}
void My_drive(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    wchar_t text[256] = { 0 };
    wsprintf(text, L"WPARAM的值为%d,LPARAM的值为%d", wParam, lParam);
    MessageBox(hwnd, text,L"infor",MB_OK);
}

LRESULT CALLBACK test(HWND hwnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
    switch (msgID)
    {
    case WM_SIZE:
        onsize(hwnd, lParam);
        break;
    case WM_CREATE:
        MyCreate(hwnd);
        break;
    case MY_MESS:
        My_drive(hwnd, wParam, lParam);
        break;
    case WM_SYSCOMMAND:
        if (wParam == SC_CLOSE)
        {
            if (MessageBox(hwnd, L"是否关闭?", L"infor", MB_OKCANCEL | MB_ICONEXCLAMATION) == IDOK)
            {
                PostQuitMessage(0);
            }
            else
            {
                return 0;
            }
        }
       
        break;
    }
    return DefWindowProc(hwnd, msgID, wParam, lParam);
}
int CALLBACK wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    AllocConsole();//增加dos窗口
    g_out = GetStdHandle(STD_OUTPUT_HANDLE);
    //注册窗口类
    WNDCLASS wc = { 0 };
    wc.cbClsExtra = 0;//申请缓冲区
    wc.cbWndExtra = 0;//申请缓冲区
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//窗口背景色
    wc.hCursor = NULL;//默认光标
    wc.hIcon = NULL;//默认图标
    wc.hInstance = hInstance;//实例句柄
    wc.lpfnWndProc = test;//窗口处理函数
    wc.lpszClassName = (LPCWSTR)L"main";//窗口类名称
    wc.lpszMenuName = NULL;//不要菜单
    wc.style = CS_HREDRAW | CS_VREDRAW;//窗口水平或竖直方向有变化就重绘窗口
    RegisterClass(&wc);//将以上所有赋值写入操作系统
    //在内存中创建窗口
    HWND hwnd = CreateWindow((LPCWSTR)L"main", (LPCWSTR)L"hello world", WS_OVERLAPPEDWINDOW, 100,100, 500, 500, NULL, NULL, hInstance, NULL);
    //显示窗口
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);
    //消息循环
    MSG nMSG = { 0 };
    while (GetMessage(&nMSG,NULL,0,0))
    {
        TranslateMessage(&nMSG);
        DispatchMessage(&nMSG);//派发消息,将消息交给窗口处理函数处理
    }
    return 0;
}

运行结果:
在这里插入图片描述
4.消息队列

1.消息队列的概念

· 消息队列是用于存放消息的队列

· 消息在队列中先入先出

· 所有窗口程序都具有消息队列

· 程序可以从队列中获取消息

2.消息队列的分类

· 系统消息队列 - 由系统维护的消息队列,存放系统产生的消息,例如鼠标、键盘等。

· 程序消息队列 - 属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。

GetMessage只抓本进程的消息

系统消息队列会每隔一段时间更具窗口句柄,将消息派发到各个进程中去。

3.消息和消息队列的关系

例子:
a. 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
b. 系统会根据存放的消息,找到对应程序的消息队列
c. 将消息投递到程序的消息队列中

根据消息和消息队列之间使用关系,将消息分为俩类:

队列消息 - 消息的发送和获取,都是通过消息队列完成
非队列消息 - 消息的发送和获取,是直接调用消息的窗口处理完成。消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处理函数,完成消息。

例:SendMessage - 直接将消息发送给窗口处理函数,并等候处理结果。
常见消息:WM_CREATE、WM_SIZE等。

3.GetMessage函数
· 在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列取出消息返回

· 如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序的消息队列中。

· 如果系统消息队列也没有消息,检查当前进程的所有窗口的需要重写绘制的区域,如果发现有需要绘制区域,产生WM_PAINT消息,取得消息返回处理。

· 如果没有重新绘制区域,检查定时器如果有到时的定时器,产生WM_TIMER,返回处理执行

· 如果没有到时的定时器,整理程序资源、内存等等。

· GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。

· 注意:GetMessage如果获取到的是WM_QUIT,函数会返回FALSE

5.WM_PAINT
产生时间:当前窗口需要绘制的时候,且GetMessage没有消息可抓时

附带信息:wParam : 0;lParam : 0

专职用法:用于绘图

//窗口无效区域:需要重新绘制的区域
BOOL InvalidateRect(
HWND hWnd,//窗口句柄
CONST RECT* lpRect,//区域的矩形坐标
BOOL bErase//重绘前是否先擦除
);

消息处理步骤:
· 开始绘图

HDC BeginPaint(
HWND hwnd,//绘图窗口
LPPAINTSTRUCT lpPaint//绘图参数的BUFF
)//返回绘图设备句柄HDC

· 正式绘图

· 结束绘图

BOOL EndPaint(
HWND hWnd,
CONST PAINTSTRUCT *lpPaint)
//绘图参数的指针BeginPaint返回
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值