Windows编程(2)

编程入门 行业动态 更新时间:2024-10-27 20:35:56

<a href=https://www.elefans.com/category/jswz/34/1771365.html style=Windows编程(2)"/>

Windows编程(2)

文章目录

  • windows有关的重要概念
    • 句柄
    • 窗口
    • Windows的消息机制
      • 消息结构体
  • 宽字符与Unicode
    • 宽字符串的长度
    • ASCII 和 Unicode 兼容性问题
  • Windows数据类型

windows有关的重要概念

句柄

在学习Windows编程的过程当中,相信很多人都听说过“句柄”这个词语吧,相比好多人还是不清楚具体怎么回事儿。接下来我简单介绍一下。所谓“句柄(HANDLE)”;不过就是在Windows编程中,不同窗口、控件、图像等对应的一个唯一的数字,可以理解为ID吧。程序通过句柄获取对应资源的各种信息,修改,删除资源。
句柄里面有很多细节,程序员不需要了解背后的机制。比如说用 CreateFile() 函数创建文件后会返回一个文件句柄,然后通过这个句柄就可以读写、删除该文件,里面很多细节我们无从知道,只有微软知道。
还不能理解的话,用一个曾经看到的生动的比喻描述一下吧。

你可以将句柄理解为学号,你不需要记住学生的姓名、住址、成绩等各种信息,当你需要了解这名学生时,只要去教务处,将学号(句柄)告诉那里的工作人员(Windows),他就能够帮你找到这个学生。

窗口

一说到Windows,大家第一反应相比就是窗口了吧(反正我是如此),Windows 的核心就是窗口。而窗口也比较容易理解,就是我们看到的这种界面,框框。
这些窗口可以包含输入框下拉菜单单选按钮文本区域等各种各样的控件(Controls)

窗口、控件、图像、音频视频等都称为资源(Resource),在程序中都可以使用、创建、添加、修改等。

Windows的消息机制

我们知道,DOS靠过程来驱动,而windows靠消息驱动。

消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。
什么意思呢?
也就是说,在一般的编程中,我们通过 API 函数来调用系统功能,让操作系统来帮我们完成很多工作,非常方便。反过来,操作系统也会“偷懒”,会调用我们程序中的函数,让我们自己处理某些事情。例如用户敲击键盘,操作系统会首先收到通知,但它并不会处理,而是调用程序中的函数,告诉程序用户敲击了键盘,你自己处理好了;如果程序不处理,操作系统才会进行默认的操作。

当有事件发生时,Windows 会生成一条消息(Message),告诉程序发生了什么事情。这与我们平时理解的“消息”是类似,都表示一种传递信息的载体。

那么,Windows 是如何通过消息将发生的事件通知给应用程序的呢?

每当事件发生时,Windows 会生成一条消息,并放到一个由系统维护的队列中。然后,程序会自己从这个队列中获取消息并分析,调用事件处理函数(处理事件的代码也就在这个函数中),对用户的操作进行响应。

注意:Windows 向队列中分派消息和应用程序从队列中获取消息并不是同步的,Windows 不管队列中有没有消息,不管应用程序有没有处理完毕,只要有事件发生,就会将消息丢进队列,什么时候处理完毕是应用程序的事。

可见,消息是连接 Windows 和应用程序的纽带,Windows 通过消息告诉应用程序发生了什么,应用程序通过消息知道该做什么。这些应用程序不是通过显式地函数调用来获取输入,而是等待系统将输入传递给它们。

消息结构体

消息其实是一个结构体,名字为 MSG,定义如下:

typedef struct tagMSG {HWND hwnd;UINT message;WPARAM wParam;LPARAM lParam;DWORD time;POINT pt;
} MSG;

MSG 结构体中各成员变量的含义如下:

  • hwnd表示消息所属的窗口。用户一般是在程序的窗口下进行操作,所以一个消息一般都是与某个窗口相关联的。例如在某个窗口中按下鼠标左键,产生的按键消息就是发给该窗口的。

  • message表示消息类型,是一个数值。在Windows中,消息是由一个数值来表示的,不同类型的消息对应不同的数值。但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM是Window Message的缩写)的形式,XXX 对应某种消息的英文拼写的大写形式。例如,鼠标左键按下消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是WM_CHAR,等等。在程序中我们通常都是以WM_XXX宏的形式来使用消息的。

  • 第三、第四个成员变量wParam和lParam,用于指定消息的附加信息。例如,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户到底输入的是什么字符,那么就由wParam和lParam来说明。wParam、lParam表示的信息随消息的不同而不同。

  • 最后两个变量分别表示消息投递到消息队列中的时间和鼠标的当前位置。

宽字符与Unicode

在C语言中,我们使用char来定义字符,占用一个字节,也就是用ASCII码表示,但这最多只能表示128个字符。问题是,世界上存在很多不同的语言,汉语日语韩语等等,这些语言用128个字符的ascii码来表示就显得鸡肋了。这时就需要用多字节来表示了,称之为宽字符(Wide Character)Unicode编码就是宽字符编码的一种,如今被现代计算机指定为默认的编码方式。Windows 2000、XP、Vista、Win7、Win8、Win10、Windows Phone、Windows Server 等(它们统称为 Windows NT)都从底层支持Unicode。

C语言中的宽字符
在C语言中,使用wchar.h头文件中的wchar_t来定义宽字符,例如:

wchar_t ch = 'A';

wchar_t 被定义为typedef unsigned short wchar_t,和一个无符号整型一样,占用两个字节。

如果定义宽字符串,需要加前缀L,(L是必须要加的,并且与字符串之间不能有空格)。
例如:

wchar_t *str = L"hello world!";

再比如说:

#include <stdio.h>
#include <wchar.h>
int main()
{char ch = 'A';wchar_t lch = 'A';char str[] = "Windows编程";wchar_t lstr[] = L"Windows";printf("ch=%d, lch=%d, str=%d, lstr=%d\n", sizeof(ch), sizeof(lch), sizeof(str), sizeof(lstr));return 0;
}

输出结果为:
ch = 1, lch = 2, str = 12, lstr = 16

宽字符串的长度

我们都知道计算字符串长度使用 strlen 函数但这仅仅局限于ASCII码,而计算宽字符串长度就要使用 wcslen 函数,如下:

#include <stdio.h>
#include <string.h>
#include <wchar.h>
int main()
{char str[] = "C语言大法好";wchar_t wstr[] = L"C语言大法好";printf("strlen(str)=%d, wcslen(wstr)=%d\n", strlen(str), wcslen(wstr));return 0;
}

运行结果:
strlen(str)=11, wcslen(wstr)=6
strlen 的运行结果显然不正确,因为它把一个字节作为一个字符计算,而 wcslen 把两个字节作为一个字符计算。

ASCII 和 Unicode 兼容性问题

在 Windows NT 以前的操作系统对宽字符的支持都不是很好,大多情况下使用ASCII编码。Windows NT 推出以后,从底层支持了Unicode,所以在 Windows NT 上的程序大多使用Unicode。
如果想要程序再各个Windows版本都兼容,就要进行ascii和Unicode的转换,显然,这种工作量是巨大的。
不过Windows考虑周到了,我们看看他是如何做的:

对于字符串,ASCII 中使用 char 来定义,Unicode 中使用 wchar_t 来定义,并且需要添加前缀L。那么在 windows.h 头文件中(或者是它包含的其他头文件)就这样来处理:

#ifdef UNICODE
typedef wchar_t TCHAR;
#define TEXT(quote) L##quote
#else
typedef char TCHAR
#define TEXT(quote) quote
#endif

我们在源码中可以这样来使用:

TCHAR str[] = TEXT("Windows编程");

如果是ASCII,也就是没有定义UNICODE宏,那么上面的语句等价于:

char str[] = "Windows编程";

如果是Unicode版,也就是定义了UNICODE宏,那么上面的语句等价于:

wchar_t str[] = L"Windows编程";

Windows数据类型

Windows使用typedef#define定了很多新的数据类型。这些数据类型在windows.h头文件中定义:

typedef int                 INT;       /* 整形 */
typedef unsigned int        UINT;      /* 无符号整形 */
typedef unsigned int        *PUINT;    /* 无符号整形指针 */
typedef float               FLOAT;     /* 浮点型 */
typedef FLOAT               *PFLOAT;   /* 指向float类型指针 */
typedef unsigned char       BYTE;      /* 字节 */
typedef unsigned short      WORD;      /* WORD (无符号短整型) */
typedef unsigned long       DWORD;     /* DOUBLE WORD (无符号长整形)*/
typedef int                 BOOL;      /* 布尔类型 */
typedef BOOL near           *PBOOL;    /* 指向布尔类型指针 */
typedef BOOL far            *LPBOOL;
typedef BYTE near           *PBYTE;    /* 指向字节类型指针 */
typedef BYTE far            *LPBYTE;
typedef int near            *PINT;     /* 整形指针 */
typedef int far             *LPINT;
typedef WORD near           *PWORD;    /* 指向WORD类型的指针 */
typedef WORD far            *LPWORD;
typedef long far            *LPLONG;   /* 指向长整形的指针 */
typedef DWORD near          *PDWORD;   /* 指向DWORD类型的指针 */
typedef DWORD far           *LPDWORD;
typedef void far            *LPVOID;   /* 指向void类型的指针 */
typedef CONST void far      *LPCVOID;  /* 指向void类型的常指针 */

可能很多人会对那个 far 和 near 觉得有疑问,其实,这个 far 和 near 只是用来标识变量的新旧的,例如 PINT 和 LPINT 实际上都是 int *,只不过一个是老式写法,一个是新式写法,这都是为了兼容问题。
我们来看看Windows 数据类型名命名的规律:

  • 一般是以“U”开头,比如“INT”对应的“UINT”。
  • 以 “P” 开头的都是指针(pointer)类型("LP"是老式写法)
  • 以“H”开头。比如,HWND 是window(WND简写)也就是窗口的句柄,菜单(MENU)类型对应的句柄类型为 “HMENU” 等等。
  • 加了L就是以前的老旧写法

更多推荐

Windows编程(2)

本文发布于:2023-07-01 22:37:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/982156.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Windows

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!