最近在学习 Win32编程,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习Win32开发的童鞋们提供一份参考。
本系列博文均根据学习《WindowsAPI开发详解》一书总结而来;
运行环境:
操作系统: Windows 10家庭版
编译器:Visual Studio 2013
文件系统 文件系统是操作系统最重要的组成,支持操作系统运行的系统可执行文件本身也位于文件系统中。
文件系统概念 Windows操作系统的文件虽然具有FAT16、FAT32、NTFS等多种格式;
对文件系统进行开发时,所设计一些概念包括磁盘分区、卷、目录、文件对象、文件句柄、文件映射等。
磁盘分区
磁盘是装在计算机上的存储设备,硬盘就是常见的存储设备,可以对硬盘进行分为多个独立的逻辑驱动器
卷
卷也成为逻辑驱动器,一个磁盘分区最少拥有一个卷。卷也可以分为多个磁盘分区上;
Windows中文件命名标准
Windows系统中,文件命名格式为”主文件名 + 扩展名”
文件路径长度应限制再260个字符以内。
不允许使用特殊符号
磁盘和驱动器管理APIGetLogicalDrivers 获取主机中所有的逻辑驱动器,以Bit Map的形式返回. GetLogicalDriverString 获取主机中所有的逻辑驱动器,以驱动器根路径字符串返回. FindFirstVolume 查找主机中的第一个驱动器,返回查找句柄. FindNextVolume 根据FindFirstVolume返回句柄,查找主机中后继的逻辑驱动器 FindVolumeClose 关闭驱动器查找句柄 GetDriveType 获取驱动器类型 GetVolumeInformation 获取逻辑驱动器信息 FindFirstVolumeMountPoint 查找指定卷的第一个挂载点,返回查找句柄 FindNextVolumeMountPoint 根据FindFirstVolumeMountPoint返回的句柄,查找卷的后继挂载点. FindVolumeMountPointClose 关闭挂载点查找句柄 GetVolumeNameForVolumeMountPoint 根据指定挂载点获取相应的卷设备名 SetVolumeMountPoint 将指定卷挂载到指定挂载点处 GetDiskFreeSpace 获取磁盘空间信息,包括每簇的扇区数,每扇区的字节数,簇数量,空闲的簇数量 GetDiskFreeSpaceEx 获取用户可用的空闲空间的字节数,磁盘总容量的字节数
文件和目录管理API DeleteFile 删除参数所指定文件 CopyFile 复制指定文件为一个新文件 MoveFile 将指定文件或目录移动到指定位置 CreateFile 新建或打开一个文件,获取文件句柄 ReadFile 读取由文件句柄指定文件的内容 WriteFile 向由文件句柄指定的文件中写入内容 GetFileSize 获取文件大小,返回DWORD中;大小超出DWORD最大值时可指定高32位的DWORD联合存储 GetFileSizeEx 获取文件大小,存储到一个64位的大整数联合体中. CreateDirectory 创建一个目录 GetCurrentDirectory 获取当前程序所在目录 SetCurrentDirectory 设置当前程序所在目录 GetModuleFileName 获取当前模块全路径 FindFirstFile 查找指定目录下第一个文件句柄或目录,获得查找句柄 FindNextFile 根据FindFirstFile获得的句柄,循环查找文件或目录 GetFileAttributes 获取指定文件目录属性,返回一个DWORD值 GetFileAttributesEx 获取文件或目录属性,存储在WIN32_FILE_ATTRIBUTE_DATA结构体中 SetFileAttributes 将文件属性设定为指定值 FileTimeToLocalFileTime 将文件时间转换为本地时间 FileTimeToSystemTime 将文件转换为系统时间,SYSTEMTIME格式便于显示
高级文件操作 CreateFileMapping 创建文件的映射对象 MapViewOfFile 创建视图,将创建的文件映射对象映射到当前进程的地址空间中 FlushViewOfFile 将视图中的数据都写入磁盘,对视图的操作都会反映到磁盘上的文件中 OpenFileMapping 打开已经存在的命名的文件映射对象 UnmapViewOfFile 取消文件映射 GetMappedFileName 从映射对象获取被映射文件的文件设备名 QueryDosDevice 获取MS-DOS设备名
磁盘和驱动器
使用两种方法来遍历驱动器并获取驱动器属性。
使用API操作驱动器挂载点。
判断光驱中是否有光盘。
获取磁盘剩余空间、扇区信息等。
遍历卷获得属性 (1) GetLogicalDrives。 获取主机中所有的逻辑驱动器,以BitMap的形式返回,其函数原型如下:
(2) GetLogicalDriverStrings。 获取主机中所有驱动器,以驱动器根路径字符串返回,其函数原型如下:
(3)FindFirstVolume。 查找主机中的第一个驱动器,返回驱动器设备名,其函数原型如下:
(4)FindNextVolume 查找主机中后继的逻辑驱动器,其函数原型如下:
(5)FindVo1umeClose。 关闭FindFirstVolume打开的卷遍历句柄,其函数原型如下:
(6) GetDriveType。 获取驱动器类型,其函数原型如下:
(7) GetVolumeInformation。 获取逻辑驱动器信息,其函数原型如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 #include <windows.h> #include <stdlib.h> #include <stdio.h> #define BUFSIZE 1024 BOOL GetDirverInfo (LPSTR szDrive) ;void main (void ) { CHAR szLogicalDriveStrings[BUFSIZE]; PCHAR szDrive; ZeroMemory(szLogicalDriveStrings,BUFSIZE); GetLogicalDriveStrings(BUFSIZE - 1 ,szLogicalDriveStrings); szDrive = (PCHAR)szLogicalDriveStrings; do { if (!GetDirverInfo(szDrive)) { printf ("\nGet Volume Information Error: %d" , GetLastError()); } szDrive += (lstrlen(szDrive)+1 ); } while (*szDrive!='\x00' ); getchar(); } BOOL GetDirverInfo (LPSTR szDrive) { UINT uDriveType; DWORD dwVolumeSerialNumber; DWORD dwMaximumComponentLength; DWORD dwFileSystemFlags; TCHAR szFileSystemNameBuffer[BUFSIZE]; TCHAR szRootName[BUFSIZE]; printf ("\n%s\n" ,szDrive); uDriveType = GetDriveType(szDrive); switch (uDriveType) { case DRIVE_UNKNOWN: printf ("The drive type cannot be determined. " ); break ; case DRIVE_NO_ROOT_DIR: printf ("The root path is invalid, for example, no volume is mounted at the path. " ); break ; case DRIVE_REMOVABLE: printf ("The drive is a type that has removable media, for example, a floppy drive or removable hard disk. " ); break ; case DRIVE_FIXED: printf ("The drive is a type that cannot be removed, for example, a fixed hard drive. " ); break ; case DRIVE_REMOTE: printf ("The drive is a remote (network) drive. " ); break ; case DRIVE_CDROM: printf ("The drive is a CD-ROM drive. " ); break ; case DRIVE_RAMDISK: printf ("The drive is a RAM disk. " ); break ; default : break ; } if (!GetVolumeInformation( szDrive, szRootName, BUFSIZE, &dwVolumeSerialNumber, &dwMaximumComponentLength, &dwFileSystemFlags, szFileSystemNameBuffer, BUFSIZE )) { return FALSE; } printf ("\nVolume Serial Number is %u" ,dwVolumeSerialNumber); printf ("\nMaximum Component Length is %u" ,dwMaximumComponentLength); printf ("\nSystem Type is %s\n" ,szFileSystemNameBuffer); printf ("\RootName is %s\n" , szRootName); if (dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS) { printf ("The file system does not support volume mount points.\n" ); } if (dwFileSystemFlags & FILE_VOLUME_QUOTAS) { printf ("The file system supports disk quotas.\n" ); } if (dwFileSystemFlags & FILE_CASE_SENSITIVE_SEARCH) { printf ("The file system supports case-sensitive file names.\n" ); } printf ("...\n" ); return TRUE; }
使用FindFirstVolume遍历驱动器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #define BUFSIZE MAX_PATH BOOL GetDirverInfo (LPTSTR szDrive) ;int main (void ) { TCHAR buf[BUFSIZE]; HANDLE hVol; BOOL bFlag; hVol = FindFirstVolume(buf, BUFSIZE); if (hVol == INVALID_HANDLE_VALUE) { printf ("No volumes found!\n" ); return (-1 ); } GetDirverInfo(buf); while (FindNextVolume( hVol, buf, BUFSIZE )) { GetDirverInfo(buf); } bFlag = FindVolumeClose( hVol ); getchar(); return (bFlag); } BOOL GetDirverInfo (LPTSTR szDrive) { UINT uDriveType; DWORD dwVolumeSerialNumber; DWORD dwMaximumComponentLength; DWORD dwFileSystemFlags; TCHAR szFileSystemNameBuffer[BUFSIZE]; TCHAR szDirveName[MAX_PATH]; wprintf(TEXT("\n%s\n" ), szDrive); uDriveType = GetDriveType(szDrive); switch (uDriveType) { case DRIVE_UNKNOWN: printf ("The drive type cannot be determined. " ); break ; case DRIVE_NO_ROOT_DIR: printf ("The root path is invalid, for example, no volume is mounted at the path. " ); break ; case DRIVE_REMOVABLE: printf ("The drive is a type that has removable media, for example, a floppy drive or removable hard disk. " ); break ; case DRIVE_FIXED: printf ("The drive is a type that cannot be removed, for example, a fixed hard drive. " ); break ; case DRIVE_REMOTE: printf ("The drive is a remote (network) drive. " ); break ; case DRIVE_CDROM: printf ("The drive is a CD-ROM drive. " ); break ; case DRIVE_RAMDISK: printf ("The drive is a RAM disk. " ); break ; default : break ; } if (!GetVolumeInformation( szDrive, szDirveName, MAX_PATH, &dwVolumeSerialNumber, &dwMaximumComponentLength, &dwFileSystemFlags, szFileSystemNameBuffer, BUFSIZE )) { return FALSE; } if (0 != lstrlen(szDirveName)) { wprintf(TEXT("\nDrive Name is %s\n" ), szDirveName); } printf ("\nVolume Serial Number is %u" , dwVolumeSerialNumber); printf ("\nMaximum Component Length is %u" , dwMaximumComponentLength); printf ("\nSystem Type is %s\n" , szFileSystemNameBuffer); if (dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS) { printf ("The file system does not support volume mount points.\n" ); } if (dwFileSystemFlags & FILE_VOLUME_QUOTAS) { printf ("The file system supports disk quotas.\n" ); } if (dwFileSystemFlags & FILE_CASE_SENSITIVE_SEARCH) { printf ("The file system supports case-sensitive file names.\n" ); } printf ("...\n" ); return TRUE; }
操作驱动器挂载点 一般可以用FindFirstVolumeMountPoint系列的API来找到一个卷的所有挂载点;用GetVolumeNameForVolumeMountPoint来获取指定挂载点所指向的卷名,卷名形式为”//?/Volume{GUID}/”;用SetVolumeMountPoint来设置新的挂载点。
(1)FindFirstVolumeMountPoint. 获取指定卷的第一个挂载点,函数原型如下: 以用GetLastError()函数获取更详细的错误信息。 (2) FindNextVolumeMountPoint 查找指定卷的后继挂载点,函数原型如下:
(3)FindVolumeMountPointClose. 关闭FindVolumeMountPointClose打开的卷句柄,其函数原型如下: ◇参数 hFindVolumeMountPoint:要关闭的挂载点查找句柄。 ◇返回值 (4)GetVolumeNameForVolumeMountPoint。 根据指定的挂载点获取相应的卷设备名,函数原型如下:
(5)SetVolumeMountPc 将指定卷挂载到指定挂载点处,函数原型如下:
判断光驱 首先使用驱动器根路径作为GetDriveType和参数,如果返回值是DRIVE_CDROM,则说明此驱动器为光驱。然后使用GetVolumeInformation获取信息,如果成功,则说明存光盘已经放入。调用完成后GetVolumeInformation函数的第7个参数LPTSTR lpFileSystemNameBuffer存储的是文件系统的类别字符串,光盘一般是CDFS。如果调用GetVolumeInformation时返回FALSE,并且GetLastError返回21,则说明驱动器中未放入光盘。
1.关键API (1)GetDiskType与GetVolumeInformation。 这两个API已经在4.2.1小节介绍过,这里不再赘述。 (2)GetLastError。 获取在执行中本线程最近的一次错误。本函数是很多系统API返回执行错误原因的方法。可能使用SetLastError函数设置本线程的Last-Error值。GetLastError函数原型如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #include <tchar.h> #define BUFSIZE MAX_PATH #define FILESYSNAMEBUFSIZE MAX_PATH int main (int argc,TCHAR argv[]) { TCHAR szFileSystemNameBuffer[BUFSIZE]; DWORD dwLastError; DWORD dwFileSystemFlags; if (GetDriveType(TEXT("H:\\" )) != DRIVE_CDROM) { printf ("驱动器 %s 不是 CD/DVD ROM。\n" , argv[1 ]); return (-1 ); } if (!GetVolumeInformation( TEXT("H:\\" ), NULL , 0 , NULL , NULL , &dwFileSystemFlags, szFileSystemNameBuffer, BUFSIZE )) { dwLastError = GetLastError(); if (dwLastError == 21 ) { printf ("设备未就绪,请放入光盘!\n" ); return 0 ; } else { printf ("GetVolumeInformation 错误 %d\n" , dwLastError); return 0 ; } } printf ("光盘已经放入,文件系统类别 %ls。\n" , szFileSystemNameBuffer); getchar(); return 0 ; }
获取磁盘信息 获取磁盘分区的总容量和空闲空间的容量可以使用GetDiskFreeSpace函数或GetDiskFree SpaceEx函数。GetDiskFreeSpace使用DWORD类型作为输出参数,由于DWOR长度为32位,最大只能表示4GB,而一般的磁盘分区大小都大于4GB,所以,GetDiskFreeSpace并不直接返回磁盘的总容量和空闲空间的容量,而是使用总簇数、空闲的簇数、每簇的扇区数、每扇区的字节数来表示。用户在编程时,可以使用它们的乘积来获得最终结果。而GetDiskFreeSpaceEx使用ULARGE_INTEGER (DWORD64)类型的数据来存储磁盘空间总空间和剩余空间,所以可以直接获得结果。DWORD64可以表示约16777216TB的数据量(DWORD64最大可表示2Byte,lTB=2Byte,
(2)GetDiskFreeSpacEX。 获取驱动器根路径作为输入,获取用户可用的空闲空间的字节数、空闲空间的字节数、磁盘总容量的字节数;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <windows.h> #include <stdio.h> BOOL GetDiskSpaceInfo (LPCTSTR pszDrive) { DWORD64 qwFreeBytesToCaller, qwTotalBytes, qwFreeBytes; DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters; BOOL bResult; bResult = GetDiskFreeSpaceEx(pszDrive, (PULARGE_INTEGER)&qwFreeBytesToCaller, (PULARGE_INTEGER)&qwTotalBytes, (PULARGE_INTEGER)&qwFreeBytes); if (bResult) { printf ("使用GetDiskFreeSpaceEx获取磁盘空间信息\n" ); printf ("可获得的空闲空间(字节): \t%I64d\n" , qwFreeBytesToCaller); printf ("空闲空间(字节): \t\t%I64d\n" , qwFreeBytes); printf ("磁盘总容量(字节): \t\t%I64d\n" , qwTotalBytes); } bResult = GetDiskFreeSpace(pszDrive, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); if (bResult) { printf ("\n使用GetDiskFreeSpace获取磁盘空间信息\n" ); printf ("空闲的簇数量 : \t\t\t%d\n" , dwFreeClusters); printf ("总簇数量 : \t\t\t%d\n" , dwTotalClusters); printf ("每簇的扇区数量 : \t\t%d\n" , dwSectPerClust); printf ("每扇区的容量(字节): \t\t%d\n" , dwBytesPerSect); printf ("空闲空间(字节): \t\t%I64d\n" , (DWORD64)dwFreeClusters* (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect); printf ("磁盘总容量(字节): \t\t%I64d" , (DWORD64)dwTotalClusters* (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect); } return bResult; } int main (int argc, PCHAR argv[]) { GetDiskSpaceInfo(TEXT("C:\\" )); getchar(); return 0 ; }
文件和目录管理 文件操作 Windows系统为文件的删除、复制、重命名或移动文件提供了相应的API函数。删除文件使用DeleteFile函数;复制文件使用CopyFile函数;重命名文件和移动文件实际是一个操作,使用MoveFile函数。这几个函数的使用都非常简单,下面分别介绍。 1.关键API (1) DeleteFile。
DeleteFile的功能是删除文件。以文件路径作为输入,指向需要删除的文件。文件路径可以是类似于“c:/files/delete.txt”的绝对路径,也可以是类似于“./delete.txt”的相对路径,二相对于可执行文件所在的路径。
(2) CopyFile。 CopyFile的功能是复制文件。通过参数输入复制文件和源路径和目的路径,路径可以是绝对路径也可以是相对路径,还可以通过参数指明如果目的路径已经存在文件,是否覆盖。可以使用CopyFileEx函数进行更为高级的操作,比如在复制进行过程中取消复制等。CopyFileEx可以指定 一个回调函数来处理文件复制中所可能发生的各种情况。
MoveFile。 MoveFile的功能是移动、重命名文件和目录。通过参数输入源路径和目的路径,路径可以是绝对路径也可以是相对路径,如果目的路径的文件或目录已经存在,则返回失败。可以使用MoveFileEx函数来指定更多的选项,如果已经存在是否替换等。还可以使用MoveFileWithProgress指定一个回调函数来处理文件移动中所可能发生的各种情况。函数原型如下:
(4) CopyFileEx、MoveFileEx以及MoveFileWithProgreSS. 这3个API函数功能更丰富,但是限于篇幅这里不再做详细介绍,读者可以使用SDK文档学习它们的使用方法。
1 2 3 4 5 6 7 8 9 10 11 12 #include <windows.h> #include <stdio.h> #include <tchar.h> int main (int argc, PCHAR argv[]) { getchar(); return 0 ; }
创建文件 1.关键API (1)CreateFile CreateFile是文件操作中最主要的一个函数。几乎所有的文件操作都需要使用到文件句柄。而CreateFile函数为这些操作建立文件句柄。CreateFile函数定义如下:
(2)ReadFile。
ReadFile动能是从文件中读出数据。需要使用CreateFile所返回的文件句柄。函数原型如下:
(3)WriteFile。 WriteFile函数的功能是将数据写入到文件中,写入到文件指针所在的位置,写入操作完成后,文件指针会移动到写入的数据之后,函数原型如下:
(4)GetFileSize、GetFileSizeEX. GetFileSize、GetFileSizeEX的功能是一致的,都是获取文件大小,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <windows.h> #include <stdio.h> #include <tchar.h> int main (int argc, PCHAR argv[]) { const int BUFSIZE = 4096 ; char szFileBuffer[MAX_PATH]; char szFileBuffer_Read[MAX_PATH]; memcpy (szFileBuffer, "sYstemk1t" , 20 ); DWORD dwWriteSize = 0 ; HANDLE hFile = CreateFile(TEXT("1.txt" ), GENERIC_WRITE | GENERIC_READ, 0 , NULL , OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == NULL ) { printf ("CreateFile Error = %d\n" , GetLastError()); return FALSE; } BOOL bFile = WriteFile(hFile, szFileBuffer, 20 , &dwWriteSize, NULL ); if (!bFile) { printf ("WriteFile Error = %d\n" , GetLastError()); } FlushFileBuffers(hFile); LONG IDistance = 0 ; DWORD dwPtr = SetFilePointer(hFile, IDistance, NULL , FILE_BEGIN); if (dwPtr == INVALID_FILE_ATTRIBUTES) { printf ("WriteFile Error = %d\n" , GetLastError()); } DWORD dwReadSize = 0 ; bFile = ReadFile(hFile, szFileBuffer_Read, 20 , &dwReadSize, NULL ); if (!bFile) { printf ("WriteFile Error = %d\n" , GetLastError()); } printf ("Buffer = %s\n" , szFileBuffer_Read); CloseHandle(hFile); getchar(); return 0 ; }
创建目录 1. 关键API (1) Createdirectory 函数原型如下: ◇参数 lpPathName:输入参数,所要创建的目录名或路径。 lpSecurityAttributes:输入参数,设置为NULL。 ◇返回值 返回BOOL值,表示是否成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <windows.h> #include <stdio.h> #include <tchar.h> int main () { if (!CreateDirectory(TEXT("test" ), NULL )) { printf ("CrreateDirectory Error = %d\n" , GetLastError()); return FALSE; } if (!CreateDirectory(TEXT("D:\\Test" ), NULL )) { printf ("CrreateDirectory Error = %d\n" , GetLastError()); return FALSE; } getchar(); return 0 ; }
获取目录信息 用户可以使用 GetCurrentDirectory和SetCurrentDirectory获取程序的当前目录,获取模块的路径使用 GetModuleFileName,如果以NULL参数调用GetModuleFileName,将会返回当前模块的路径。如果在程序主模块(exe)中获取当前模块路径,便可以从当前模块的路径中提取出程序运行时所在的路径。 1.关键API (1)GetCurrentDirectory。 获取进程的当前目录,函数原型如下:
(2)SetCurrentDirectory。 设置进程的当前目录,函数原型如下:
(3)GetModuleFileName。 获取模块文件名,当第一个参数为NULL时获取当前模块路径,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 #include <windows.h> #include <stdio.h> int main (void ) { TCHAR szCurrentDirectory[MAX_PATH]; TCHAR szMoudlePath[MAX_PATH]; LPTSTR szKernel32 = TEXT("kernel32.dll" ); HMODULE hKernel32; DWORD dwCurDirPathLen; dwCurDirPathLen = GetCurrentDirectory(MAX_PATH, szCurrentDirectory); if (dwCurDirPathLen == 0 ) { printf ("获取当前目录错误。\n" ); return 0 ; } printf ("进程当前目录为 %ls \n" , szCurrentDirectory); lstrcpy(szCurrentDirectory, TEXT("D:\\" )); if (!SetCurrentDirectory(szCurrentDirectory)) { printf ("设置当前目录错误。\n" ); return 0 ; } printf ("已经设置当前目录为 %ls \n" , szCurrentDirectory); CreateDirectory(TEXT("current_dir" ), NULL ); dwCurDirPathLen = GetCurrentDirectory(MAX_PATH, szCurrentDirectory); if (dwCurDirPathLen == 0 ) { printf ("获取当前目录错误。\n" ); return 0 ; } printf ("GetCurrentDirectory获取当前目录为 %ls \n" , szCurrentDirectory); if (!GetModuleFileName(NULL , szMoudlePath, MAX_PATH)) { printf ("获取模块路径录错误。\n" ); return 0 ; } printf ("本模块路径 %ls \n" , szMoudlePath); hKernel32 = LoadLibrary(szKernel32); if (!GetModuleFileName(hKernel32, szMoudlePath, MAX_PATH)) { printf ("获取模块路径错误。\n" ); return 0 ; } printf ("kernel32模块路径 %ls \n" , szMoudlePath); return 0 ; }
遍历目录 Windows API中,有一组专门的函数和结构,用于遍历目录,它们是FindFirstFile函数、 FindNextFile函数和WIN32_FIND_DATA结构。使用FindFirstFile和FindNextFile函数并与do-while循环结合,可以完成遍历目录的任务 值得一提的是,FindFirstFile输入参数的路径需使用通配符,也就是用户可以根据一些条件来对查找的文件作简单的过滤。 1.关键API (1)FindFirstFile。 查找第一个目录或文件,获取查找句柄,函数原型如下:
(2)FindNextFile 对文件、文件夹进行循环查找,函数原型如下:
2.关键结构 WIN32_FIND_DATA结构用于表示找到的文件,结构中包括文件、目录的名字,创建、最后访问和最后写入时间,文件大小、文件属性等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 DWORD EnumerateFileInDrectory (LPTSTR szPath) { WIN32_FIND_DATA FindFileData; HANDLE hListFile; TCHAR szFilePath[MAX_PATH]; lstrcpy(szFilePath, szPath); lstrcat(szFilePath, TEXT("//*" )); hListFile = FindFirstFile(szFilePath, &FindFileData); if (hListFile == INVALID_HANDLE_VALUE) { printf ("错误:%d" , GetLastError()); return 1 ; } else { do { printf ("%ls/t/t" , FindFileData.cFileName); if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_ENCRYPTED) { printf ("<加密> " ); } if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) { printf ("<隐藏> " ); } if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { printf ("<DIR> " ); } printf ("\n" ); } while (FindNextFile(hListFile, &FindFileData)); } return 0 ; }
获取设置文件属性 为了获取文件属性,用户可以使用GetFileAttributes与GetFileAttributesEx函数。 GetFileAttributesEx函数除了返回文件属性外,还返回文件时间信息、文件大小等。 GetFileAttributesEx将返回结果保存在WIN32_FILE_ATTRIBUTE DATA结构中。 获取的文件时间是以FILETIME格式存在的,如果要正确显示,还需要对其时区进行调整,调整为本地时区,然后转换为系统时间格式,便于显示。 前面在获取文件大小时已经介绍,NTFS文件系统使用了64位数据来表示文件大小。因为32位的数据最多只能表示4GB的大小。Windows将其分为了高32位和低32位,两个都需要使用到,这一点尤其要在对大于4GB的文件操作时注意。 1.关键API (1)GetFileAttributeS。 获取文件或目录的属牲-函数原型如下:
(2)GetFileAttributesEx。 获取文件或目录的属性、时间、大小,以WIN32_FILE ATTRIBUTE_DATA结构的形式返回 结果,函数原型如下:
(3) SetFileAttributes. 设置文件或目录的属性,函数原型如下:
(4)FileTimeToLocalFileTime。 把文件时间转换为本地的文件时间,函数原型如下:
5)FileTimeToSystemTime 将文件时间转换为系统时间(SYSTEMTIME格式),便于显示,函数原型如下:
2.关键数据结构 (1) FILETIM。 此结构用最小的数据量表示的时间,但是不便于用户查看和显示。通过API获取的系统时间都是这种格式的。如果要使用显示,可以使用FileTimeToSystemTime转换为便于显示的SYSTEMTIME结构。
(2) SYSTEMTIME。 此结构使用了较为直观的方式表示时间。
(3) WIN32_FILE ATTRIBUTE_DATA。 GetFileAttributesEx使用这个结构表示返回结果,包括文件属性、文件创建时间、文件最后访问时间、文件最后写入时间和文件大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 #include <windows.h> #include <stdio.h> DWORD ShowFileTime (PFILETIME lptime) ;DWORD ShowFileSize (DWORD dwFileSizeHigh, DWORD dwFileSizeLow) ;DWORD ShowFileAttrInfo (DWORD dwAttribute) ;DWORD SetFileHiddenAndReadonly (LPTSTR szFileName) ;DWORD ShowFileAttributes (LPTSTR szPath) { WIN32_FILE_ATTRIBUTE_DATA wfad; printf ("文件:%s\n" , szPath); if (!GetFileAttributesEx(szPath, GetFileExInfoStandard, &wfad)) { printf ("获取文件属性错误:%d\n" , GetLastError()); return 1 ; } printf ("创建时间:\t" ); ShowFileTime(&(wfad.ftCreationTime)); printf ("最后访问时间:\t" ); ShowFileTime(&(wfad.ftLastAccessTime)); printf ("最后修改时间:\t" ); ShowFileTime(&(wfad.ftLastWriteTime)); ShowFileSize(wfad.nFileSizeHigh, wfad.nFileSizeLow); ShowFileAttrInfo(wfad.dwFileAttributes); return 0 ; } DWORD ShowFileAttrInfo (DWORD dwAttribute) { printf ("文件属性:\t" ); if (dwAttribute&FILE_ATTRIBUTE_ARCHIVE) printf ("<ARCHIVE> " ); if (dwAttribute&FILE_ATTRIBUTE_COMPRESSED) printf ("<压缩> " ); if (dwAttribute&FILE_ATTRIBUTE_DIRECTORY) printf ("<目录> " ); if (dwAttribute&FILE_ATTRIBUTE_ENCRYPTED) printf ("<加密> " ); if (dwAttribute&FILE_ATTRIBUTE_HIDDEN) printf ("<隐藏> " ); if (dwAttribute&FILE_ATTRIBUTE_NORMAL) printf ("<NORMAL> " ); if (dwAttribute&FILE_ATTRIBUTE_OFFLINE) printf ("<OFFLINE> " ); if (dwAttribute&FILE_ATTRIBUTE_READONLY) printf ("<只读> " ); if (dwAttribute&FILE_ATTRIBUTE_SPARSE_FILE) printf ("<SPARSE> " ); if (dwAttribute&FILE_ATTRIBUTE_SYSTEM) printf ("<系统文件> " ); if (dwAttribute&FILE_ATTRIBUTE_TEMPORARY) printf ("<临时文件> " ); printf ("\n" ); return 0 ; } DWORD ShowFileSize (DWORD dwFileSizeHigh, DWORD dwFileSizeLow) { ULONGLONG liFileSize; liFileSize = dwFileSizeHigh; liFileSize <<= sizeof (DWORD) * 8 ; liFileSize += dwFileSizeLow; printf ("文件大小:\t%I64u 字节\n" , liFileSize); return 0 ; } DWORD ShowFileTime (PFILETIME lptime) { FILETIME ftLocal; SYSTEMTIME st; FileTimeToLocalFileTime( lptime, &ftLocal ); FileTimeToSystemTime( &ftLocal, &st ); printf ("%4d年%.2d月%#02d日,%.2d:%.2d:%.2d\n" , st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); return 0 ; } DWORD SetFileHiddenAndReadonly (LPTSTR szFileName) { DWORD dwFileAttributes = GetFileAttributes(szFileName); dwFileAttributes |= FILE_ATTRIBUTE_READONLY; dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; if (SetFileAttributes(szFileName, dwFileAttributes)) { printf ("文件%s的隐藏和属性设置成功\n" , szFileName); } else { printf ("属性设置; %d\n" , GetLastError()); } return 0 ; } int main (int argc, LPTSTR argv[]) { if (argc != 3 ) { printf ("请输入参数\n" ); printf ("显示第一个参数指定文件的属性、时间、大小;\n" ); printf ("将第二个参数的属性设置为隐藏、只读。" ); return 1 ; } ShowFileAttributes((LPTSTR)argv[1 ]); SetFileHiddenAndReadonly(argv[2 ]); return 0 ; }
内存映射文件 文件映射( mapping)是一种在将文件内容映射到进程的虚拟地址空间的技术。视图(View)是一段虚拟地址空间,进程可以通过View来存取文件的内容,视图是一段内存,可以使用指针来操作视图。使用的文件映射之后,读写文件就如同对读写内存一样简单。在使用文件映射时需要创建映射对象,映射对象分为命名的和未命名的。映射对象还存取权限。 使用文件映射至少有3个好处,一是因为文件是存储于硬盘上的,而文件视图是一段内存,使用文件映射操作时更方便;二是效率更高;三是可以在不同的进程间共享数据。 文件映射依赖于系统虚拟内存管理的分页机制。 本节将演示如何使用文件映射,下一节将演示如何使用文件映射来进行内存共享。 1. 关键API (1)GetSystemInfo 获取系统信息 (2)CreateFileMapping。 创建mapping对象,函数原型如下
(3)MapViewOfFile。 创建视图,将文件mapping映射到当前进程内存虚拟地址空间。函数原型如下:
(4)FlushViewOfFile。 将视图中的文件数据写入到磁盘上。调用此参数后,对映射视图的内存操作将会及时反映到硬件中的文件。函数原型如下:
◇使用说明 如果不调用此函数,数据最终也会写回到硬盘,调用此函数后,数据会立刻写回到硬盘。 (5) FillMemory、CopyMemory。内存操作函数,分别为填充内存和复制内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 #include <Windows.h> #include <tchar.h> #include <stdio.h> #define BUFFSIZE 1024 #define FILE_MAP_START 0x28804 LPTSTR lpcTheFile = TEXT("test.dat" ); int main () { HANDLE hFileMap; HANDLE hFile; DWORD dwByteWritten; DWORD dwFileSize; DWORD dwFileMapSize; DWORD dwMapViewSize; DWORD dwFileMapStart; DWORD dwSysGran; SYSTEM_INFO SysInfo; LPVOID lpMapAddress; PCHAR pData; INT i; INT iData; INT iViewDelta; BYTE cMapBuffer[32 ]; hFile = CreateFile(lpcTheFile, GENERIC_READ | GENERIC_WRITE, 0 , NULL , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf ("CreateFile Error : %d\n" , GetLastError()); return FALSE; } for (size_t i = 0 ; i < 65535 ; i++) { WriteFile(hFile, &i, sizeof (i), &dwByteWritten, NULL ); } dwFileSize = GetFileSize(hFile, NULL ); printf ("文件大小%d:\n" , dwFileSize); GetSystemInfo(&SysInfo); dwSysGran = SysInfo.dwAllocationGranularity; dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran; dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE; dwFileMapSize = FILE_MAP_START + BUFFSIZE; iViewDelta = FILE_MAP_START - dwFileMapStart; hFileMap = CreateFileMapping(hFile, NULL , PAGE_READWRITE, 0 , dwFileMapSize, NULL ); if (hFileMap == NULL ) { printf ("CreateFileMapping error: %d\n" , GetLastError()); return 1 ; } lpMapAddress = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0 , dwFileMapStart, dwMapViewSize); if (lpMapAddress == NULL ) { printf ("MapViewOfFile error: %d\n" , GetLastError()); return 1 ; } printf ("文件map view相对于文件的起始位置: 0x%x\n" , dwFileMapStart); printf ("文件map view的大小:0x%x\n" , dwMapViewSize); printf ("文件mapping对象的大小:0x%x\n" , dwFileMapSize); printf ("从相对于map view 0x%x 字节的位置读取数据," , iViewDelta); pData = (PCHAR)lpMapAddress + iViewDelta; iData = *(PINT)pData; printf ("为:0x%.8x\n" , iData); CopyMemory(cMapBuffer, lpMapAddress, 32 ); printf ("lpMapAddress起始的32字节是:" ); for (i = 0 ; i<32 ; i++) { printf ("0x%.2x " , cMapBuffer[i]); } FillMemory(lpMapAddress, 32 , (BYTE)0xff ); FlushViewOfFile(lpMapAddress, dwMapViewSize); printf ("\n已经将lpMapAddress开始的32字节使用0xff填充。\n" ); if (!CloseHandle(hFileMap)) { printf ("\nclosing the mapping object error %d!" , GetLastError()); } if (!CloseHandle(hFile)) { printf ("\nError %ld occurred closing the file!" , GetLastError()); } getchar(); return 0 ; }