2.1 初识Windows程序

Windows程序设计是一种面向对象的编程。Windows操作系统以数据结构的形式定义了大量预定义的对象作为操作系统的数据类型。Windows动态链接库提供了各种各样的API接口函数供Windows应用程序调用。一个Windows应用程序是运行在Windows操作系统之上的。这些API接口函数的调用所实现的功能仅仅是冰山的一角,更多的功能实现都是Windows操作系统内核自动实现的。我们对此一定要有清醒的认识。

本节必须掌握的知识点:

        Windows数据类型

        匈牙利命名法

        窗口

        消息

2.1.1 Winodws数据类型

       Windows操作系统有自己的数据类型,且往往以对象名的方式定义数据类型的名称。

Windows 支持的数据类型用于定义函数返回值、函数和消息参数以及结构成员。 它们定义这些元素的大小和含义。 有关Windows数据类型的信息可以查阅MSDN,搜索“Windows数据类型”。由于Windows操作系统可以运行各种编程语言的应用程序,因此,也支持汇编语言、C\C++语言的数据类型。当我们调用Windows API函数时自然使用的是Windows定义的数据类型。

下表包含以下数据类型:字符、整型、布尔、指针和句柄。 字符、整数和布尔类型是大多数 C 编译器通用的。 大多数指针类型名称以P或LP前缀开头。句柄引用已加载到内存中的资源。除此之外,我们还会陆续接触大量Windows预定义的对象结构类型。

Windows数据类型参见《附录A》。

提示

       请读者不要死记硬背任何内容,否则就失去了学习的兴趣,Windows程序设计将变得枯燥无味。只要可以查阅到的知识都等同于已经记住了。学习的过程关键在于理解、动手实验和勤于思考。为了加深印象,可以认真做好笔记,方便查阅,提高学习效率,仅此而已。

2.1.2 匈牙利命名法

在程序中需要给一些常量值、自定义数据类型、变量、函数命名,随着代码量的增大,对于初学者而言这似乎是一件比较麻烦的事情。其实我们只需要遵循既定的一些命名规范就可以了。

四种基本的编程命名规范

匈牙利命名法、驼峰式命名法、帕斯卡命名法和下划线命名法。

●匈牙利命名法

匈牙利命名法是由微软的一个匈牙利人发明的,Windows操作系统遵循的就是匈牙利命名法。该命名规范,要求前缀字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,单词第一个字母大写。匈牙利标记法可以避免因数据类型不匹配造成的错误。

1.变量类型:

Ex

int iMyAge;            #  "i": int

char cMyName[10];    #  "c": char

float fManHeight;       #  "f": float

其他前缀类型还有:

a            数组(Array)

b        布尔值(Boolean)

by       字节(Byte)

c        有符号字符(Char)

cb       无符号字符(Char Byte)

cr        颜色参考值(Color Ref)

cx,cy      坐标差(长度 Short Int)

dw     双字(Double Word)

fn       函数(Function)

h        Handle(句柄)

i         整形(Int)

l         长整型(Long Int)

lp        长指针(Long Pointer)

m_     类成员(Class Member)

n        短整型(Short Int)

np     近程指针(Near Pointer)

p        指针(Pointer)

s        字符串(String)

sz       以 Null 做结尾的字符串型(String with Zero End)

w      字(Word)

举例

szCmdLine的前缀sz表示“以零结尾的字符串”。

hInstance和hPrevInstance中的前缀h表示“句柄”;

iCmdShow中的前缀i表示“整型”。

2.结构类型

当命名结构变量时,可以使用结构名(或结构名称的缩写)的小写形式作为变量名称的前缀或整个变量名。

举例

HELLOWIN.C的WinMain函数中,msg变量就是一个MSG类型的结构,wnclass是一个WNDCLASS类型的结构。

在WndProc函数中,ps是一个PAINTSTRUCT结构,而rect是一个RECT结构。

3.常量类型

Windows中的常量使用大写标识符。这些标识符都在windows头文件中定义的。这些标识符有很多都是以两个或三个字母作为前缀,且其后缀紧跟一个下划线。

举例

CS_HREARAW       DT_VCENTER        SND_FILENAME           CS_VREDRAW      

IDC_ARROW         WM_CREATE         CW_USEDEFAULT        IDI_APPLICATION  WM_DESTROY      DT_CENTER          MB_ICONERROR          WM_PAINT           DT_SINGLELINE     SND_ASYNC         WS_OVERLAPPEDWINDOW

前缀

常量

含义

CS

类风格选项

CLASS

CW

创建窗口选项

CreateWindow

DT

文本绘制选项

DrawText

IDI

图标的ID

Icon ID

IDC

光标的ID

Cursor ID

MB

消息框选项

MessageBox

SND

声音选项

Sound

WM

窗口消息

Windows Message

WS

窗口风格

Windows style

●驼峰式命名法

驼峰式命名法,又叫小驼峰式命名法。该命名规范,要求第一个单词首字母小写,后面其他单词首字母大写,简单粗暴易学易用。

举例

int myAge;

char myName[10];

float manHeight;

●帕斯卡命名法

帕斯卡命名法,又叫大驼峰式命名法。与小驼峰式命名法的最大区别在于,每个单词的第一个字母都要大写。

举例

int MyAge;

char MyName[10];

float ManHeight;

●下划线命名法

下划线命名法要求单词与单词之间通过下划线连接。尤其在宏定义和常量中使用比较多,通过下划线来分割全部都是大写的单词。

举例

int my_age;

char my_name[10];

float man_height;

随着技术的发展,命名规范也在不断的细化。不同的语言不同 IDE 推崇的规范也有所不同,无法评判哪一种最好,可以根据个人习惯或者指定的规范选择合适的命名规则。

例如,谷歌 C++ 编程规范,从项目的命名到文件的命名,再到类和变量以及宏定义的命名都做到了细致入微,充分的结合了下划线命名法与驼峰式命名法。

当然,命名规范并不代表着编程规范,仅仅是编程规范的一部分而已,除去命名规范,还有很多编程上的细节是必须关注的,例如,等号两边留空格还是等号对齐?空行什么时候什么地方留更加符合代码结构?空格什么时候什么地方留更加美观?花括号是否对齐?诸如此类,还有很多,无法一下子全部掌握并应用,但是在编程经验增加的过程中,一定也要不断的留意,自己所在的公司部门使用的是什么样的规范,并不提倡大家练就自己的规范,一定要去融入工作环境的需求。每次去新的工作环境,第一个要看的文档一定是编程规范。

2.1.3 窗口

Windows窗口是用来和用户进行交互信息的,可以在窗口中输入信息,也可以在窗口中输出信息。这些信息包括文本、图形、动画等等。对比控制台黑窗口,Windows窗口可以输入和输出的信息要丰富的多。

自定义窗口

窗口就是对象,作为程序员来说,就是一块内存。这块内存中通常包含一个标题栏、一个菜单栏、一个工具栏和一个滚动条等其他小的对象(更小的一块内存)。通常我们会使用窗口对象的句柄对窗口进行操作。

如果我们要创建一个窗口,需要告诉Windows系统一些明确的信息:

typedef struct tagWNDCLASSA {

  UINT             style;                     //创建一个什么样风格的窗口

  WNDPROC     lpfnWndProc;        //由谁来负责处理窗口的消息—窗口过程

  int                cbClsExtra;           //要根据窗口类结构分配的额外字节数

  int                cbWndExtra;        //在窗口实例之后分配的额外字节数

  HINSTANCE      hInstance;            //窗口所属的进程

  HICON          hIcon;                  //窗口的图标

  HCURSOR       hCursor;               //窗口的鼠标

  HBRUSH         hbrBackground;    //窗口的背景颜色

  LPCSTR          lpszMenuName;    //窗口所包含的菜单

  LPCSTR          lpszClassName;     //窗口类名(等同于进程名)

} WNDCLASSA, *PWNDCLASSA, *NPWNDCLASSA, *LPWNDCLASSA;

显然,将创建窗口的所有信息组合到一起就是一个结构体。细心的读者可能会发现,创建窗口的信息还应该包含窗口的尺寸。这是一定需要的,我们将在下一节中使用示例代码来说明。

预定义对话框窗口

Windows还预定义另一种窗口,可以不带标题栏,而是包含各种各样的控件,例如按钮、列表框、滚动条和文本框等。

对话框窗口可以分为:

●模态对话框:当程序显示一个模态对话框时,用户不能在对话框和该程序的其他窗口之间进行切换。用户必须先明确地终止该对话框。这通常由单击OK或Cancel按钮来实现。但是当对话框正在显示时,用户可以切换到其他的程序。有些对话框(所谓“系统模态”)则连这种切换都不允许。在Windows 中,用户必须先结束系统模态对话框才可以进行其他操作。典型的默认对话框就是MessageBox框了。

●非模态对话框:非模态对话框允许用户在对话框和窗口之间,以及在对话框和其他程序之间进行切换。非模态对话框因此更接近于程序自定义的正常弹出窗口。如果在一段时间内,一直要显示某个对话框,用户更倾向于使用非模态对话框,因为它更方便。典型的非模态对话框如查找和替换对话框。

●公用对话框:为了方便用户快速熟悉和使用Windows应用程序,从Windows 3.1开始,提供了统一标准的“公用对话框库”(common dialogue box library)。这个库包括了一些函数,可以用来激活打开和存储文件、查找和替换、选择颜色、选择字体(所有这些将在本书第十一章中演示)以及打印(将在第十三章中演示)的对话框。

预定义子窗口控件

子窗口控件也是一种窗口,也是Windows预定义的窗口类型。虽然我们也可以自定义子窗口控件,但是直接使用Windows提供的标准子窗口控件更为方便快捷。Windows预定义了子窗口控件的窗口类和窗口过程,并且提供多种不同风格的子窗口样试供我们选择。常用的子窗口控件包括按钮类的BUTTON控件、静态文本控件、滚动条控件、文本编辑控件和列表框控件。我们将在第八章详细讲解子窗口控件。

2.1.4 消息

       Windows操作系统是一种消息驱动的系统,这句话应该被每一位从事Windows程序设计的开发人员所熟知。那么什么是消息呢?也许有很多已经从事多年Windows程序开发的程序员都无法说清楚。这是因为他们并不清楚消息传递的实现过程。

消息的本质

       消息其实非常简单,就是函数调用时传递的参数,仅此而已。只不过我们并不能从代码中真实的感受到消息传递的整个过程,所以会觉得不可琢磨。Windows操作系统中有很多很多消息,这些消息可以是键盘消息、鼠标消息、滚动条消息、字符消息、绘图消息、控件消息、菜单消息或者是系统消息等等。键盘消息和鼠标消息肯定是由用户操作键盘和鼠标产生的,这是人机交互的需要。其他消息又是如何产生的呢?如果我们把消息看作是参数,那么这些消息肯定是在调用函数调用传递参数时产生的,消息本身就是参数。例如绘图时,我们将绘图消息WM_PAINT作为实参传递给GDI绘图函数。不论什么样的消息都是由操作系统捕捉并分发的。API函数的调用和执行也是由Windows操作系统实现的,这些都是潜藏在水面以下的冰山。正是因为我们看不见,所以才会感到困惑。

       既然消息就是一个参数,我们来了解一下消息本身:

typedef struct tagMSG {

  HWND   hwnd;       //接收消息的窗口的句柄

  UINT   message;     //指定消息类型-消息ID,例如 WM_PAINT、WM_CLOSE等。

  WPARAM wParam;   //针对特定消息的附加信息

  LPARAM lParam;      //详细的附加信息,通常与wParam一起配合使用

  DWORD  time;        //消息发布的时间

  POINT  pt;               //鼠标在发布消息的时候在屏幕上的位置(鼠标消息特性)

  DWORD  lPrivate;    //仅在某些消息类型中使用,其他情况下是保留项

} MSG, *PMSG, *NPMSG, *LPMSG;

       我们用一个结构体来描述消息,显然消息是一个对象(Windows系统处处是对象)。消息结构体中包含7个成员,我们只需要关系前面四个成员,后面三个成员仅提供给操作系统使用。

       hwnd:接收消息的窗口的句柄,所有的消息都是发送给指定窗口的。

message:指定消息类型-消息ID,Windows系统使用一个32位无符号整数标识消息。

wParam 和lParam:针对特定消息的附加信息。仅有一个消息ID远远不够的,还需要借助于32位的wParam 和32位的lParam传递具体的信息。

我们在Windows程序中通常会将上述四个成员作为参数传递。

举例

例如发送一个消息:

LRESULT SendMessage(

  [in] HWND   hWnd,       //接收消息的窗口句柄

  [in] UINT   Msg,             //消息ID

  [in] WPARAM wParam,    //附加参数,其他的消息特定信息

  [in] LPARAM lParam        //附加参数,其他的消息特定信息

);

       很显然,这里的消息就是参数。在Windows系统内部产生和传递消息也是如此。

       Windows系统中的消息虽然非常多,但是绝大多数消息都是由Windows系统按照默认方式处理的,不需要我们劳心费力,目的当然是不想为难我们这些开发者了。

       ■窗口过程

在Winodws程序中,我们需要写一个函数来处理各种消息,这个函数称为窗口过程。它是一个回调函数。正常情况下,在Windows程序中是由我们来调用操作系统的API函数,回调的意思是由操作系统反过来调用我们写的窗口过程来处理消息。窗口过程只需要处理我们关心的一小部分消息,绝大多数消息都是交给默认的Windows系统的窗口过程来处理。本书的学习过程也就是学习各种各样消息处理的过程。

队列消息

       Windows操作系统的消息可以分为队列消息和非队列消息。Windows操作系统中有一个总消息队列,所有进程的队列消息都会被送入总消息队列中。然后再根据消息所属的窗口,将消息分发到各个窗口队列。还记得消息结构的第一个成员就是接收消息的窗口。以此判断该消息属于哪个窗口。

什么样的消息属于队列消息呢?鼠标消息、键盘消息肯定是属于队列消息,一定会被送入消息队列。这是由于用户通过鼠标、键盘与窗口进行交互产生的消息,而用户的操作是有先后顺序的,因此需要使用队列进行同步操作。因此可以认为,凡是与窗口进行交互或需要保持同步操作的消息都是队列消息,一定会被送上消息队列。队列消息都是调用PostMessage函数将消息送入指定窗口的消息队列。

BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

       消息队列存在于线程中,理论上每个线程都可以创建一个消息队列。

假如一个Windows进程只有一个主线程,那么非常简单,所有的窗口消息都是送入主线程的消息队列。

假如一个Windows进程同时拥有多个线程,其中只有一个主线程负责处理窗口消息,其它线程执行其他任务。意思是在多线程的Windows程序中,同样只有一个消息队列,所有消息都交给主线程处理,不存在多个线程间的冲突问题。因此,虽然窗口是不包含消息队列的,但是我们将线程消息队列称为窗口消息队列也没什么错。

在Windows程序设计中,需要遵循“十分之一秒原则”。“十分之一秒原则”是指用户在做出操作后,至少应在0.1秒之内得到某种形式的反馈,这样才能让用户感觉到系统在对他的操作给予响应。如果一个任务执行时间超过0.1秒,我们为了良好的用户体验,就需要考虑新建一个线程来单独处理这个任务。我们将在本书的第二十章详细讲解进程与线程。

windows应用程序中一般都包含一小段称为“消息循环”的代码,该段代码用于从消息队列中检索消息,并将其分发给相应的窗口过程。其他非队列消息则不经过消息队列直接发送给窗口过程。

非队列消息

       除了队列消息之外,剩下的消息就都属于非队列消息了。不需要被送入消息队列的消息可以通过SendMessage函数将消息直接发送给负责处理消息的窗口过程。

在Windows程序设计中,SendMessage函数被用于将一个消息发送给指定窗口或线程,它会等待消息处理完毕才会返回,也就是说它是一个同步或者说阻塞的函数。这是一个非常重要的用来在窗口间或线程间通信的函数。SendMessage函数可以在同一个线程内、同一个进程内的线程间或者不同进程的线程间通过消息进行通信。

下面是SendMessage函数的定义:

LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

       SendMessage函数应该是使用最频繁的一个函数了,在后面的章节中我们将深有体会。

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

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

相关文章

【Vue】路由的基本使用

文章目录 一、固定5个固定的步骤二、代码示例三、两个核心步骤四、完整代码 vue-router插件作用 修改地址栏路径时,切换显示匹配的组件 说明 Vue 官方的一个路由插件,是一个第三方包 官网 https://v3.router.vuejs.org/zh/ VueRouter的使用&#xff0…

TCP/IP协议介绍——三次握手四次挥手

TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议…

CSS学习|css三种导入方式、基本选择器、层次选择器、结构伪类选择器、属性选择器、字体样式、文本样式

第一个css程序 css程序都是在style标签中书写 打开该网页,可以看到h1标签中的我是标题被渲染成了红色 可以在同级目录下创建一个css目录,专门存放css文件,可以和html分开编写 然后在html页面中,利用link标签以及css文件地址&…

大模型基架:Transformer如何做优化?

大模型的基础模式是transformer,所以很多芯片都实现先专门的transformer引擎来加速模型训练或者推理。本文将拆解Transformer的算子组成,展开具体的数据流分析,结合不同的芯片架构实现,分析如何做性能优化。 Transformer结构 tr…

go的反射和断言

在go中对于一个变量,主要包含两个信息变量类型(type)和变量值(value) 可以通过reflect包在运行的时候动态获取变量信息,并能够进行操作 对于Type可以通过reflect.TypeOf()获取到变量的类型信息 reflect.Ty…

13_前端工程化_ES6

1.前端工程化概念 前端工程化是使用软件工程的方法来单独解决前端的开发流程中模块化、组件化、规范化、自动化的问题,其主要目的为了提高效率和降低成本。 前后端分离(前端代码工程化独立出来形成一个单独的app) 1.开发分离 2.部署分离 3.服务器分离…

信号(上)

本节目标: 1. 掌握Linux信号的基本概念 2. 掌握信号产生的一般方式 3. 理解信号递达和阻塞的概念,原理。 4. 掌握信号捕捉的一般方式。 5. 重新了解可重入函数的概念。 6. 了解竞态条件的情景和处理方式 7. 了解SIGCHLD信号, 重新编写信号处理…

ChatGPT基本原理详细解说

ChatGPT基本原理详细解说 引言 在人工智能领域,自然语言处理(NLP)一直是研究的热点之一。随着技术的发展,我们见证了从简单的聊天机器人到复杂的语言模型的演变。其中,ChatGPT作为一项突破性技术,以其强大…

2004NOIP普及组真题 2. 花生采摘

线上OJ: 【04NOIP普及组】花生采摘 核心思想: 1、本题为贪心即可。 2、因为本题严格限制了顺序,所以先把每个节点的花生数量按降序排序。然后逐一判断下一个花生是否需要去采摘即可 3、每一次采摘完,记录耗时 t 以及采集的花…

基于web的垃圾分类回收系统的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,用户管理,公告管理,运输管理,基础数据管理 用户账户功能包括:系统首页,个人中心,运输管理,公告…

pyqt QlineEdit内部增加按钮方法

pyqt QlineEdit内部增加按钮方法 def addButton(self,lineEdit):btn QtWidgets.QPushButton("")icon1 QtGui.QIcon()icon1.addPixmap(QtGui.QPixmap(":/image/images/th.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)btn.setIcon(icon1)btn.setStyleShe…

全光谱led灯的危害有哪些?曝光低质量全光谱led灯产生的四大风险

眼睛是人类获取信息最重要的感官器官之一,而近视则会导致视力模糊,进而影响学习效果和生活品质。因此,如何保护眼睛,尤其是在学习和使用电子设备时,成为了一个迫切需要解决的问题。然而在护眼领域上,护眼台…

SCAU 数据结构 实验六 排序算法

![[Pasted image 20240 8638 直接插入排序 Description 用函数实现直接插入排序,并输出每趟排序的结果. 输入格式 第一行:键盘输入待排序关键的个数n 第二行:输入n个待排序关键字,用空格分隔数据 输出格式 每行输出一趟排序…

十三、resultMap解析

分为两部分:解析和使用 解析 1.解析XML的时候单独解析所有的resultMap标签,封装成ResultMap对象存入configuration中 2.解析XML中的SQL语句,封装MappedStatement对象,这里会根据SQL的返回类型是resultMap还是resultType做处理。如…

C语言 | Leetcode C语言题解之第133题克隆图

题目: 题解: struct Node** visited; int* state; //数组存放结点状态 0:结点未创建 1:仅创建结点 2:结点已创建并已填入所有内容void bfs(struct Node* s) {if (visited[s->val] && state[s->val] 2…

Python Lambda函数的应用实例教程

在Python编程中,lambda函数是一种简洁且强大的工具,用于创建小型匿名函数。它们在需要快速定义简单函数时特别有用。本文将详细介绍lambda函数的语法及其多种应用实例,帮助读者更好地理解和使用lambda函数。 一、lambda函数的基本概念 1.1 什…

c++(内存分配,构造,析构)

#include <iostream>using namespace std; class Per { private:string name;int age;double *height;double *weigh; public://无参构造Per(){cout << "Per::无参构造" << endl;}//有参构造Per(string name,int age,double height,double weigh):…

【TB作品】 51单片机8x8点阵显示滚动汉字仿真

功能 题目5基于51单片机LED8x8点阵显示 流水灯 直接滚动显示HELLO 直接滚动显示老师好 代码 void main( void ) {/** 移位后&#xff0c;右边的是第一个595&#xff0c;接收0X02&#xff0c;显示出0X02* 移位后&#xff0c;左边的是第2个595&#xff0c;接收0Xfe&#xff0c…

创建常规DLL的动态链接库

本文仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;如本文涉及侵权请及时联系本人将于及时删除 【例9.3】创建一个MFC 常规DLL的动态链接库Areadll&#xff0c;在该动态链接库中添加一个导出类CArea&#xff0c;通过该类获取正方形和圆的面积。 (1) 使用“MFC动态链接…

Allegro器件角度倾斜如何回正?

Allegro器件角度倾斜,坐标含有小数点调整为45度整数倍的方法 Allegro器件角度倾斜回正的方法。 在用Allero进行PCB设计过程中,有时候由于误操作;或者刚开始器件需要非45度整数倍的角度,后又需要调整为整数倍的角度。器件角度倾斜含有小数点调整为45度整数倍的方法。 1、如…