WIN32汇编语言教程:第10章 内存管理和文件操作 · 10.3 驱动器和目录(1)
先简单复习一下Windows中的逻辑驱动器、目录和路径等基本概念。
Windows中的文件组织方式与DOS操作系统类似,也是采用分层次的结构:计算机中可以安装有多个物理驱动器,每个物理驱动器可以分为多个主分区和扩展分区,每个主分区就是一个逻辑驱动器,而每个扩展分区可以划分成多个逻辑驱动器,逻辑驱动器组成了我们熟悉的C盘与D盘等盘符。
如图10.6所示,假如计算机上安装了2个硬盘和2个光驱,每个硬盘都分为一个主分区和一个扩展分区,其中第一个硬盘的扩展分区中又分为3个逻辑驱动器,第二个硬盘的扩展分区分为2个逻辑驱动器,那么计算机中的逻辑驱动器就会从C盘排列到K盘为止。
图10.6 逻辑分区的分配
对于每个逻辑驱动器,可以给它取一个标号叫做“卷标”(Volume Label),卷标是当做一个目录项存放在逻辑驱动器的根目录中的。在每个逻辑驱动器中可以有多个文件,文件可以存放在各个目录中,目录是按照多层树状结构来安排的,每个逻辑驱动器中有个顶层目录叫做“根目录”,根目录下可以安排多个子目录,每个子目录中也可以包含多个下层子目录,一个逻辑驱动器中能够存放文件和子目录的数量只受限于驱动器的空间大小。
虽然同一个子目录中的文件名必须是惟一的,但不同的子目录中可以存在同名的文件,所以只有文件名的话并不能惟一确定一个文件,要惟一确定文件还需要指出文件的位置,除了指出文件位于的逻辑驱动器外,还要指出从根目录开始一直到文件所在目录为止的所有子目录名,这就是路径。
对一个进程来说,Windows维护一个当前驱动器,并为每个逻辑驱动器维护一个当前路径,如果不指定路径,表示要操作的文件就位于当前驱动器的当前路径下。如果要操作非当前路径下的文件,就必须明确指出包含全路径的文件名。比如指定一个文件System.ini,如果当前目录下有这个文件,那么操作的对象就是这个文件,如果当前目录下并没有这个文件,即使其他目录中存在多个同名的文件,程序也无法知道它究竟对应哪个文件。
Win32中有一部分函数专门用来完成与逻辑驱动器及目录有关的操作,在本节中将具体讨论这些函数的使用方法。
10.3.1 逻辑驱动器操作
1. 卷标操作
为一个驱动器创建、修改以及删除卷标都使用SetVolumeLabel函数。如果要创建或修改卷标(如果原来没有卷标则为创建,原来存在卷标则为修改)可以这样使用:
szPath db 'c:\',0 szVolume db 'System',0 invoke SetVolumeLabel,addr szPath,szVolume
本例中,C盘的卷标会被设置为System,第一个参数指出了要设置卷标的逻辑驱动器的根目录,如果要设置C盘的卷标,目录名既不能写为“c:”也不能写为“c:\windows”,必须写为“c:\”,否则函数调用会失败;第二个参数则指向包含卷标字符串的缓冲区。
删除一个逻辑驱动器的卷标有两种方法。方法一是:
szPath db 'c:\',0 szVolume db 0 invoke SetVolumeLabel,addr szPath,szVolume
方法二是:
szPath db 'c:\',0 invoke SetVolumeLabel,addr szPath,NULL
这两种方法的执行结果是一样的。如果函数执行成功,返回值是TRUE,否则返回FALSE。
获取卷标可以使用下面介绍的GetVolumeInformation函数。
2. 逻辑驱动器的检测
要检测系统中当前存在多少个逻辑驱动器可以使用GetLogicalDrives函数,函数返回了所有可用的盘符。GetLogicalDrives函数没有输入参数,它返回一个32位的整数,用其中的每一位代表是否存在一个逻辑驱动器。由于系统中可用的盘符仅有26个(A:~Z:),所以32位已经可以反映出所有的逻辑驱动器以及它们的盘符分布情况了,返回值的第0位到第25位分别代表驱动器A:~Z:是否存在,如系统中存在A,C,D,E和F 5个逻辑驱动器的时候,返回值的二进制数值为00000000000000000000000000111101b,也就是16进制的0000003dh。
如果认为GetLogicalDrives函数返回的数据要进行位测试比较麻烦,可以使用另一个函数:GetLogicalDriveStrings,这个函数返回字符串类型的逻辑驱动器列表:
invoke GetLogicalDriveStrings,dwBufferSize,lpBuffer
lpBuffer指向一个缓冲区,函数在这里返回“A:\”,0,“B:\”,0,“C:\”,0,0格式的字符串,凡是存在的逻辑驱动器都会列在这个字符串中,字符串列表以一个附加的0结束;dwBufferSize指出缓存区的大小,如果缓冲区不够大,后面的数据会被截尾。
获取了逻辑驱动器的分布情况后,有时候还必须了解某个逻辑驱动器的类型,因为它可能是各种类型的盘——软盘、硬盘、光驱和内存中的虚拟盘等都是以逻辑驱动器的模样出现的。虽然文件操作函数中可以不必理会文件究竟位于什么样的驱动器上,只要指定全路径的文件名就可以透明地工作,但有时候必须检测盘的类型,比如,希望对软件进行保护,要求文件必须位于光盘上,那么就需要检查文件所在的逻辑驱动器是否是光盘;另外,需要建立一个临时文件的时候,如果建立在只读的光盘上是不会成功的,为了保证创建的成功,需要预先检测一下程序是否运行于硬盘上。
检测驱动器类型的工作可以用GetDriveType函数来完成:
szPath db 'c:\',0 invoke GetDriveType,addr szPath
该函数惟一的一个参数指向存放有逻辑驱动器根目录的字符串的缓冲区,函数的返回值是逻辑驱动器的类型,它可能是下面取值中的一种:
● 0—驱动器类型无法检测。
● 1—指定的根目录不存在。
● DRIVE_REMOVABLE—可移动介质,如软盘。
● DRIVE_FIXED—固定盘,如硬盘中的逻辑驱动器。
● DRIVE_REMOTE—远程驱动器,如网络上映射的驱动器。
● DRIVE_CDROM—光盘。
● DRIVE_RAMDISK—内存虚拟盘。
如果需要更详细的情况,可以使用GetVolumeInformation函数,这个函数可以返回逻辑驱动器的卷标、序列号和文件系统类型等属性:
invoke GetVolumeInformation,lpRootPathName,\ lpVolumeNameBuffer,dwVolumeNameSize,\ lpVolumeSerialNumber,lpMaximumComponentLength,\ lpFileSystemFlags,\ lpFileSystemNameBuffer,dwFileSystemNameSize
参数lpRootPathName指向需要检测的驱动器根目录字符串,如果要检测的是网络上的驱动器,那么字符串可以是“\\服务器名\共享名”格式。
后面的各个参数指向一些用来返回数据的缓冲区。
lpVolumeNameBuffer指向一个字符串缓冲区,用来返回驱动器的卷标,缓冲区的长度由dwVolumeNameSize参数指出。
lpVolumeSerialNumber指向一个双字变量,函数在这里返回逻辑驱动器的序列号。序列号是驱动器被格式化的时候由系统随机生成的一个32位数,它保存在位于驱动器第一个扇区的引导记录中。在程序的运行中检测并记录软盘的序列号就可以检测到软盘是否被更换。
lpFileSystemFlags指向一个双字变量,函数在这里返回最大允许的文件名长度,在Windows系统中一般这个数值是255。
上页:第10章 内存管理和文件操作 · 10.2 文件操作(10) 下页:第10章 内存管理和文件操作 · 10.3 驱动器和目录(2)