孙鑫VC++第一章 Windows程序内部运行机制

news2024/11/27 16:29:33

目录

1.1 API和SDK

1.2 窗口和句柄

1.3 消息和队列

1.4 WinMain

1.4.1 WinMain函数的定义

1.4.2 窗口的创建

1.4.3 消息循环

1.4.4 窗口过程函数


1.1 API和SDK

API:Windows操作系统提供给应用程序编程的接口。
SDK(软件开发包):用于开发的所有资源的集合。

  • 1箭头表示操作系统控制输出设备

  • 2箭头表示操作系统可以得到输入设备信息

  • 3箭头表示应用程序通知操作系统执行具体操作 操作系统提供给应用程序的接口 API

  • 4箭头表示输入设备变化告诉应用程序

1.2 窗口和句柄

句柄:系统在创建资源时会为他们分配内存,并返回这些资源的标识号,即句柄。(类似于指针)

窗口句柄(HWND)、图标(HICON)、光标(HCURSOR)、画刷(HBRUSH)

1.3 消息和队列

typedef struct tagMSG {
  HWND   hwnd;           //HWND:窗口变量,hwnd:消息所属的窗口
  UINT   message;        //message消息标识符,数值定义为WM_XXX  (P4)
  WPARAM wParam; 
  LPARAM lParam;         //指定消息的附加信息,ASCII等
  DWORD  time;           //消息投递到消息队列中的时间
  POINT  pt;             //当前鼠标的位置
} MSG, *PMSG;

1.4 WinMain

Win32实现的步骤:

  • 定义WinMain函数;
  • 创建窗口;
  • 消息循环;
  • 窗口过程函数。

1.4.1 WinMain函数的定义

winmain函数是程序入口函数,由系统调用。

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance,always NULL in Win32
  LPSTR lpCmdLine,          // 空终止的字符串,指定传递给应用程序的命令行参数
  int nCmdShow              // 指定窗口应该如何显示
  );

1.4.2 窗口的创建

步骤:

  • 设计窗口类;
  • 注册窗口;
  • 创建窗口;
  • 显示及更新窗口;

1. 设计窗口类

typedef struct _WNDCLASS                //窗口类
{ 
    UINT       style;                      /*(P7知识点方框)窗口样式;
                                             CS_XXX(都只有一位是1,且1位各不相同:位标志);
                                             多种特点组合用(|)号;
                                             去掉style中的样式用(&~)*/
    WNDPROC    lpfnWndProc;             //指向回调函数的指针;在特定的事件发生时,用于对该事件的响应
    int        cbClsExtra;               
    int        cbWndExtra;              //cbClsExtra和cbWndExtra两个附加内存,一般都为0
    HINSTANCE  hInstance;               //实例句柄
    HICON      hIcon;                  //图标句柄;HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
    HCURSOR    hCursor;                  //光标句柄;HCURSOR LoadCursor(HINSTANCE hInstance,LPCTSTR lpCursorName);
    HBRUSH     hbrBackground;        //画刷句柄,背景颜色;wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    LPCTSTR    lpszMenuName;           //菜单名字,NULL
    LPCTSTR    lpszClassName;             //类名,和创建窗口CreateWindow函数中的lpClassName一致
} WNDCLASS, *PWNDCLASS;

2. 注册窗口

ATOM RegisterClass(  CONST WNDCLASS *lpWndClass ); // 注册窗口

3. 创建窗口

HWND CreateWindow(  
  LPCTSTR lpClassName,  // registered class name,与窗口类WNDCLASS中的lpszClassName一致
  LPCTSTR lpWindowName, // window name,
  DWORD dwStyle,        /*window style;和WNDCLASS中的style不同,style是指定具体窗口的样式,dwstyle是窗口都具有的样式
                        常用WS_OVERLAPPEDWINDOW*/
  int x,                // horizontal position of window
  int y,                // vertical position of window
  int nWidth,           // window width
  int nHeight,          // window height;
                        /*如果x设为CW_USEDEFAULT,系统为窗口选择左上角并忽略y;
                        nWidth设为CW_USEDEFAULT,系统为默认大小并忽略nHeight。
                        窗口之间的父子关系,子窗口必须有WS_CHILD*/
  HWND hWndParent,      // handle to parent or owner window(父窗口句柄);NULL
  HMENU hMenu,          // menu handle or child identifier;NULL
  HINSTANCE hInstance,  // handle to application instance;hInstance
  LPVOID lpParam        // window-creation data;NULL
);

注意:创建窗口成功,函数返回系统为该窗口分配的句柄,否则返回NULL。创建窗口之前应先定义一个窗口句柄变量来接收创建窗口之后返回的句柄值。

4. 显示及更新窗口

  • 显示
BOOL ShowWindow(
  HWND hWnd,     // 
  int nCmdShow   // 常用SW_SHOWNORMAL
);
  • 更新窗口
BOOL UpdateWindow(
    HWND hWnd   // handle to window
);

1.4.3 消息循环

BOOL GetMessage(
  LPMSG lpMsg,         // 指向一个消息结构体MSG,GetMessage取出的消息放入该结构体对象中
  HWND hWnd,           // handle to window,设为NULL接收所用窗口
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax   // last message;范围过滤,获得所有消息则设为0
);

注意:GetMessage函数除了接收到WM_QUIT(退出消息)外都返回非零值,出错返回-1。

通常编写的消息循环代码如下:

MSG msg;//声明消息结构体变量
while(GetMessage(&msg,NULL,0,0))//没接收到WM_QUIT时一致循环
{
    TranslateMessage(&msg);//将WM_KEYDOWN和WM_KEYUP转化为WM_CHAR,不修改原消息
    DispatchMessage(&msg);//将消息发送至操作系统,后者用窗口过程函数对消息响应; Dispatch:派遣
}

1.4.4 窗口过程函数

即回调函数

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // 窗口句柄
  UINT uMsg,      // 消息代码
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

过程函数名WindowProc可以换,但要和声明保持一致。
使用switch/case来对不同消息作出不同反应。
如下方例子中的过程函数所示。

例子1.1
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <stdexcept>

/*******************函数声明****************************/
LRESULT CALLBACK WinSunProc(
    HWND hwnd,      // handle to window
    UINT uMsg,      // message identifier
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
);

/*******************WinMain函数*************************/
int WINAPI WinMain(
    HINSTANCE hInstance,      // handle to current instance
    HINSTANCE hPrevInstance,  // handle to previous instance
    LPSTR lpCmdLine,          // command line
    int nCmdShow              // show state
)
{
    /*设计一个窗口类*/
    WNDCLASS wndcls;
    wndcls.cbClsExtra = 0;
    wndcls.cbWndExtra = 0;
    wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
    wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);
    wndcls.hInstance = hInstance;
    wndcls.lpfnWndProc = WinSunProc;
    wndcls.lpszClassName="sunxin2021";
    wndcls.lpszMenuName = NULL;
    wndcls.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&wndcls);

    /*创建窗口*/
    HWND hwnd;
    hwnd = CreateWindow("sunxin2021", "sx's home.", WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL);

    /*显示及刷新窗口*/
    ShowWindow(hwnd, SW_SHOWNORMAL);
    UpdateWindow(hwnd);

    /*消息循环*/
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//将WM_KEYDOWN和WM_KEYUP转化为WM_CHAR,不修改原消息
        DispatchMessage(&msg);//将消息发送至操作系统,后者用窗口过程函数对消息响应
    }
    return msg.wParam;

}

/*******************窗口过程函数*************************/
LRESULT CALLBACK WinSunProc(
    HWND hwnd,      // handle to window
    UINT uMsg,      // message identifier
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
)
{
    switch (uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar, "char code is %d", wParam);
        MessageBox(hwnd, szChar, "char", 0);
        break;

    case WM_LBUTTONDOWN:
        MessageBox(hwnd, "mouse clicked", "message", 0);
        HDC hdc;                    //要在窗口中输出文字或显示图形,要用到设备描述表(DC)。DC是一个包含设备信息的结构体,所有的图形操作都是利用DC来完成。
                                    //定义类型为HDC的变量hdc
        hdc = GetDC(hwnd);          //GetDC返回与特定窗口相关联的DC句柄
        TextOut(hdc, 0, 50, "sx's home",strlen("sx's home"));
        ReleaseDC(hwnd, hdc);          //在使用完GetDC后一定要注意释放
        break;

    case WM_PAINT://窗口重绘
        HDC hDC;
        PAINTSTRUCT ps;
        hDC = BeginPaint(hwnd, &ps);
        TextOut(hDC, 0, 0, "http://www.sunxin.org", strlen("http://www.sunxin.org"));
        EndPaint(hwnd, &ps);//WM_PAINT、BeginPaint、EndPaint一起用,而不能用GetDC
        break;

    case WM_CLOSE://关闭消息
        if (IDYES == MessageBox(hwnd, "是否真的结束了?", "message", MB_YESNO))
        {
            DestroyWindow(hwnd);//销毁窗口
        }
        break;
            
//此时窗口销毁,但程序还在后台运行
            
    case WM_DESTROY:
        PostQuitMessage(0);//在响应消息后,投递一个退出的消息使用程序安全退出
        break;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);//调用缺省的消息处理过程函数,对没有处理的其他消息以默认处理

    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/524773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

swing列表框_强制存储的DefaultListModel和DefaultComboBoxModel

package com.aynu.layout;import javax.swing.*; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;public class DefaultListModelTest {JFrame jf new JFrame("测试DefaultListModel");JTextField bookNa…

JVM学习(二)

1. JVM 运行时内存 Java 堆从 GC 的角度还可以细分为: 新生代 ( Eden 区 、 From Survivor 区 和 To Survivor 区 )和 老年 代。 1.1. 新生代 是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象&#xff0c;所以新生代会频繁触发 MinorGC 进行垃圾回收。新…

《如何评价北化面向对象江某英之我是传奇》

点进来的都是家人了&#xff0c;来&#xff0c;今天带你们一起速通江某英的面向对象。 首先&#xff0c;我们先看一下江某英的教学安排&#xff0c;所谓知己知彼&#xff0c;百战不殆。 一共是九个章节&#xff0c;但是最后一个总复习没讲&#xff0c;这不是为难我们吗&#x…

【移动端网页布局】Flex 弹性布局案例 ② ( 顶部固定定位搜索栏 | 固定定位盒子居中对齐 | 二倍精灵图设置 | CSS3 中的垂直居中对齐 )

文章目录 一、顶部固定定位搜索栏1、固定定位盒子居中对齐2、设置最大宽度和最小宽度3、使用 Flex 弹性布局管理宽度4、二倍精灵图设置5、CSS3 中的垂直居中对齐 - 行高 内容高度 ( 总高度 - 边框高度 - 内边距高度 ) 二、代码示例1、HTML 标签结构2、CSS 样式3、展示效果 一、…

Pytroch nn.Unfold() 与 nn.Fold()图码详解

文章目录 Unfold()与Fold()的用途nn.Unfold()Unfold()与Fold() 变化模式图解 nn.Fold()单通道 滑动窗口无重叠模拟图片数据&#xff08;b,3,9,9&#xff09;&#xff0c;通道数 C 为3&#xff0c;滑动窗口无重叠。单通道 滑动窗口有重叠。 卷积等价于&#xff1a;Unfold Matri…

国民技术N32G430开发笔记(20)- FreeRTOS的移植

FreeRTOS的移植 1、官网下载FreeRTOSv202212.01&#xff0c;搜索官网下载即可。 2、新建一个FreeRTOSDemo的工程&#xff0c;可以把之前的工程中的Bootloader工程复制一份。 3、打开下载的freertos代码将相应代码移植到我们的工程中。 protable文件夹&#xff0c;因为是gcc环…

ChatGPT国内镜像网站集合

ChatGPT是一个基于人工智能的聊天机器人&#xff0c;它可以与用户进行自然语言交互。ChatGPT使用了最新的自然语言处理技术&#xff0c;包括深度学习和神经网络&#xff0c;以便更好地理解用户的意图和回答用户的问题。 ChatGPT可以回答各种问题&#xff0c;包括但不限于常见问…

RabbitMQ如何避免丢失消息

目录标题 消息丢失1. 生产者生产消息到RabbitMQ Server 消息丢失场景1. 网络问题2. 代码层面&#xff0c;配置层面&#xff0c;考虑不全导致消息丢失解决方案&#xff1a;开启confirm模式 2. 队列本身可能丢失消息1. 消息未完全持久化&#xff0c;当机器重启后&#xff0c;消息…

shell脚本之“sed“命令

文章目录 1.sed编辑器概述2.sed命令常用选项3.sed命令常用操作4.sed命令演示操作部分5.总结 1.sed编辑器概述 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处理数据流中的数据&#xff0c;这些…

C嘎嘎~~[类 下篇 之 日期类的实现]

类 下篇 之 日期类的实现 6.const成员6.1 const成员的引入6.2const成员的概念 7.日期类的实现 6.const成员 6.1 const成员的引入 class Date { public:// 构造函数Date(int year 2023, int month 5, int day 5){_year year;_month month;_day day;}void Print(){cout &…

【STL】vector的使用

目录 前言 默认成员函数 构造函数 拷贝构造 赋值重载 迭代器 正向迭代器 反向迭代器 容量管理 查看容量和大小 扩容 判空 访问数据 下标访问 边界访问 数据修改 尾插尾删 指定位置插入删除 迭代器失效 清空 ​编辑 交换 查找数据 vector可以代替strin…

VOACAP 软件的简单介绍

VOACAP 软件可以预测短波通信中的最高可用频率、最佳传输频率、角度、延迟、反射点高度、信噪比、收发增益等参数&#xff0c;它可以直接输出文本文件&#xff0c;或者以图表输出&#xff0c;同时&#xff0c;它也可以绘制某一参数随时间、距离的变化图表。 该软件的下载安装可…

C语言从入门到精通第18天(指针和函数的联用)

指针和函数的联用 一级指针作为函数的形参二级指针 一级指针作为函数的形参 当函数的形参为数组时&#xff0c;我们定义函数如下&#xff1a; 语法: 数据类型 函数名(数据类型 数组名) 例如 : void func(int a[],int a){ 语句; } 但是在实际使用中我们通常用指针的形式进行…

GEE:如何进行对MOD09GA数据集进行水体/云掩膜并计算NDVI将其导出至云盘?

目录 01 为什么用GEE而不是传统的下载ENVIArcGIS&#xff1f; 02 操作详解 01 为什么用GEE而不是传统的下载ENVIArcGIS&#xff1f; 由于地理空间数据云中缺少2015年10月份的NDVI月合成影像&#xff0c;于是查看了地理空间数据云的NDVI数据集处理的一些介绍如下(地理空间数据…

【Linux内核】信号量semaphore机制

信号量实现方法 信号量机制是一种用于控制并发访问的同步机制&#xff0c;常用于多进程或多线程之间的协调。在Linux内核中&#xff0c;信号量机制是通过struct semaphore结构体来实现的。 每个semaphore结构体包含一个计数器和一个等待队列&#xff0c;它们用于跟踪当前可用…

Linux 并发与竞争

一、并发与竞争 1、并发 Linux 系统是个多任务操作系统&#xff0c;会存在多个任务同时访问同一片内存区域&#xff0c;这些任务可 能会相互覆盖这段内存中的数据&#xff0c;造成内存数据混乱。 多线程并发访问&#xff0c; Linux 是多任务(线程)的系统&#xff0c;所以多线…

命令firewalld和firewall-cmd用法

firewalld命令跟firewall-cmd 1.启动firewalld服务 systemctl start firewalld.service2.关闭firewalld服务 systemctl stop firewalld.service3.重启firewalld服务 systemctl restart firewalld.service4.查看firewalld状态 systemctl status firewalld.service5.开机自启…

接口测试怎么做?全网最详细从接口测试到接口自动化详解,看这篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 抛出一个问题&…

孙鑫VC++第三章 2.基于MFC的程序框架剖析

目录 1. MFC向导生成类 2. 框架流程 2.1 WinMain 2.2 全局对象&#xff1a;theApp 2.3 AfxWinMain函数 1.AfxWinMain&#xff1a; 2.AfxGetThread函数&#xff08;thrdcore.cpp&#xff09;&#xff1a; 3.AfxGetApp是一个全局函数&#xff0c;定义于&#xff08;afxwin1…

原型/原型链/构造函数/类

认识构造函数 为什么有构造函数 因为一般的创建对象的方式一次只能创建一个对象, 利用工厂模式创建的对象&#xff0c;对象的类型都是Object类型 什么是构造函数 构造函数也称之为构造器&#xff08;constructor&#xff09;&#xff0c;通常是我们在创建对象时会调用的函数…