作者归档:老沙

内存映射文件

使用内存映射文件
1.内存映射文件函数
内存映射文件包括:CreateFileMapping,OpenFileMapping,MapViewOfFile,UnmapViewOfFile和FlushViewOfFile.
创建一个内存映射文件对象使用CreateFileMapping这个步骤内存映射文件的用途(是在磁盘上建立内存映射文件,还是在页文件中建立进程间共享的映射

invoke CreateFileMapping,hFile,lpFileMappingAttributes,flProtect,dwMaximumSizeHigh,dwMaximumSizeLow,lpName
.if eax
mov hFileMap,eax

hFile:指定一个文件句柄.如果句柄是属于一个已经打开的文件的,那么内存映射文件将在这个文件上面建立;如果要建立存在于页文件中的内存映射供不同进程共享,那个hFile指定为-1
lpFileMappingAttributes:指向一个SECURITY_ATTRIBUTES结构,用来定义内存映射文件对象是否可继承
SECURITY_ATTRIBUTES结构,该结构定义如下

SECURITY_ATTRIBUTES STRUCT
nLength DWORD ? ;本结构的长度
lpSectrityDescriptor DWORD ?
bInheritHandle DWORD ? ;是否允许继承
SECURITY_ATTRIBUTES ENDS

将nLength设置为结构的长度,将bInheritHandle设置为TRUE就可以使句柄能够被子进程继承
不继承可把这个参数设置为NULL
flProtect:指定内存映射文件的保护类型,有3个取值
PAGE_READONLY:内存映射文件提交的内存页面是只读的,对应的CreateFile也要设置GENERIC_READ标志
PAGE_READWRITE:内存页面可读写,对应CreateFile设置GENERIC_READ和GENERIC_WRITE
PAGE_WRITECOPY:内存页可以有Copy on Write属性.对应CreateFile设置GENERIC_READ和GENERIC_WRITE
dwMaximumSizeHigh和dwMaximumSizeLow:这两个参数组合指定了一个64位的内存映射文件长度,如果内存映射文件用于磁盘文件的时候,这个长度如大于磁盘文件长度,磁盘文件将扩展到这个长度.如小于磁盘文件长度,那么只能存取磁盘文件的一部分,一种简单的方法是全设置成0,系统当自动调整磁盘文件大小
lpName:用来给定内存映射文件的名字.当内存映射文件作用于磁盘文件的时候,不需要给它起名;如用于进程间共享内存,那就必须为该对象命名,因为在其它进程中只有使用这个名称才能打开这个内存映射文件对象,该名字字符串不能和其他进程已创建的对象同名.

当一个进程创建内存共享文件用于和其他进程共享的时候,其它进程不能再使用CreateFileMapping去创建同样的内存映射文件对象,而是要用OpenFileMapping函数打开创建好的对象

invoke OpenFileMapping,dwDesiredAccess,bInheritHandle,lpName
.if eax
mov hFileMap,eax
.endif

dwDesiredAccess:参数指定保护类型,有3个取值
FILE_MAP_WRITE(或FILE_MAP_ALL_ACCESS):可写属性
FILE_MAP_READ:可读属性
FILE_MAP_COPY:Copy on write属性
lpName:指向的名字就是创建对象时使用的名字
如果CreateFileMapping或OpenFileMapping函数执行成功返回内存映射文件句柄,如果执行失败返回NULL

MapViewOfFile函数用来映射内存映射文件的一个视图,这个函数的用法

invoke MapViewOfFile,hFile,hFileMap,dwDesiredAccess,dwFileOffsetHigh,dwFileOffsetLow,dwNumberOfBytesToMap
.if eax
mov lpMemory,eax
.endif

hFileMap:CreateFileMapping或OpenFileMapping返回的句柄
dwDesiredAccess:指定保护类型
FILE_MAP_WRITE(或FILE_MAP_ALL_ACCESS):可写属性
FILE_MAP_READ:可读属性
FILE_MAP_COPY:Copy on write属性
dwFileOffsetHigh和dwFileOffsetLow:组成64位的偏移量,用来指定视图的基地址是从文件的哪个位置开始映射
dwNumberOfBytesToMap:指定映射的字节数,如果设置为0则映射的是整个文件,同时偏移地址被忽略
如果映射成功,返回一个地址,如果映射失败,则返回NULL

当不再使用映射文件后,通过UnmapViemOfFile函数撤销映射并使用CloseHandle函数关闭内存映射文件对象句柄

invoke UnmapViewOfFile,lpMemory
invoke CloseHandle,hFileMap

视图中的内存修改后,系统会在视图撤销映射或文件映射对象被删除时自动将数据写到磁盘上,但可以根据需要将对文件的修改立即写到磁盘上,该功能的函数FlushViewOfFile

invoke FlushViewOfFile,lpMemory,dwFileSize

该函数将从指定地址开始,指定大小的数据块中的脏页面写到磁盘,指定的内存范围必须位于视图的边界之内

2使用内存映射文件读写文件
内存映射文件读写文件的步骤
(1) 调用CreateFile打开想要映射的文件,得到hFile
(2) 调用CreateFileMapping函数生成一个建立在CreateFile函数创建的文件对象基础上的内存映射对象,得到hFileMap
(3) 调用MapViewOfFile把整个文件的一个区域或整个文件映射到内存中,得到指向映射到内存的第一个字节的指针lpMemory
(4) 用该指针来读写文件
(5) 调用UnmapViewOfFile来解除文件映射,传入参数为lpMemory
(6) 调用CloseHandle来关闭内存映射文件,传入参数为hFileMap
(7) 调用CloseHandle来关闭文件,传入参数为hFile
例程: …………….

3使用内存映射文件在进程间共享数据
进程间共享数据的步骤如下:
(1) 调用OpenFileMapping打开一个命名的内存映射文件对象,得到hFileMap,打开成功跳到(3),否则表示此程式是第一个副本,继续执行步骤(2)
(2) 调用CreateFileMapping函数创建一个命名的内存映射对象,得到hFileMap
(3) 调用MapViewOfFile函数映射对象的一个视图,得到lpMemory
(4) 用该指针来读写共享的内存区域.
(5) 调用UnmapViewOfFile来解锁视图映射,传入参数为lpMemory
(6) 调用CloseHandle来关闭内存映射文件,传入参数为hFileMap
例程: …………….

驱动器和目录 — 目录操作

1.创建和删除目录
创建目录使用CreateDirectory函数,例如:

szDir db 'c:dir1dir2',0

invoke CreateDirectory,addr szDir,NULL

如果创建成功返回TRUE,失败返回FALSE
注意:创建目录的上层目录必须存在,创建目录名不能与同目录下的目录或文件同名

删除目录使用RemoveDirectory函数

szDir db 'c:dir1dir2',0

invoke RemoveDirectory,addr szDir

如删除成功返回TRUE,否则返回FALSE
注意:被删除的是参数中指出的最后一级目录,删除目录必须是一个空目录,删除的文件不会进入回收站

2.一些特殊目录
当前目录:所有未指定路径的文件名均默认使用这个目录
Windows目录:Windows操作系统的安装目录
系统目录:Windows安装目录下存放系统文件的目录(9X下是system,NT下是system32)
临时目录:存放临时文件的目录,系统可以在磁盘空间不足的时候自动删除里面的文件.
Win32中专门设置了几个函数来获取这些目录的位置

invoke GetCurrentDirectory,dwBufferSize,lpBuffer ;获取当前目录
invoke GetTempPath,dwBufferSize,lpBuffer ;获取临时目录
invoke GetWindowsDirectory,lpBuffer,dwBufferSize ;获取Windows目录
invoke GetSystemDirectory,lpBuffer,dwBufferSize ;获取系统目录

lpBuffer:指向一个缓冲区,用来接收返回的路径字符串
dwBufferSize:指出了缓冲区的大小,一般设置为MAX_PATH
注意:四个函数的参数顺序,GetTempPath返回值包括'' 而其它三个没有,当程序运行的时候,默认的当前路径是执行程序所在目录,但不是绝对的,比如使用GetOpenFileName等函数,会设置当前目录为指定的目录

修改当前路径用SetCurrentDirectory

szDir db 'c:dir1dir2',0

invoke SetCurrentDirectory,addr szDir

驱动器和目录 — 逻辑驱动器操作

1.卷标操作
驱动器创建,修改,删除卷标都可以使用SetVolumeLabel函数

szPath db 'c:',0
szVolume db 'System',0
invoke SetVolumeLabel,addr szPath,szVolume

szPath:指出了要设置卷标的逻辑驱动器的根目录
szVolume:指向包含卷标字符串的缓冲区
删除卷标的二种方法

szPath db 'c:',0
szVolume db 0
invoke SetVolumeLabel,addr szPath,szVolume

szPath db 'c:',0
invoke SetVolumeLabel,addr szPath,NULL

如果函数执行成功返回值是TRUE,否则返回FALSE

2.逻辑驱动器的检测
检测系统中当前存在多少个逻辑驱动器可以使用GetLogicalDrives函数,它没有输入参数,它返回一个32位整数,用其中的每一位代表是否存在一个逻辑驱动器.由于系统中可用的盘符公有26个(A~Z),所以用第0到第25位表示A:~Z:

如果认为认为上面的函数做位测试比较麻烦也可以使用GetLogicalDriveStrings,这个函数返回字符串类型的逻辑驱动器列表:

invoke GetLogicalDriverStrings,dwBufferSize,lpBuffer

lpBuffer:指向一个缓冲区,函数在这里返回'A:',0,'B:',0 格式的字符串
dwBufferSize:指出缓存区的大小,如果缓冲区不够大,后面的数据会被截尾

检测驱动器类型的工作可以用GetDriveType函数来完成

szPath db 'c:',0
invoke GetDriveType,addr szPath

szPath指向存放在逻辑驱动器根目录的字符串的缓冲区,函数返回值是驱动器的类型,是下面7个位的一种
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位数,它保存在位于驱动器第一个扇区的引导记录中.
lpMaximumComponentLength:指向一个双字变量,在这里返回最大允许的文件名长度,windows中为255
lpFileSystemFlags:指向一个双字变量,在这里返回一些逻辑驱动器的属性标志返回值可能是下列值的组合
FS_CASE_IS_PRESERVED:文件系统保存文件名时保持它的大小写
FS_CASE_SENSITIVE:支持区分大小写的文件名
FS_UNICODE_STORED_ON_DISK:允许存放Unicode格式的文件名
FS_PERSISTENT_ACLS:支持ACL
FS_FILE_COMPRESSION:支持文件压缩
FS_VOL_IS_COMPRESSED:支持卷压缩
lpFileSystemNameBuffer:指向一个字符串缓冲区,用来接收文件系统字符串,类似于'NTFS'或'FAT32'之类的dwFileSystemNameSize指定了这个缓冲区的长度

检测逻辑驱动器剩余空间GetDiskFreeSpace用法如下

invoke GetDiskFreeSpace,lpRootPathName,lpSectorsPerCluster,lpBytesPerSector,lpNumberOfFreeClusters,lpTotalNumberOfClusters

lpRootPathName:指向驱动器根目录字符串
lpSectorsPerCluster:返回每簇的扇区数
lpBytesPerSector:返回每扇区的字节数
lpNumberOfFreeClusters:返回驱动器中未使用的簇的数量
lpTotalNumberOfClusters:返回驱动器中簇的总数

Windows 文件操作 — 其它文件操作

1.拷贝文件
拷贝文使用CopyFile或CopyFileEx

invoke CopyFile,lpExistingFileName,lpNewFileName,bFailIfExists

函数将lpExistingFileName指定文件拷贝为lpNewFileName指定的文件
bFailIfExists指定目标存在时的动作,指定为TRUE,拷贝失败;指定为FALSE则覆盖掉原来的文件,拷贝出来的新文件的属性和原来文件的属性一样
CopyFileEx函数可以完成同样的功能,只不过函数可以指定一个回调函数.

2.移动文件
移动文件使用MoveFile或MoveFileEx

invoke MoveFile,lpExistingFileName,lpNewFileName

将lpExistingFileName指定的文件移动到lpNewFileName指定的目标位置,文件名可以同时改变或不改变,目标文件必须不存在,否则函数调用失败.当函数执行成功的时候返回非0值,否则函数返回0
注意:MoveFile函数可以移动文件或目录.当移动一个文件时,源文件和目标文件可以处于不同的驱动器上
当移动对象是一个文件夹时,源目录与目标目录必须在一个驱动器上

invoke MoveFileEx,lpExistingFileName,lpNewFileName,dwFlags

MoveFileEx函数增加了一个dwFlags参数来时行移动控制,参数可以是下面取值的组合
MOVEFILE_COPY_ALLOWED:允许拷贝数据,如果不指定,文件不能移动到不同的驱动器上,不能与REBOOT同时使用
MOVEFILE_DELAY_UNTIL_REBOOT:在Winnt上执行时,函数在下一次启动时再进行移动操作
MOVEFILE_REPLACE_EXISTING:如果目标存在,将它替换掉(与MoveFile相比的优点)
MoveFileEx还有个特殊用法

invoke MoveFileEx,lpExistingFileName,NULL,MOVEFILE_DELAY_UNTIL_REBOOT

将在下一次启动时将lpExistingFileName指定的文件删除(Win95不支持)

3.删除文件
删除文件使用DeleteFile函数

invoke DeleteFile,lpFileName

lpFileName指向一个包含要删除文件名的字符串.在Win95下执行时,可以删除打开状态的文件,在NT下执行,不能对一个打开的文件进行删除.

Windows 文件操作 — 文件属性

1.Win32的文件函数可以操作多种对象,用GetFileType函数可以得到操作对象的类型.

invoke GetFileType,hFile

该函数返回值有4种
FILE_TYPE_UNKNOWN 文件类型未知
FILE_TYPE_DISK 磁盘文件
FILE_TYPE_CHAR 字符设备
FILE_TYPE_PIPE 管道

2.获取文件长度
使用GetFileSize函数

invoke GetFileSize,hFile,lpFileSizeHigh

lpFileSizeHigh指向一个用来接收高32位长度的变量,一般设置为NULL,长度的低32位在函数的返回值中返回,GetFileSize返回的是当前长度

3.获取和修改文件日期
获取文件日期使用GetFileTime

invoke GetFileTime,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime

hFile:操作文件句柄
lpCreationTime:创建日期
lpLastAccessTime:最后存取日期
lpLastWriteTime:最后写入日期
如果不需要某个日期可将它设置为NULL
返回的日期是个FILETIME 结构

FILETIME STRUCT
dwLowDateTime DWORD ? ;文件日期低32位
dwHighDateTime DWORD ? ;文件日期高32位
FILETIME ENDS

这个结构中无法直接得到日期的年月日时分秒等数据.转换FILETIME为SYSTEMTIME结构,使用FileTimeToSystemTime进行转换

invoke FileTimeToSystemTime,lpFileTime,lpSystemTime

设置日期

invoke SetFileTime,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime

填写FILETIME结构的时候,最简便的方法

invoke SystemTimeToFileTime,lpSystemTime,lpFileTime

4.获取和修改文件属性
创建文件是,可以在CreateFile的dwFlagsAndAttributes参数指定,也可以在以后用SetFileAttributes修改属性

invoke SetFileAttributes,lpFileName,dwFileAttributes

调用SetFileAttributes不需要打开文件上,只要指定全路径的文件名就可以了
dwFileAttributes与dwFlagsAndAttributes的参数是一样的

获取文件的只读,隐含与系统等属性,可以使用GetFileAttributes

invoke GetFileAttributes,lpFimeName

如果函数执行失败返回-1 成功返回文件的属性

Windows 文件操作 — 查找文件

开始查找文件,首先使用FindFirstFile函数,如果函数执行成功,返回一个句柄hFindFile来对应这个寻找操作,接下来可以利用这个句柄循环调用FindNextFile继续查找其它文件,直到FindNextFile返回失败为止.最后关闭hFindFile句柄.一般查找文件的代码结构:

invoke FindFirstFile,lpFindFile,lpFindFileDate
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.repeat
;处理本次找到的文件
invoke FindNextFile,hFindFile,addr lpFindFileData
.until eax==FALSE
invoke FindClose,hFindFile
.endif

FindFirstFile的参数lpFindFile指向一个字符串,代表要寻找的文件名,如果文件名中不锯含路径,将在当前目录中查找文件.在文件名中可以包含'*'或'?'通配符
FindFirstFile函数和FindNextFile函数中的lpFindFileData参数则指向一个缓冲区,函数会在缓冲区中返回一个WIN_FIND_DATA结构,结构中包括了Windows查找过程中临时使用的数据和找到的文件名与属性等数据,该结构定义如下:

WIN32_FIND_DATA STRUCT
dwFileAttributes DWORD ? ;文件属性
ftCreationTime FILETIME <> ;文件的创建日期
ftLastAccessTime FILETIME <> ;文件的最后存取日期
ftlastWriteTime FILETIME <> ;文件的最后修改日期
nFileSizeHigh DWORD ? ;文件长度的高32位
nFileSizeLow DWORD ? ;文件长度的低32位
dwReserved0 DWORD ? ;内部使用
dwReserved1 DWORD ? ;内部使用
cFileName BYTE MAX_PATH dup(?) ;本次找到的文件名
cAlternate BYTE 14 dup(?) ;文件的8.3结构的短文件名
WIN32_FIND_DATA ENDS

dwFileAttributes字段可以是下面取值的组合,通过它可以检查找到的是一个文件还是一个子目录,以及属性
FILE_ATTRIBUTE_ARCHIVE:文件包含归档属性
FILE_ATTRIBUTE_COMPRESSED:文件和目录被压缩
FILE_ATTRIBUTE_DIRECTORY:找到的是一个目录
FILE_ATTRIBUTE_HIDDEN:文件包含隐含属性
FILE_ATTRIBUTE_NORMAL:文件没有其它属性
FILE_ATTRIBUTE_READONLY:文件包含只读属性
FILE_ATTRIBUTE_SYSTEM:文件包含系统属性
FILE_ATTRIBUTE_TEMPORARY:文件是一个临时文件
注意:cFileName字段中包括了找到的文件名,这个文件名中并不包含路径.

Windows 文件操作 — 创建和读写

1 打开和关闭文件
打开文件使用CreateFile 用法如下

invoke CreateFile,lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile

各参数含义如下:
lpFileName:指向存放有文件名的缓冲区,文件名是以0结尾的字符串,字符最大长度为MAX_PATH(windows.inc中为260),可以打开多种对象,包括:控制台(Consoles),通信设备(Communications resources)-包括串口等,目录(Directories)和文件(Files),邮件槽(Mailslots),管道(Pipes)

dwDesiredAccess参数是存取方式,可以取的值有两个
GENERIC_READ 表示读取文件数据
GENERIC_WRITE 表示写数据
如果要读写数据,要同时指定这两个标志

dwShareMode参数是共享属性,表明文件被打开后是否允许其它进程再次打开文件, 可以取的值有四个
0:不允许文件再被打开
FILE_SHARE_DELETE:允许其它进程同时对文件进行删除
FILE_SHARE_READ:允许其它进程以读方式打开文件
FILE_SHARE_WRITE:允许其它进程同时以写方式打开文件

lpSecurityAttributes参数为安全属性,指定文件句柄是否可以被子进程继承,为NULL表明无法被继承,否则要将参数指向一个SECURITY_ATTRIBUTES结构,该结构定义如下

SECURITY_ATTRIBUTES STRUCT
nLength DWORD ? ;本结构的长度
lpSectrityDescriptor DWORD ?
bInheritHandle DWORD ? ;是否允许继承
SECURITY_ATTRIBUTES ENDS

将nLength设置为结构的长度,将bInheritHandle设置为TRUE就可以使句柄能够被子进程继承

dwCreationDisposition参数用来设置文件已经存在或不存在时系统采取的动作,在这里可以指定函数要执行的功能是创建还是打开.共有5个值:
CREATE_NEW:创建新文件,如果文件以存在函数会返回失败
CREATE_ALWAYS:创建新文件,如果文件以存在则清除原文件
OPEN_EXISTING:打开存在的文件,当文件不存在时函数返回失败
OPEN_ALWAYS:如果文件以存在,则打开,不存在则创建新文件
TRUNCATE_EXISTING:打开文件并将文件截断为零,当文件不存在时,返回失败

dwFlagsAndAttributes参数用来指定新建文件的属性,可以有10个值
FILE_ATTRIBUTE_NORMAL:普通文件,设置这个属性时其他属性都不会生效
FILE_ATTRIBUTE_ARCHIVE:设置归档属性
FILE_ATTRIBUTE_HIDDEN:设置隐藏属性
FILE_ATTRIBUTE_READONLY:设置只读属性
FILE_ATTRIBUTE_SYSTEM:设置系统属性
FILE_ATTRIBUTE_TEMPORARY:临时文件,系统会尽量把文件内容保持在内存中,以加快存取速度,程序在不使用它时会尽快删除它
此外还可以指定对文件操作的方式
FILE_FLAG_WRITE_THROUGH:使用WriteThrough模式,系统不会对文件使用缓存.
FILE_FLAG_OVERLAPPED:使用异步文件操作模式
FILE_FLAG_DELETE_ON_CLOSE:文件被关闭后立即被系统自动删除
FILE_FLAG_RANDOM_ACCESS:对文件进行随机读写操作

hTemplateFile:指定了一个文件模板的句柄,该文件模板的所有属性都会被复制到当前创新的文件中.win95不支持本参数,建议在参数中使用NULL.当打开或创建文件成功的时候函数返回一个文件句柄,失败返回INVALID_HANDLE_VALUE,这个值是-1而不是NULL

关闭文件用

invoke CloseHandle,hFile

2移动文件指针
调整文件指针使用SetFilePointer函数

invoke SetFilePointer,hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod

hFile:是CreateFile返回的文件句柄
lDistanceToMove:指定要移动的距离.
ldistanceToMoveHigh:是一个指针指向一个32位变量存放移动距离的高32位,他与lDistanceToMove组成一个64位地址,但在X86平台上的windows版本中,文件长度不会超过4G,所以一般设置为NULL
dwMoveMethod指定了移动模式,有3个值
FILE_GEGIN:总是从文件头部开始移动
FILE_CURRENT:从当前的文件指针处开始移动
FILE_END:从文件尾开始移动
当lDistanceToMoveHigh=NULL时,如果函数执行失败返回值是-1,否则返回新的文件指针

可以使用以下代码获得当前指针的位置

invoke SetFilePointer,hFile,0,NULL,FILE_CURRENT

SetEndOfFile设置文件长度

invoke SetEndOfFile,hFile

3读写文件
读写文件可以使用ReadFile/WriteFile,这两个函数读写方式可以是同步或异步
也可以用ReadFileEx/WriteFileEx,这两个函数只用于异步读写

ReadFile用法

invoke ReadFile,hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped

hFile是文件句柄
lpBuffer指向一个缓冲区,函数会将读出的数据传送到这里
nNumberOfBytesToRead指定需要读入的字节数
lpNumberOfBytesRead指向一个dword变量,函数将在这里返回实际读入的字节数
lpOverlapped参数指向一个OVERLAPPED结构,供函数在异步读取文件时使用,同步读写中为NULL
读取文件失败,则返回0,成功则函数返回非0值
例:

invoke ReadFile,@hFile,addr @szReadBuffer,sizeof @szReadBuffer,addr @dwBytesRead,0

读出的字节数保存在@dwBytesRead中.

WriteFile用法

invoke WriteFile,hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWriten,lpOverlapped

hFile:文件句柄
lpBuffer:指向一个缓冲区,当中包含有要写入的文件数据
nNumberOfBytesToWrite:指定要写入的字节数
lpNumberOfBytesWriten:函数在这里返回成功写入的字节数
lpOverlapped:异步结构,同步时为NULL
写入文件时可能会由于多种原因使数据丢失
可以使用FlushFileBuffers函数来清空数据缓冲区

invoke FlushFileBuffers,hFile

总之如果这个函数执行成功的话,就能够保证所有的数据以经被传送.如果成执行成功返回值是非0值,失败返回0

4文件的共享
加锁可以防止其他进程对该区域进行读取或写入操作,加锁与解锁使用LockFile与UnlockFile也可以使用LockFileEx与UnlockFileEx,这两个函数使用异步方式执行.

invoke LockFile,hFile,dwFileOffsetLow,dwFileOffsetHigh,nNumberOfBytesToLockLow,nNumberOfBytesToLockHigh
invoke UnlockFile,hFile,dwFileOffsetLow,dwFileOffsetHigh,nNumberOfBytesToLockLow,nNumberOfBytesToLockHigh

dwFileOffsetLow和dwFileOffsetHigh参数组合起来指定了加锁区域的开始位置
dwNumberOfBytesToLockLow和dwNumberOfBytesToLockHigh组合指定加锁区域的大小,windows中,可以只使用低32位
注意:不能对一个区域重复加锁,两个不同的加锁区域也不能重叠,在对文件加锁与解锁操作的区域也必须一一对应,必须一次全部解锁,不能分次解锁.当程序读取一个可能被其它时程加锁的程序时,如果读取失败,必须调用GetLastError来获取失败原因,如果是因为锁定造成的,那可以等待一段时间后继续读取.

关于组播的特殊地址

224.0.0.0 - Base address
224.0.0.1 - 网段中所有支持多播的主机
224.0.0.2 - 网段中所有支持多播的路由器
224.0.0.4 - 网段中所有的DVMRP路由器
224.0.0.5 - 所有的OSPF路由器
224.0.0.6 - 所有的OSPF指派路由器
224.0.0.7 - 所有的ST路由器
224.0.0.8 - 所有的ST主机
224.0.0.9 - 所有RIPv2路由器
224.0.0.10 - 网段中所有支的路由器
224.0.0.11 - Mobile-Agents
224.0.0.12 - DHCP server / relay agent.
224.0.0.13 - 所有的PIM路由器
224.0.0.22 - 所有的IGMP路由器
224.0.0.251 - 所有的支持组播的DNS服务器

IP地址与子网掩码

2、网络号
3、主机号
4、广播地址
5、可用IP地址范围 首先,不要管这个IP是A类还是B类还是C类,IP是哪一类对于解题是没有任何意义的. 1、明确“子网”的函义:
子网就是把一个大网划分为几个小网,每个小网的IP地址数目都是一样多的。这个小网就叫做这个大网的子网。大网可以是A类大网,也可以是B类大网,还可能是C类大网。
A类大网中容纳了2的24次方个IP地址,即16777216个IP地址;B类大网中容纳着2的16次方个IP地址,即65536个IP地址;C类大网中容纳着2的8次方个IP地址,即256个IP地址。
如果把B类大网划分为32个小网,那么每个小网的IP地址数目就是65536/32=2048;如果把C类大网划分为32个小网,那么每个小网的IP地址数目就是256/32=8。 2、明确“掩码”的函义:
掩码的作用就是用来告诉电脑把“大网”划分为多少个“小网”! 好多书上说,掩码是用来确定IP地址所在的网络号,用来判断另一个IP是不是与当前IP在同一个子网中。这也对,但是对于我们做题来说,意义不大。我们要明确:掩码的作用就是用来告诉电脑把“大网”划分为多少个“小网”! 掩码是用来确定子网数目的依据! 3、牢记各类网络的默认掩码
A类网络的默认掩码是255.0.0.0,换算成二进制就是 11111111.00000000.00000000.00000000;默认掩码意味着没有将A类大网再划分为若干个小网。掩码中的1表示网络号,24个0表示在网络号确定的情况下(用二进制表示的IP地址的左边8位固定不变),用24位二进制数来表示IP地址的主机号部分。(IP地址是由网络号+主机号两部分构成)
B类网络的默认掩码是255.255.0.0,换算成二进制就是 11111111.11111111.00000000.00000000;默认掩码意味着没有将B类大网再划分为若干个小网。16个0表示在网络号确定的情况下(用二进制表示的IP地址的左边16位固定不变)可以用16位二进制数来表示IP地址的主机号部分。(可以把B类默认掩码理解为是将A类大网划分为2的8次方(即256)个小网)
C类网络的默认掩码是255.255.255.0,换算成二进制就是 11111111.11111111.11111111.00000000;默认掩码意味着没有将C类大网再划分为若干个小网。这里的8个0表示在网络号确定的情况下(用二进制表示的IP地址的左边24位固定不变),可以用8位二进制数来表示IP地址的主机部分。(可以把C类默认掩码理解为是将A类大网划分为2的16次方(即65536)个小网,是将B类大网划分为2的8次方(即256)个小网) 4、关于正确有效的掩码:
正确有效的掩码应该满足一定的条件,即把十进制掩码换算成二进制后,掩码的左边部分一定要是全为1且中间不能有0出现。比方说将255.255.248.0转为二进制是 11111111.11111111.11111000.00000000,可以看到左边都是1,在1的中间没有0出现(0都在1的右边),这样就是一个有效的掩码。我们再来看254.255.248.0,转成二进制是 11111110.11111111.11111000.00000000,这不是一个正确有效的掩码,因为在1中间有一个0的存在。再来看255.255.249.0,转为二进制是11111111.11111111.11111001.00000000,这也不是一个正确有效的掩码,因为在1中间也有0的存在。 5、关于子网掩码的另类表示法:
有些题目中不是出现如255.255.248.0这样的子网掩码,而是出现 IP地址/数字 这样的形式,这里的/数字就是子网掩码的另类表示法。在做题时,我们要正确理解这种另类表示法。我们将255.255.248.0转为二进制的形式是 11111111.11111111.11111000.00000000,可以看到左边是有21个1,所以我们可以将255.255.248.0这个掩码表示为/21。反过来,当我们看到/21时,我们就把32位二进制的左边填上21个1,将这个32位二进制数每8位做为一节用句点隔开,再转换为十进制,就是255.255.248.0了。 6、网络中有两个IP地址不可用:
不管是A类还是B类还是C类网络,在不划分子网的情况下,都是有两个IP地址不可用的:网络号和广播地址。比如在一个没有划分子网的C类大网中用202.203.34.0来表示网络号,用202.203.34.255来表示广播地址,因为C类大网的IP地址有256个,现在减去这两个IP地址,那么可用的IP地址就只剩下256-2=254个了。如果把一个C类大网划分为4个子网,会增加多少个不可用的IP地址?可以这样想:在C类大网不划分子网时,有两个IP地址不可用;现在将C类大网划分为4个子网,那么每个子网中都有2个IP地址不可用,所以4个子网中就有8个IP地址不可用,用8个IP地址减去没划分子网时的那两个不可用的IP地址,得到结果为6个。所以在将C类大网划分为4个子网后,将会多出6个不可用的IP地址。 7、根据掩码来确定子网的数目
首先看给出的掩码是属于哪个默认掩码的“范围”内,这样我们就可以知道是对A类还是B类还是C类大网来划分子网。比方说202.117.12.36/30,我们先把/30这种另类的掩码表示法转换为我们习惯的表示法: 11111111.11111111.11111111.11111100,转为十进制是255.255.255.252。我们可以看到,这个掩码的左边三节与C类默认掩码相同,只有第四节与C类默认掩码不同,所以我们认为255.255.255.252这个掩码是在C类默认掩码的范围之内的,意味着我们将对C类网络进行子网划分。因为C类网络的默认掩码是255.255.255.0,将C类默认掩码转换为二进制是11111111.11111111.11111111.00000000,这里的8个0表示可以用8位二进制数来表示IP地址,也就是说C类大网中可有2的8次方个IP地址,也就是256个IP地址。这道题中的掩码的最后一节是252,转换为二进制是11111100,因为1表示网络号,所以111111就表示将C类大网划分为(111111)2进制个子网。将111111转换为十进制是64,所以就表示将C类大网划分为64个子网,每个子网的IP地址数目是256/64=4,去除子网中的第一个表示子网号的IP地址和最后一个表示广播地址的IP地址,子网中的可分配的IP地址数目就是子网中的总的IP地址数目再减去2,也就是4-2=2个。 8、综合实例:
已知172.31.128.255/18,试计算:
1、子网数目,
2、网络号,
3、主机号,
4、广播地址,
5、可分配IP的起止范围
解:
1、算子网数目
首先将/18换成为我们习惯的表示法:
11111111.11111111.11000000.000000转为十进制就是255.255.192.0,可以看到这个掩码的左边两节和B类默认掩码是一致的,所以这个掩码是在B类默认掩码的范围内,意味着我们将对B类大网进行子网划分。B类掩码默类是用16位(16个0)来表示可分配的IP地址,本题中的掩码在B类默认掩码的基础上多出了两个表示网络号的1,这就是说是将B类大网划分为(11)2进制个子网,将(11)2进制转换为十进制就是4,所以本题中是将B类大网划分为4个子网。 2、算网络号
用公式:将IP地址的二进制和子网掩码的二进制进行“与”(and)运算,得到的结果就是网络号。“与运算”的规则是1和1得1,0和1得0,1和0得0。
172.31.128.255转为二进制是10101100.00011111.10000000.11111111,掩码是:11111111.11111111.11000000.00000000
所以:
10101100.00011111.10000000.11111111
11111111.11111111.11000000.00000000
10101100.00011111.10000000.00000000
将10101100.00011111.10000000.00000000
转换为十进制就是172.31.128.0,所以网络号是172.31.128.0 3、算主机号
也用公式:用IP地址的二进]] >