2.1 初识Windows程序

news2024/11/16 11:51:57

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.coloradmin.cn/o/1792947.html

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

相关文章

MKS AX7680 SERIES 电源使用说明手侧

MKS AX7680 SERIES 电源使用说明手侧

【Python报错】AttributeError: ‘NoneType‘ object has no attribute ‘xxx‘

成功解决“AttributeError: ‘NoneType’ object has no attribute ‘xxx’”错误的全面指南 一、引言 在Python编程中,AttributeError是一种常见的异常类型,它通常表示尝试访问对象没有的属性或方法。而当我们看到错误消息“AttributeError: ‘NoneTyp…

Face Forgery Detection by 3D Decomposition

文章目录 Face Forgery Detection by 3D Decomposition研究背景研究目标创新点方法提出问题研究过程技术贡献实验结果未来工作Face Forgery Detection by 3D Decomposition 会议:CVPR2021 作者: 研究背景 面部伪造引发关注传统面部伪造检测主要关注原始RGB图像

linux进程家族-管理子进程,确保进程族稳健运行

在Linux环境下,进程之间相互影响、相互依赖,就像一个大家庭一样。作为程序员,我们不仅需要创建子进程,更要熟练掌握监控和管理子进程的技能,确保整个进程族能稳健高效地运行。本文将为你揭开进程创建、监控子进程、处理…

【Vue】小黑记事本

文章目录 一、需求说明二、思路分析三、代码实现 一、需求说明 拆分基础组件渲染待办任务添加任务删除任务底部合计 和 清空功能持久化存储 二、思路分析 拆分基础组件 咱们可以把小黑记事本原有的结构拆成三部分内容:头部(TodoHeader)、列…

代码随想录训练营Day29

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、递增子序列二、全排列三、全排列2 前言 今天是跟着代码随想录刷题的第29天,今天主要学了以下几个内容:491.递增子序列、46.全排列、…

1877java项目建设平台管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 项目建设平台管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助采用了java设计,系统具有完整的源代码和数据库,系统采用web模式,系统主要采用B/S模式开 发。开发环境为TOMCAT7.0,Myeclipse8.…

工频耐压试验仪

武汉凯迪正大智能5KV工频耐压仪是根据国家行业试验标准而设计的试验设备,其功能强、使用方便、维护简单。主要用于对各种电器产品、电气元件、绝缘材料等进行规定电压下的碳化试验,绝缘强度试验,以考核产品的绝缘水平,发现被试品的…

将小爱音箱接入 ChatGPT 和豆包ai改造成专属语音助手

这个GitHub项目,mi-gpt,旨在将小爱音箱和米家设备与ChatGPT和豆包集成,有效地将这些设备转变为个性化语音助手。以下是对其功能和设置的详细分析: 主要特点 角色扮演:该项目允许小爱适应不同的角色,如伴侣…

源码编译安装LNMP

目录 LNMP包含: LNMP的工作原理 : 编译安装: nginx服务器配置 安装依赖包 创建用户 上传软件包至/opt目录下并解压 编译安装 设置软链接,可以直接调用nginx命令来进行管理 添加Nginx系统服务 配置Nginx支持php解析&…

关于文件上传失败问题的排查思路

问题场景: 最近公司的app有很多用户反馈上传文件失败了。业务路径就是简单的app前端调用后端文件上传接口,所以发生上传失败的可能因素可能是:1、文件大小/文件类型等是否有问题,公司用的是七牛的文件服务器,对文件上…

淘宝扭蛋机源码解析:功能实现与技术细节

随着在线购物和娱乐的融合,淘宝扭蛋机作为一种创新的购物娱乐方式,受到了广大用户的喜爱。本文将深入解析淘宝扭蛋机的源码,探讨其功能实现与技术细节,以期为开发者们提供一些有价值的参考。 一、功能实现 1.用户登录与注册 淘宝…

《令狐带你阅读JDK源码之简单集合ArrayList》

文章目录 Java简单集合ArrayList继承体系源码解析 总结 大家好哈,欢迎来到令狐小哥本期专栏,这期专栏主要是带着大家阅读JDK源码,我会分几期篇幅来介绍这个jdk源码、会进行剖析、梳理,欢迎大家指正阅读。后面我会配套自己的视频进…

【C++题解】1090 - 同因查找

问题:1090 - 同因查找 类型:for循环、简单循环 题目描述: 求出 10 至 1000 之内能同时被2、3、7 整除的数,并输出。 每行一个。 输入: 无。 输出: 按要求输出满足条件的数,每行 1 个。 完…

TiDB-从0到1-配置篇

TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCCTiDB-从0到1-部署篇TiDB-从0到1-配置篇 一、系统配置 TiDB的配置分为系统配置和集群配置两种。 其中系统配置对应TiDB Server(不包含TiKV和PD的参数&#xff0…

GaussDB技术解读——GaussDB架构介绍(一)

目录 1 GaussDB 关键架构目标 2 GaussDB分布式架构 2.1 GaussDB 分布式关键技术架构 3 数据计算路由层(Coordinator)关键技术方案 3.1 分布式优化器 3.2 分布式执行框架 GaussDB是华为自主创新研发的关系型数据库,基于华为在数据库领域…

vivo手机如何改ip地址

在数字化时代,网络已成为我们日常生活和工作中不可或缺的一部分。而IP地址,作为网络连接的唯一标识,有时出于安全或隐私的需要,我们可能希望对其进行更改。对于使用vivo手机的用户来说,如何轻松修改IP地址可能是一个令…

2024后端服务架构升级

文章目录 背景改造方案新架构图技术选型思考 服务拆分公共组件设计自部署算法服务排期计划 全球多活改造背景架构图分布式ID大表分区处理范围使用用途改造方案排期计划升级预算 背景 1、xx业务经过多轮的业务决策和调整,存在非常多技术包袱,带了不好的用…

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:轨道交通监控系统

株洲中车时代电气股份有限公司(下称中车时代电气)是中国中车旗下股份制企业,其前身及母公司——中车株洲电力机车研究所有限公司创立于1959年。中车时代电气扎根株洲,走好两条钢轨,走出两条钢轨。中车时代电气秉承“双…