前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Win32 最简单的窗口模板和常用的5个消息参数使用示例

Win32 最简单的窗口模板和常用的5个消息参数使用示例

作者头像
独元殇
发布2023-03-16 11:03:00
9980
发布2023-03-16 11:03:00
举报
文章被收录于专栏:独元殇的文章

一个很常用的生成窗口模板

相比于 vc++ 默认实例的那个两百行,这个精简很多。

代码语言:javascript
复制
#include <windows.h>
#include <stdio.h>

// 不使用 Win98 风格
#pragma comment(linker,"\"/manifestdependency:type='win32'  name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

// 窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {

    // 关闭窗口
    switch (msgID) {
    case WM_DESTROY:
        PostQuitMessage(0); // 可以使 GetMessage 函数返回 0 
        break;
    }

    return DefWindowProc(hWnd, msgID, wParam, lParam);
}

// 入口函数
//int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow) {  // 旧版本入口用这行
int WINAPI wWinMain(HINSTANCE hIns, HINSTANCE hPreIns, PWSTR lpCmdLine, int nCmdShow){        // vs 2022 用的这行

    // 注册窗口类
    WNDCLASS wc = { 0 };
    wc.cbClsExtra = 0;  // 窗口类的附加数据 buff 的大小
    wc.cbWndExtra = 0;  // 窗口的附加数据 buff 的大小
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  // 绘制窗口背景的画刷句柄
    wc.hCursor = NULL;  // 鼠标的句柄
    wc.hIcon = NULL;  // 窗口图标的句柄
    wc.hInstance = hIns;  // 当前模块的实例句柄
    wc.lpfnWndProc = WndProc;  // 窗口处理函数
    wc.lpszClassName = "Main";  // 窗口类的名称
    wc.lpszMenuName = NULL;  // 窗口菜单的资源 ID 字符串
    wc.style = CS_HREDRAW | CS_VREDRAW;  // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)

    // 将以上全部赋值全部写入操作系统
    RegisterClass(&wc);

    // 在内存中创建窗口
    HWND hWnd = CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);

    /* CreateWindowEx 是加强版函数
        多了一个dwExStyle: 窗口的扩展风格

        窗口创建的过程:

        1、根据窗口名称,到每一个窗口类中找到相应的窗口。
        2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
        3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
    */

    // 显示窗口
    ShowWindow(hWnd, SW_SHOW);

    // 刷新窗口
    UpdateWindow(hWnd);

    // 消息循环
    MSG nMsg = { 0 };
    while (GetMessage(&nMsg, NULL, 0, 0)) {
        TranslateMessage(&nMsg);
        DispatchMessage(&nMsg); // 将窗口交给窗口处理函数来处理
    }

    return 0;
}

五个常见消息

这里消息是大写字母常量,真正的消息是数字,这些常量就是代表的数字。

1. WM_DESTROY (销毁)

产生时间:窗口被销毁时(不是关闭按钮)

常用于窗口被销毁前做的善后处理,如资源和内存

2. WM_SYSCOMMAND (系统点击)

产生时间:点击最大化、最小化、关闭等产生

返回参数 wParam:具体点击的位置,如 SC_CLOSE 关闭 lParam:鼠标光标位置 LOWORD(lParam); //水平位置 HIWORD(lParam); //垂直位置

常用于窗口关闭时,提示用户处理

3. WM_CREATE (创建窗口前)

产生时间:在窗口创建成功但还未显示时。

返回参数 wParam 为 0 lParam 类型是CREATETRUCT类型的指针 可获取到CreatWindowEx中的全部12个参数

常用于初始化窗口的参数

4. WM_SIZE (改变大小)

产生时间:窗口大小发生变化后

返回参数 wParam 窗口大小变化的原因 lParam 窗口变化后的大小 LOWORD(lParam); //变化后的宽度 HIWORD(lParam); //变化后的高度

常用于窗口变化后,调整各个部分的布局

5. WM_QUIT (开发者自行销毁进程)

产生时间:程序员发生

返回参数 wParam :PostQuitMessage 函数传递的参数 lParam : 0

用于退出。由 GetMessage 接收


使用实例

代码语言:javascript
复制
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;  // 接受标准输出句柄

void OnCreate(HWND hWnd, LPARAM lParam){
    /* 下面三行代码,把开发者在创建窗口之前弹出那个自定义的字符串pszTest */
    CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
    char* pszText = (char*)pcs->lpCreateParams;
    // MessageBox(NULL,pszText,"Infor",MB_OK);

    // 还能创建一个子窗口
    CreateWindowEx(0,"EDIT","hello",WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);
}

// 打印长宽高信息
void OnSize( HWND hWnd, LPARAM lParam ){
    short nWidth = LOWORD(lParam);
    short nHight    = HIWORD(lParam);

    char szText[256] = { 0 };
    sprintf( szText, "WM_SIZE:宽:%d,高:%d\n",nWidth,nHight);
    WriteConsole( g_hOutput, szText, strlen(szText), NULL, NULL);
}

// 窗口处理函数(自定义,处理消息)
// 参数:窗口句柄、消息ID,消息参数、消息参数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID, WPARAM wParam,LPARAM lParam){

    // 关闭窗口
    switch(msgID){
    case WM_SIZE:
        OnSize(hWnd, lParam);
        break;
    case WM_CREATE:
        OnCreate(hWnd, lParam);
        break;
    case WM_DESTROY:
        PostQuitMessage(0); // 可以使 GetMessage 函数返回 0 
        /* 
            PostQuitMessage(0) 可以在 GetMessage 函数经常走的道上埋下
                一个叫 WM_QUIT 的雷,当 GetMessage 抓取到这雷,则返回 0 
        */
        break;
    case WM_SYSCOMMAND:
        if(wParam == SC_CLOSE){
            int nRet = MessageBox( hWnd,"是否退出?","Infor",MB_YESNO);
            if(nRet == IDYES){
                // 什么都不写

            }else{
                return 0;
            }
        }
        break;
    }

    return DefWindowProc( hWnd,msgID,wParam,lParam);  // 给各种消息默认处理
}

// 入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow){
    //增加 DOS 窗口
    AllocConsole();
    g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    // 注册窗口类
    WNDCLASS wc = { 0 };
    wc.cbClsExtra = 0;  // 窗口类的附加数据 buff 的大小
    wc.cbWndExtra = 0;  // 窗口的附加数据 buff 的大小
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  // 绘制窗口背景的画刷句柄
    wc.hCursor = NULL;  // 鼠标的句柄
    wc.hIcon = NULL;  // 窗口图标的句柄
    wc.hInstance = hIns;  // 当前模块的实例句柄
    wc.lpfnWndProc = WndProc;  // 窗口处理函数
    wc.lpszClassName = "Main";  // 窗口类的名称
    wc.lpszMenuName = NULL;  // 窗口菜单的资源 ID 字符串
    wc.style = CS_HREDRAW|CS_VREDRAW;  // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)

    /*
        如果要创建子窗口
        1. 需要设置父窗口的句柄。
        2. 创建风格(即 CreateWindow 第三个参数)要增加 WS_CHILD|WS_VISIBLE
    */
    // 将以上全部赋值全部写入操作系统
    RegisterClass( &wc );

    // 在内存中创建窗口
    char* pszText = "hello data!";
    HWND hWnd = CreateWindow( "Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,pszText);

    /* CreateWindowEx 是加强版函数 
        多了一个dwExStyle: 窗口的扩展风格

        窗口创建的过程:

        1、根据窗口名称,到每一个窗口类中找到相应的窗口。
        2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
        3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
    */

    // 创建子窗口类
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.hCursor = NULL;
    wc.hIcon = NULL;
    wc.hInstance = hIns;
    wc.lpfnWndProc = DefWindowProc;
    wc.lpszClassName = "Child";
    wc.lpszMenuName = NULL;
    wc.style = CS_HREDRAW|CS_VREDRAW;
    RegisterClass( &wc );

    // 创建子窗口
    // HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
    // HWND hChild2 = CreateWindowEx(0,"Child","c2",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);

    // 显示窗口
    ShowWindow( hWnd,SW_SHOW);

    // 刷新窗口
    UpdateWindow( hWnd );

    // 消息循环
    MSG nMsg = { 0 };
    while( GetMessage(&nMsg,NULL,0,0) ){
        TranslateMessage( &nMsg );
        DispatchMessage( &nMsg ); // 将窗口交给窗口处理函数来处理
    }
    /*
        消息的组成

        1.窗口句柄
        2.消息ID
        3.消息的两个参数
        4.消息产生的时间
        5.消息产生时的鼠标位置

        GetMessage : 到系统内抓本进程的消息
        参数:
            LPMSG lpMsg // 存放获取的消息BUFF
            HWND hWnd // 窗口句柄(填某个句柄,只抓取那个窗口的消息,如果填 NULL 则都抓取)
            UINT wMsgFilterMin // 获取消息的最小ID(这两个参数,限定消息的范围,如果都为0,则不限制)
            UINT wMsgFilterMax // 获取消息的最大ID
        返回值:
            直接决定程序能不能退出

        TranslateMessage -翻译消息,将 按键翻译成字符消息
            tips: 内部第一件事先检查消息是不是按键消息
    */

    return 0;
}

自定义消息处理函数

代码语言:javascript
复制
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;  // 接受标准输出句柄

#define WM_MYMESSAGE WM_USER+1001  //自己定制消息,WM_USER = 0x400

void OnCreate(HWND hWnd, LPARAM lParam){
    /* 下面三行代码,把开发者在创建窗口之前弹出那个自定义的字符串pszTest */
    CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
    char* pszText = (char*)pcs->lpCreateParams;
    // MessageBox(NULL,pszText,"Infor",MB_OK);

    // 还能创建一个子窗口
    CreateWindowEx(0,"EDIT","hello",WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);

    // 自定义消息
    PostMessage( hWnd,WM_MYMESSAGE, 1, 2);
}

// 打印长宽高信息
void OnSize( HWND hWnd, LPARAM lParam ){
    short nWidth = LOWORD(lParam);
    short nHight    = HIWORD(lParam);

    char szText[256] = { 0 };
    sprintf( szText, "WM_SIZE:宽:%d,高:%d\n",nWidth,nHight);
    WriteConsole( g_hOutput, szText, strlen(szText), NULL, NULL);
}

// 自定义消息的处理函数
void OnMyMessage( HWND hWnd, WPARAM wParam, LPARAM lParam ){
    char szText[256] = { 0 };
    sprintf( szText,"自定义消息被处理:wParam=%d,lParam=%d\n",wParam,lParam);
    MessageBox( hWnd, szText, "Infor", MB_OK);
}
// 窗口处理函数(自定义,处理消息)
// 参数:窗口句柄、消息ID,消息参数、消息参数
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID, WPARAM wParam,LPARAM lParam){

    // 关闭窗口
    switch(msgID){
    case WM_MYMESSAGE:
        OnMyMessage( hWnd, wParam, lParam);
        break;
    case WM_SIZE:
        OnSize(hWnd, lParam);
        break;
    case WM_CREATE:
        OnCreate(hWnd, lParam);
        break;
    case WM_DESTROY:
        PostQuitMessage(0); // 可以使 GetMessage 函数返回 0 
        /* 
            PostQuitMessage(0) 可以在 GetMessage 函数经常走的道上埋下
                一个叫 WM_QUIT 的雷,当 GetMessage 抓取到这雷,则返回 0 
        */
        break;
    case WM_SYSCOMMAND:
        if(wParam == SC_CLOSE){
            int nRet = MessageBox( hWnd,"是否退出?","Infor",MB_YESNO);
            if(nRet == IDYES){
                // 什么都不写

            }else{
                return 0;
            }
        }
        break;
    }

    return DefWindowProc( hWnd,msgID,wParam,lParam);  // 给各种消息默认处理
}

// 入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdShow, int nCmdShow){
    //增加 DOS 窗口
    AllocConsole();
    g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    // 注册窗口类
    WNDCLASS wc = { 0 };
    wc.cbClsExtra = 0;  // 窗口类的附加数据 buff 的大小
    wc.cbWndExtra = 0;  // 窗口的附加数据 buff 的大小
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  // 绘制窗口背景的画刷句柄
    wc.hCursor = NULL;  // 鼠标的句柄
    wc.hIcon = NULL;  // 窗口图标的句柄
    wc.hInstance = hIns;  // 当前模块的实例句柄
    wc.lpfnWndProc = WndProc;  // 窗口处理函数
    wc.lpszClassName = "Main";  // 窗口类的名称
    wc.lpszMenuName = NULL;  // 窗口菜单的资源 ID 字符串
    wc.style = CS_HREDRAW|CS_VREDRAW;  // 窗口类的风格(CS_DBLCLICK|CS_NOCLOSE)

    /*
        如果要创建子窗口
        1. 需要设置父窗口的句柄。
        2. 创建风格(即 CreateWindow 第三个参数)要增加 WS_CHILD|WS_VISIBLE
    */
    // 将以上全部赋值全部写入操作系统
    RegisterClass( &wc );

    // 在内存中创建窗口
    char* pszText = "hello data!";
    HWND hWnd = CreateWindow( "Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,pszText);

    /* CreateWindowEx 是加强版函数 
        多了一个dwExStyle: 窗口的扩展风格

        窗口创建的过程:

        1、根据窗口名称,到每一个窗口类中找到相应的窗口。
        2、如果找到,把 HINSTANCE (即 hIns)对比,如果相等,创建窗口。
        3、找不到,到应用程序全局窗口类中寻找,还没找到,到系统窗口类寻找
    */

    // 创建子窗口类
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.hCursor = NULL;
    wc.hIcon = NULL;
    wc.hInstance = hIns;
    wc.lpfnWndProc = DefWindowProc;
    wc.lpszClassName = "Child";
    wc.lpszMenuName = NULL;
    wc.style = CS_HREDRAW|CS_VREDRAW;
    RegisterClass( &wc );

    // 创建子窗口

    // HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
    // HWND hChild2 = CreateWindowEx(0,"Child","c2",WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);

    // 显示窗口
    ShowWindow( hWnd,SW_SHOW);

    // 刷新窗口
    UpdateWindow( hWnd );

    /* 消息循环*/
    MSG nMsg = { 0 };

    /* 这种方式效率太低,注释掉 */
    /*while( GetMessage(&nMsg,NULL,0,0) ){ 
        TranslateMessage( &nMsg );
        DispatchMessage( &nMsg ); // 将窗口交给窗口处理函数来处理
    }*/

    /* 使用这个方法,(PeekMessage)可以作为侦察兵 */
    while(1){
        if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)){
            // 侦察兵侦查到有消息
            if(GetMessage(&nMsg,NULL,0,0)){
                // 消息为真
                TranslateMessage( &nMsg );
                DispatchMessage( &nMsg );
            }else{
                return 0;
            }
        }else{
            // 空闲处理(利用空闲的时间,即没有消息的时间,来做点事)
            WriteConsole( g_hOutput, "OnIdle", strlen("OnIdles"), NULL, NULL);
        }
    }

    /*

    */
    /*
        消息的组成

        1.窗口句柄
        2.消息ID
        3.消息的两个参数
        4.消息产生的时间
        5.消息产生时的鼠标位置

        GetMessage : 到系统内抓本进程的消息
        参数:
            LPMSG lpMsg // 存放获取的消息BUFF
            HWND hWnd // 窗口句柄(填某个句柄,只抓取那个窗口的消息,如果填 NULL 则都抓取)
            UINT wMsgFilterMin // 获取消息的最小ID(这两个参数,限定消息的范围,如果都为0,则不限制)
            UINT wMsgFilterMax // 获取消息的最大ID
        返回值:
            直接决定程序能不能退出

        TranslateMessage -翻译消息,将 按键翻译成字符消息
            tips: 内部第一件事先检查消息是不是按键消息
    */

    return 0;
}

/*
    五个常见消息(都是代表一个数字)。:

        1. WM_DESTROY
            窗口被销毁时(不是关闭按钮)
            常用于窗口被销毁前做的善后处理,如资源和内存

        2. WM_SYSCOMMAND
            点击最大化、最小化、关闭等产生
            附带信息,wParam:具体点击的位置,如 SC_CLOSE 关闭
                          lParam:鼠标光标位置
                            LOWORD(lParam); //水平位置
                            HIWORD(lParam); //垂直位置

            常用于窗口关闭时,提示用户处理

        3. WM_CREATE 
            在窗口创建成功但还未显示时。
                wParam 为 0 
                lParam 类型是CREATETRUCT类型的指针
                    可获取到CreatWindowEx中的全部12个参数
                常用于初始化窗口的参数

        4. WM_SIZE
            窗口大小发生变化后
                wParam 窗口大小变化的原因 
                lParam 窗口变化后的大小
                    LOWORD(lParam); //变化后的宽度
                    HIWORD(lParam); //变化后的高度

                常用于窗口变化后,调整各个部分的布局

            5. WM_QUIT
                程序员发生
                    wParam :PostQuitMessage 函数传递的参数
                    lParam : 0

                用于退出。由 GetMessage 接收
*/

/*
    发送消息的两个函数
        1. SendMessage() - 发送消息 - 像打电话
        2. PostMessage() - 投递消息 - 像投递信件 

        两者的不同是,第一个会等消息处理的结果,无结果会阻塞
            ,第二个发送后立即返回,不等结果

        上面的 
        PostQuitMessage(0); 等同于 PostMessage( hWnd, WM_QUT, 0, 0);

    系统消息
        ID范围 0 - 0x03FF
        由系统定义好的消息,可以在系统中直接使用

    用户自定义消息
        ID范围 0x0400 - 0x7FFF (31743个消息)
            由用户自己定义,满足用户自己的需求。

*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-1-25 1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一个很常用的生成窗口模板
  • 五个常见消息
    • 1. WM_DESTROY (销毁)
      • 2. WM_SYSCOMMAND (系统点击)
        • 3. WM_CREATE (创建窗口前)
          • 4. WM_SIZE (改变大小)
            • 5. WM_QUIT (开发者自行销毁进程)
            • 自定义消息处理函数
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档