文章目录

  • 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)相关推荐

  1. 如何使对话框中接收到WM_CHAR消息(Windows编程)

    我们大家都知道,对话框是有的时候捕获不到WM_CHAR消息的.比如,你想使对话框里的Edit控件所键入的全部变为大写.我们毫不犹豫的写到:    #include //Declare the Dial ...

  2. 使用c++进行Windows编程中各种操作文件的方法 【转】

    https://www.zhaokeli.com/article/8232.html 使用c++进行Windows编程中各种操作文件的方法 [转] 来源:赵克立博客 分类: C/C++ 标签:--发布 ...

  3. 【Windows编程】系列第三篇:文本字符输出

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇我们展示了如何使用Windows SDK创建基本控件,本篇来讨论如何输出文本字符. 在使用Win32编程时,我们常常要输 ...

  4. Windows编程一日一练(1)

    首先,编程和旅游是我个人人生两大爱好,所以,每天空闲的时候我喜欢敲敲代码,或者看看别人写的程序,实在是很惬意.今天想看看window编程,争取坚持每日一练.        windows程序主要是由微 ...

  5. Windows 编程

    Delphi 利用Object Pascal 和可视控件库(VCL)对底层的Windows API 进行了完美的封装,所以很少需要使用基础Pascal 语言来建立Windows应用程序,也无需直接调用 ...

  6. 一个物理学家学习Windows编程的感受

    最近学习用Visual C++ 作为平台的Windows 编程,感觉到学习这种编程技术的过程与学习物理的思维差异非常大.最明显的,比如对于物理课本,在学习的时候值得一个字一个词的认真去读,有时候需要读 ...

  7. C++,C++编程,Windows编程,MFC

    编程 我们日常生活中接触到的电子类产品中的应用都是由编程而来 为什么编程,偷懒 我们通过编程驱使(指挥,命令)的是电信号 为什么上面说编程是偷懒,电的发现,给人们带来了便利,人们在各个方面驱使(换成& ...

  8. Windows编程初步(一)

    第一节:安装帮助文档 使用C语言进行Windows开发,必然使用到WindowsSDK.Windows SDK指Windows开发人员工具包,是为使用C语言开发Windows程序所提供的工具集.里面提 ...

  9. 学好Windows编程要看的书籍

    本文是接着前面的学好C++要阅读的书籍而写的,如果想了解C++的学习的话请先看学好C++要阅读的书籍:http://blog.csdn.net/a809146548/article/details/4 ...

  10. C/C++:Windows编程—Hook IE浏览器实现URL拦截及更改(下)

    Hook IE浏览器实现URL拦截及更改(下) 前言 接上一篇 C/C++:Windows编程-Hook IE浏览器实现URL拦截及更改(上),本节为了实现上一篇待优化部分.实现IE进程时时监控,当有 ...

最新文章

  1. 基于深度学习的位姿估计方法
  2. 基于R的信用评分卡模型解析
  3. cron和crontab
  4. oracle删表分区同时维护索引,有关Oracle表分区进行(DML)维护后对索引的影响的分析...
  5. Zookeeper API 学习与使用
  6. List的三种遍历方式
  7. java长连接心跳包_socket中的短连接与长连接,心跳包示例详解
  8. java命令行编译命令_Java使用命令行编译运行程序
  9. 结队编程思路及感悟(python、tkinter、mysql、腾讯云短信等)
  10. org.tinygroup.database-数据库元数据定义
  11. java5、java6、java7、java8的新特性
  12. 查看linux操作系统版本信息
  13. 2021-09-23
  14. 四川师范大学地信概论(3- 空间数据模型)90分以上版本
  15. window7磁盘分区
  16. Kubernetes网络flannel之host-gw模式分析
  17. Nature:Jeff Dangl团队揭示贪噬菌属在微生物组中维持根的生长
  18. EnvironmentNotWritableError:The current user does not have write permissions to the target...
  19. CPU主频越高越好吗?
  20. Outlook默认接收地址修改

热门文章

  1. Zabbix监控通过企业微信报警
  2. 怎么导出微信语音【亲测有效】
  3. 教你一键采集天猫商品主图视频的方法及步骤
  4. 怎么做硬件产品的需求分析?
  5. 为什么Excel公式使用不了?
  6. y7000电池固件_y7000怎么刷电池固件|Surface Pro 3固件更新:电池续航问题终解决
  7. Android 说说Bitmap那些事
  8. zealer情感机器人_你曾经想象的到来——中文版temi机器人
  9. Vscode 与服务器建立远程连接(ssh)
  10. [转]天龙八部的BillingServer