[TOC]
起步
介绍主函数入口参数
[upl-image-preview url=https://forum.crash.work/assets/files/2024-10-25/1729840738-404405-windows-api-1-1.png]
- 第一个参数:
HINSTANCE
类型的参数,称为“实例句柄" , 这个参数唯一标志了我们写的这个程序。
- 第二个参数:
HINSTANCE
类型的参数,该参数也为句柄。
- 该句柄在多路并发同一个程序的时候会被访问,通过hPrevInstance来判断是否有它的其他实例在运行,然后将前一个实例的数据搬过来,从而提高效率。不过已经是时代遗留下来的参数了,因为在32位windows机械下,该概念不再被采用,因此第二个参数的值为NULL即0。
- 第三个参数:
LPSTR
类型的参数,这个参数是用来运行程序的命令行,当程序执行时用它来把文件装入内存。(input)
- 第四个参数:
int
类型的参数,这个参数指明了程序最初显示的方式:或正常显示,或者全屏显示,或最小化显示在任务栏上。
简单介绍Windows.h这个头文件
windows.h
这个头文件,包含了若干个Windows头文件,其中最基本且重要的如下:
WINDEF.H//基本数据类型定义
WINNT.H//支持Unicode的类型定义
WINBASE.H//内核函数
WINUSER.H//用户界面函数
WINGDI.H//图形设备接口函数
Unicode简介
字符集简史
对于Unicode的发展不再缀叙
- 简而言之: 随着计算机的发展与不断普及,ASCII码已经不足以应对计算机全球化,因此Unicode编码应运而生。Unicode编码是16位,而ASCII码是8位,因此Unicode可以存储更多信息,以应对应对全球化并提供一个标准。 另外一提 Unicode 被认为是“宽字符”,且Unicode只有一个字符集(因此避免了"二义性")。
- 注意: 在发展史上,并不是ASCII码无法适应全球化后就直接出现了Unicode,实际上这期间还有例如 “扩展 ASCII” ,”ANSI字符集” , “DBCS”等等。
- 宽字符 并不一定是 Unicode。 Unicode只是宽字符编码的一种实现,但我们后续的重点是为了研究和学习了解 Windows API , 因此后续我们会将 宽字符和Unicode划等号
char数据类型
为了后续对宽字符的研究,这里对char数据类型进行一个介绍,相信学过c/c++的各位对char数据类型都有自己的认识,但是还请看下去,或许会有一些收获
下面声明定义和初始化一个包含单一字符的变量
char c = 'A';
变量c会申请一个字节大小的存储空间而且会用十六进制0X41来初始化这个存储空间。也就是ASCII字母A的符号。
讲解 字符串的指针 和 字符数组
字符串指针: char* p = "Hello!";
在32位机器上,指针的大小为4个字节,这里的 指针p指向了 字符串 “Hello!”
注意: 这里是 指针p指向了 字符串”Hello!” ,这个字符串”Hello!”是存储在静态内存中并使用7个字节的存储空间----其中6个字节存储字符串而另一个字节存储表示字符串结尾的’\0’
字符数组: 我们定义一个char a[10];
这种情况下编译器为数组a保留了10个字节的存储空间。sizeof(a);
表达式返回10。
如果这个数组是全局的,我们可以属于静态字符串对其进行初始化:char a[] = "Hello!";
如果这个数组是一个局部变量,那么它必须定义为静态变量:static char a[] = "Hello!";
总结:无论是以上那种情况,字符串始终被存储在静态内存中,并有一个’\0’在最后,一共需要7个字节的存储空间。
更宽的字符
使用Unicode 或者是 宽字符 并不会改变 C语言中的字符数据类型,char类型仍然为1个字节的存储空间,而且sizeof(char);
继续返回1.
**这里第一个字节存储了*0X41* , 第二个字节存储*0X00*。**
- 单个字符的定义其实也可以加L,即 wchar_t c = L’A’; 也是可以的,这是这个就没有那么必要了。
宽字符库函数
- 如果用
strlen
来计算 宽字符串 的长度, 那么结果会是怎么样的呢?
- 首先我们知道对于
char* p = “Hello!”
而言,strlen(p);
的结果是 6 , 可是对于 wchar_t wp = L”Hello!”;
而言 , strlen(wp);
会先报个error
,这个error
说明了 strlen
接受的参数一个是一个指向char的指针,而不是一个指向unsigned short
的指针。但是我们仍然可以强制编译,但是结果会显示1。
为什么这里的结果会是1呢?
- 这是因为对于 宽字符串“Hello!” 而言,它的16位值如下
0X0048 0X0065 0X006C 0X006F 0X0021
- 而由于小端存储的原因,逐个字节来看其存储如下
48 00 65 00 6C 00 6F 00 21 00
- 而对于
strlen
函数,它是以一个字节为单位进行检索的,在检索到0时停止,因此它在计算第一个字符后就停止了,返回1。
- 看到这里,我们可以知道我们必须对C语言库中那些有字符串参数的函数进行重新,不过幸运的是 这些函数的重写已经被完成了,而不需要我们对其进行重写。
- 宽字符版本的
strlen
函数被称为wcslen
(宽字符的长度)函数,被定义在STRING.H
(也就是定义strlen
被定义的地方)和WCHAR.H
中。
- strlen函数的声明如下:
size_t _cdecl strlen(const char*);
- wcslen函数的声明如下:
size_t _cdecl wcslen(const wchar_t*);
- 所以我们可以通过
wcslen
函数来计算wp
的长度,wcslen(wp);
,返回值为6。也就是字符个数为6.
- 注意:在使用宽字符时,宽字符串的长度并没有改变,改变的只是字节长度
维护一个源代码文件(一个很巧妙的设计)
上文我们可以知道,对于宽字符的大小是大于普通字符的,宽字符运行库函数比正常的函数要大,为此可能会想要写两个版本的程序,一个用ASCII字符串,而另一个用Unicode字符串。那么最好的方法是什么呢? 最好的办法是 维护一个单一的源代码文件,但是可以编译成ASCII或者Unicode!!! 【这个设计是否的巧妙,笔者感觉已经是有 泛型 的雏形了,但是对于C语言这个面向过程的语言,如何实现这个设计?,下面我们就要看大神的设计实现和演示了,相信各位会收益,至少笔者是感觉收益良多的】