自强不息系列之基于SDK的Windows应用程序框架代码详解

1、必须包含头文件windows.h

WINDOWS.H是一个最重要的头文件,它包含了其他Windows头文件,这些头文件的某些也包含了其他头文件。这些头文件中最重要的和最基本的是:

WINDEF.H 基本数据类型定义。

WINNT.H 支持Unicode的类型定义。

WINBASE.H Kernel(内核)函数。

WINUSER.H 用户界面函数。

WINGDI.H 图形设备接口函数。

这些头文件定义了Windows的所有资料型态、函数调用资料结构和常数识别字,它们是Windows文件中的一个重要部分。

其实,远不止这些,我们可以打开该文件看一看,如果vc++6.0安装在C盘,那么我们可以在C:\Program Files\Microsoft Visual Studio\VC98\Include目录下打开该文件。当然WINDEF.H等文件也在这个目录下。这个目录下几乎包含了windows开发的所有的头文件。比如网络通信程序开发时所用的WINSOCK.H头文件等。

2、声明窗口过程函数

窗口过程函数声明如下:

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

LRESULT  看上去很奇怪。

其实LRESULT  是在WINDEF.H中定义的,可以在VC++6.0用鼠标选择LRESULT 然后点鼠标右键,查看其定义,定义如下:

typedef LONG LRESULT;

L 的意思是LONG    RESULT  的意思是结果、返回值。加在一起就是返回长整型的意思。

注意:typedef LONG LRESULT; 并不是创建了另一个数据类型,只是给 LONG类型定义了另一个别名。其实,我们会发觉在C或C++中也没有一种数据类型为LONG,只有long类型。如果我们继续用上面提到的方法查看LONG类型的定义,我们会发觉LONG在WINNT.H文件中定义为:

typedef long LONG;

所以,所谓的LRESULT 其实就是long类型。只是他还有另一个名字叫LRESULT。

Windows应用程序为我们定义了很多的这样的数据类型别名。

下面我们详细的介绍一下windows的常用数据类型。

我们查看WINDEF.H文件,可以看到windows为我们定义的一些常用的数据类型及常量如下:

typedef  unsigned long       DWORD;
typedef  int                 BOOL;
typedef  unsigned char       BYTE;
typedef  unsigned short      WORD;
typedef  float               FLOAT;
typedef  FLOAT               *PFLOAT;
typedef  int                 INT;
typedef  unsigned int        UINT;
typedef  unsigned int        *PUINT;
typedef  UINT WPARAM;
typedef  LONG LPARAM;
typedef  LONG LRESULT;
#define  MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define  MAKELONG(a, b)    ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
#define  LOWORD(l)           ((WORD)(l))
#define  HIWORD(l)           ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define  LOBYTE(w)           ((BYTE)(w))
#define  HIBYTE(w)           ((BYTE)(((WORD)(w) >> 8) & 0xFF))

可以看到DWORD其实就是一个无符号的长整型的别名,所占内存为4个字节;

typedef  int                 BOOL;

BOOL型其实就是int的别名。所占内存为4个字节。

typedef  float               FLOAT;

FLOAT 就是float类型的别名。请注意:BOOL 与 bool之间的区别,bool为布尔类型,所占内存只有一个字节。再看一个定义:

typedef  FLOAT  *PFLOAT;

有点奇怪吧!我们把它的写的格式变一下:

typedef   FLOAT  *  PFLOAT;

我们发觉PFLOAT 就是FLOAT * 即 float * 也就是浮点数指针。

也就是凡是以字母”P“开头的表示他是一个指针类型。

再看两个定义:

typedef  int near            *PINT;

typedef  int far             *LPINT;

多了两个修饰符 near   段内        4G虚拟内存空间内寻址      32 位地址

               far    段间        在整个64T虚拟内存空间寻址 32位地址

无论是PINT 还是 LPINT 都是一个4节的int * 类型,即是一个整型指针。再看一个定义:

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))

有点奇怪吧:其实MAKEWORD宏,从字面意义上来看就是”制造字“的意思,也就是用两个字节类型的数据来构成一个字。比如:

MAKEWORD(1,2)

该宏被替换后为:

((WORD)(((BYTE)(a))|((WORD)((BYTE)(b)))<<8))

将括号简化后该语句变为:

(WORD)(BYTE)(a) | (WORD)(BYTE)(b) << 8

语句执行顺序为:

  1. 将a转化为BYTE类型,然后再将前一步转换的结果转换为WORD类型,
  2. 将b转换为BYTE类型,然后再将前一步的结果转换为WORD类型,然后再左移8位。
  3. 再将第一步的结果和第二步的结果按位相或。

所以MAKEWORD(1,2)

的执行过程为:

 1、             00000001    将1转化为BYTE类型 即8位二进制数

         0000000000000001    将00000001转化为WORD类型

2、              00000010    将2转化为BYTE类型 即8位二进制数

 0000000000000010    将00000010转化为WORD类型

 0000001000000000    左移8位

     3、      0000001000000001    按位相或

我们在编程过程中常常会用到这个宏,比如加载函数库时需要提供函数库的版本,版本通常分为主版本和次版本,版本会通过一个参数进行传递,此时就可以通过:

MAKEWORD(次版本号,主版本号)来获得一个版本参数。

我们在进行WIN SOCKET 套接字编程时就需要用到这个宏,来确定WIN SOCKET库的版本号。

再看两个定义:

#define LOWORD(l)           ((WORD)(l))

该宏的功能为:获取长整型数的低十六位。

#define HIWORD(l)           ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))

该宏的功能为:获取长整型数的高十六位。

这两个在后面的编程中我们也会用到,当我们点击鼠标时,鼠标的坐标会通过一个32位数传递给窗口过程函数的lparam参数。

要的到x坐标和y坐标就可以通过如下代码得到:、

int x = (int)LOWORD(lparam);

Int y = (int)HIWORD(lparam);

我们需要适应windows为我们定义的这些数据类型的别名,这样做的目的主要是看到数据类型名,就可知道该数据的功能。

函数的调用约定——CALLBACK 以及 WINAPI

接下来我们会看到一个叫CALLBACK 的奇怪的单词,还有接下来windows应用程序的入口函数定义时的WINAPI。在函数前面加上这两个东东是做什么的呢?

CALLBACK和WINAPI与函数的调用约定有关。由CALLBACK和WINAPI修饰的函数又被称之为“回调函数。一般来说在应用程序中编写的函数,即可以被应用程序调用,也可以被windows操作系统来调用。但是,如果一个函数在声明时用CALLBACK和WINAPI来修饰,则表明该函数是被操作系统调用。这些函数包括:窗口过程函数,线程函数等。应用程序一般不会调用”回调函数“。之所以把应用程序提供给操作系统调用的函数称之为”回调函数“,是与操作系统提供给应用程序调用的API函数相比较而言的。API是操作系统提供给应用程序调用的函数,而”回调函数“是应用程序提供给操作系统调用的函数。

有两种函数调用约定。一种是: __stdcall。另一种是_cdecl。

被普通应用调用的函数的函数的调用约定为_cdecl调用约定。、

而被操作系统调用的函数的调用约定为:__stdcall。

其中CALLBACK 和WINAPI 的含义是:规定该函数的调用约定为__stdcall。我们可以在Microsoft Visual C++ 6.0中选中“WINAPI ”,点右键:如图所示:

可以看到WINAPI 被定义为:#define WINAPI      __stdcall

函数的默认调用约定为:_cdecl调用约定。

这两种调用约定有何区别呢?其实他们的区别很小。主要是函数形参内存的回收方式上有所区别。

下面我们创建一个名叫“调用约定的”控制台应用程序(创建过程就不再赘述)。

输入如下代码:

在“add(i,j);”语句前设置断点。然后调试运行。调试运行菜单操作如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术小咖龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值