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.mfbz.cn/a/687091.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大学汉语言文学古代汉语/中国古代文学试题及答案,分享几个实用搜题和学习工具 #其他#微信#知识分享

大学生搜题软件是一种方便快捷的工具,可以帮助大学生们在解答问题和完成作业时节省时间和精力。 1.彩虹搜题 这是个老公众号了 界面简洁友好,操作简单易上手。无论你是谁,都能轻松搜题。 下方附上一些测试的试题及答案 1、《中华人民共和…

MySQL8 全文索引

文章目录 创建索引使用索引总结 创建索引 之前未尝试过使用MySQL8的全文索引,今天试一试看看什么效果,否则跟不上时代了都。   创建索引非常简单,写句SQL就行。 create table goods(id integer primary key auto_increment,name varchar(2…

铁塔、烟囱建筑倾斜监测的倾角仪的分类以及工作原理

前言 倾角传感器是一种用于测量物体相对平面倾斜角度的仪器。倾角传感器又称作倾角仪、倾斜仪、测斜仪、水平仪、倾角计,经常用于物体的水平角度变化的精确测量,用它可测量被测平面相对于水平位置的倾斜度、两部件相互平行度和垂直度;已成为桥…

蓝卓热电行业解决方案

能源是人类社会发展过程中的永恒话题,热电联产作为电能和热能同时生产的能源利用形式,相较传统的火力发电具有能源利用效率高等优点,可以高效解决能源及环境问题。目前,世界各国都将热电联产作为更高效、更环保的能源供给体系而有效措施大力推广。 如何降本增效、减…

组件的注册和引用

在Vue中,开发者可以将页面中独立的、可重用的部分封装成组件,对组件的结构,样式和行为进行设置。组件是 Vue 的基本结构单元,组件之间可以相互引用。 一.注册组件 当在Vue项目中定义了一个新的组件后,要想在其他组件中…

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP+Uniapp)

🔍防伪溯源一体化管理系统:守护品质,追溯无忧 一款基于FastAdminThinkPHP和Uniapp进行开发的多平台(微信小程序、H5网页)溯源、防伪、管理一体化独立系统,拥有强大的防伪码和溯源码双码生成功能&#xff0…

为何瑞士银行成了富人的“保险箱”?

​瑞士银行,这个名字大家耳熟能详,为啥呢?因为它被誉为“全球最安全银行”。那么,这“最安全”的名头是怎么来的呢?它的金库又藏在哪儿呢? 话说在1930年代,德国纳粹迫害犹太人,导致…

政安晨【零基础玩转各类开源AI项目】解析开源:IDM-VTON:改进真实虚拟试穿的扩散模型

目录 概述 要求 数据准备 服饰代码 推理 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: 零基础玩转各类开源AI项目 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! 项目地址&…

STM32-电灯,仿真

目录 前言: 一. 配置vscode 二. 新创建软件工程 三. 仿真 1.新建工程想到,选择名称和路径 2.从选中的模板创建原理图 3.不创建PCB布版设计 4.选择没有固件项目 5.完成 四.源码 五. 运行效果 六. 总结 前言: 这篇主要是配置vscode和创建仿真,和点灯的完整代码,欢迎大…

nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入 Node.js 同时支持 CommonJS 和 ES 模块系统(自 Node.js v12 以来) // 两种模块导入方式 import * as fs from fs;// Es6:这种方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…

肥胖与代谢综合征,膳食纤维干预的相关进展

谷禾健康 肥胖和代谢综合征在全球范围内日益流行,是21世纪人类健康面临的重大威胁之一。据世界卫生组织(WHO)全球数据估计,目前全球约13%(即近65亿)成年人口受肥胖症影响。 肥胖和代谢综合征对健康的危害包括增加患心血管疾病、糖尿病和高血压的风险&…

短视频矩阵系统----可视化剪辑独立开发(采用php)

短视频矩阵系统源头技术开发: 打磨短视频矩阵系统的开发规则核心框架可以按照以下几个步骤进行: 明确系统需求:首先明确系统的功能需求,包括短视频的上传、编辑、发布、播放等环节。确定系统的目标用户和主要的使用场景&#xff…

智能数据分析(1)Lecture 6-8b

Lecture 6: Generative Models 生成模型 vs 判别模型 判别模型(Discriminative Models) 判别模型的主要任务是直接学习输入 x x x 和类别 y y y 之间的关系。它们不关心数据的生成过程,而是直接估计类别的边界。 定义:判别模…

Win10系统无法安装msi文件问题

winR输入services.msc打开服务 找到Windows Installer并启动 输入msiexec /package “msi文件路径”

perccli查看磁盘和Raid卡

1、安装 source /etc/profile chmod 755 /usr/sbin/perccli2、磁盘 perccli /c0 show all3、raid卡 cc perccli /c0 show cc 4、raid卡 pr perccli /c0 show patrolread

安卓手机忘记锁屏密码怎么办?2个方法拯救你的解锁困境!

为了保护手机信息不被他人轻易获取,我们通常会设置锁屏密码。然而,记忆力有时也会捉弄人,即使是最常用的密码,也有可能因为一时的疏忽或遗忘而导致我们无法解锁自己的手机。安卓手机忘记锁屏密码怎么办?不必慌张&#…

镜头效果技术在AI绘画中的革新作用

随着人工智能技术的飞速发展,AI绘画已经成为艺术与科技交汇的前沿领域。在这一领域中,镜头效果技术的应用不仅为艺术家和设计师们提供了全新的创作工具,更在艺术创作中扮演了革命性的角色。本文将深入探讨镜头效果技术在AI绘画中的应用&#…

物联网开发tcp协议之——netty拆包问题

1.前言 tcp协议是物联网开发中比较常见的一种通信协议,而netty则是一tcp通信协议中一个比较优秀的框架。tcp协议是一种长连接的协议,是流式传输的,开发过程中最长遇见的问题就是拆包粘包问题。我目前对接过的物联网系列有智能家居设备&#…

一脉阳光上市圆梦:销售成本高昂,两大创始人的行贿往事与屡屡被罚

《港湾商业观察》施子夫 2024年6月7日,江西一脉阳光集团股份有限公司(以下简称,一脉阳光)将正式在港交所主板挂牌上市(以下简称,一脉阳光;股票代码02522.HK),公司预计发…

【网络安全的神秘世界】Kali安装中文输入法

🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 今天就手把手教你如何在kali中安装和配置输入法 首先,打开终端,输入下面这行代码: # sudo apt install ibus ibus-pi…