win32第十五天

本文介绍了Windows API中的文件属性设置,包括如何使用SetFileAttributes和GetFileAttributes函数;接着讲解了文件遍历APIs如FindFirstFile和FindNextFile。此外,深入探讨了Windows内存管理,包括地址空间、虚拟内存、堆内存和栈内存的分配与释放。最后提到了内存映射文件在进程通信中的应用和句柄的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、文件属性APIs
BOOL SetFileAttributes (
  LPCTSTR lpFileName,       // 目录/文件路径
  DWORD dwFileAttributes // 目录/文件属性
);
成功返回TRUE,失败返回FALSE。
dwFileAttributes为以下值的位或:
FILE_ATTRIBUTE_ARCHIVE - 归档
FILE_ATTRIBUTE_COMPRESSED  - 压缩
FILE_ATTRIBUTE_OFFLINE - 离线
FILE_ATTRIBUTE_DIRECTORY - 目录
FILE_ATTRIBUTE_ENCRYPTED - 加密
FILE_ATTRIBUTE_HIDDEN - 隐藏
FILE_ATTRIBUTE_READONLY - 只读
FILE_ATTRIBUTE_SYSTEM - 系统
FILE_ATTRIBUTE_TEMPORARY - 临时
DWORD GetFileAttributes (
  LPCTSTR lpFileName  // 目录/文件路径
);
成功返回目录或文件的属性,失败返回-1。
FILE_ATTRIBUTE_ARCHIVE         00000001
FILE_ATTRIBUTE_COMPRESSED 00000010
FILE_ATTRIBUTE_OFFLINE          00000100
                                                  00000111
                                               &11111011
                                               ------------
                                                  00000011
增加文件属性:获取原属性,与需要增加的属性做位或,再设回去。
删除文件属性:获取原属性,与需要删除的属性之反做位与,再设回去。
二、文件遍历APIs
HANDLE FindFirstFile (
  LPCTSTR                     lpFileName,     // 查找路径
  LPWIN32_FIND_DATA lpFindFileData // 查找信息结构
);
成功返回查找句柄,用于后续函数调用,失败返回INVALID_HANDLE_VALUE。
BOOL FindNextFile (
  HANDLE                      hFindFile,        // 由FindFirstFile返回查找句柄
  LPWIN32_FIND_DATA lpFindFileData // 查找信息结构
);
成功返回TRUE,失败返回FALSE,GetLastError()返回ERROR_NO_MORE_FILES表示遍历结束。
三、Windows内存空间
1.地址空间:32操作系统地址空间0-2^32(4G)。地址空间越大程序越易于编写。
2.地址空间的划分:
1)用户地址空间:0-2G
A.空指针区:0-64K
B.用于区:64K-0x7FFEFFFF,存放用户程序的代码和数据
C.禁入区:0x7FFEFFFF-2G
2)内核地址空间:2G-4G
3.区域:连续的内存,区域大小一般是64K或64K的整数倍。每个区域都有一个特定的状态。
1)空闲:未被使用
2)私有:已被预订
3)映像:存放代码
4)映射:存放数据
4.物理内存(半导体内存,内存条)
系统实际可以使用的内存,CPU只能访问物理内存。
5.虚拟内存(磁盘交换文件)
将磁盘文件(pagefile.sys)虚拟成内存使用。CPU如果要访问虚拟内存,必须将虚拟内存中的数据放到物理内存中。经常使用的数据存放在物理内存中,不经常使用的数据存放在虚拟内存中。
6.内存页
系统进行内存管理的最小单位,内存页的大小4K字节,每个内存页都有特定的权限。
7.页目表
32位地址:
31              22 21             12 11                    0
XXXXXXXXXX XXXXXXXXXX XXXXXXXXXXXX
       10位                10位                  12位
     2^10=1K        2^10=1K          2^12=4K
页目中包含1K  页表中包含1K   页中包含4K个
个页表            个页                 字节
页目中包含1K项,每项对应一个页表,页表包含1K项,每项对应一个页,页包含4K字节——1K*1K*4K=4G。
8.内存访问的过程
1)CPU首先根据地址在物理内存中查找相应的位置。如果找到,则访问其中的数据,否则执行2);
2)根据地址在虚拟内存中查找相应的位置,如果没找到(野指针),则返回错误,否则执行3);
3)将该地址所在的内存页换入物理内存,同时将原物理内存页换出到虚拟内存,执行4);
4)访问物理内存中的数据。
9.内存的分配方式
1)虚拟内存分配:专有APIs
2)堆内存分配:malloc/new
3)栈内存分配:自动完成
四、虚拟内存分配
1.特点:速度快,分配大内存效率高,将内存的分配和地址的分配分开进行,可以先分配地址,直到需要时再将地址绑定(提交)到内存。常用于大型电子表格类应用程序的实现。
2.分配虚拟内存
LPVOID VirtualAlloc (
  LPVOID  lpAddress,           // NULL或者绑定(提交)地址
  SIZE_T    dwSize,                // 内存大小
  DWORD flAllocationType,  // 分配方式
  DWORD flProtect               // 访问方式,一般PAGE_READWRITE
);
成功返回虚拟内存地址,失败返回NULL。
flAllocationType取值:
MEM_COMMIT - 在分配地址的同时分配内存,如买现房
MEM_RESERVE - 只分配地址不绑定到内存,如买期房
获取内存状态:
void GlobalMemoryStatus (
  LPMEMORYSTATUS lpBuffer // 内存状态结构
);
typedef struct _MEMORYSTATUS {
  DWORD dwLength;           // 结构体字节数
  DWORD dwMemroyLoad; // 内存使用率,百分之几
  SIZE_T    dwTotalPhys;       // 物理内存总字节数
  SIZE_T    dwAvailPhys;       // 空闲物理内存字节数
  SIZE_T    dwTotalPageFile; // 分页文件总字节数
  SIZE_T    dwAvailPageFile; // 空闲分页文件字节数
  SIZE_T    dwTotalVirtual;   // 虚拟内存总字节数
  SIZE_T    dwAvailVirtual;    // 空闲虚拟内存字节数
} MEMORYSTATUS, *LPMEMORYSTATUS;
3.释放虚拟内存
BOOL VirtualFree (
  LPVOID  lpAddress,   // 虚拟内存地址
  SIZE_T    dwSize,        // 释放字节数,0表示全部释放
  DWORD dwFreeType // 释放方式
);
成功返回TRUE,失败返回FALSE。
dwFreeType取值:
MEM_DECOMMIT - 只释放内存不释放地址
MEM_RELEASE - 基释放内存也释放地址
注意:内存绑定(提交)以页(4096字节)为单位。
五、堆内存分配
1.特点:适合小内存(<1M)分配。一般每个程序都有自己的堆,默认为1M,会根据需要动态调整。每个进程都有几个缺省堆空间,malloc/new都是从这些堆中分配内存。
2.获取调用进程的首个堆
HANDLE GetProcessHeap (void);
成功返回调用进程首个堆的句柄,失败返回NULL。
3.获取调用进程的所有堆
DWORD GetProcessHeaps (
  DWORD   NumberOfHeaps, // 堆句柄数组的容量
  PHANDLE ProcessHeaps,      // 堆句柄数组
);
成功返回调用进程堆的个数,堆句柄放在ProcessHeaps数组中,失败返回0。
4.创建堆
HANDLE HeapCreate (
  DWORD flOptions,      // 创建选项
  DWORD dwInitialSize, // 初始字节数
  DWORD dwMaximumSize // 最大字节数,0表示无穷大
);
成功返回堆句柄,失败返回NULL。
flOptions取值:
HEAP_GENERATE_EXCEPTION - 堆内存分配失败则引发异常
HEAP_NO_SERIALIZE - 支持不连续存取
5.分配堆内存
LPVOID HeapAlloc (
  HANDLE hHeap,   // 堆句柄
  DWORD dwFlags, // 分配方式
  DWORD dwBytes, // 内存大小
);
成功返回堆内存地址,失败返回NULL。
dwFlags取值:
HEAP_GENERATE_EXCEPTION - 堆内存分配失败则引发异常
HEAP_NO_SERIALIZE - 支持不连续存取
(若在创建堆时已经指定此参数,则此处忽略之)
HEAP_ZERO_MEMORY - 初始化清零
6.释放堆内存
BOOL HeapFree (
  HANDLE hHeap,   // 堆句柄
  DWORD dwFlags, // 释放方式,只能取HEAP_NO_SERIALIZE
  LPVOID  lpMem   // 堆内存地址
);
成功返回TRUE,失败返回FALSE。
7.销毁堆
BOOL HeapDestroy (
  HANDLE hHeap   // 堆句柄
);
成功返回TRUE,失败返回FALSE。
当堆被销毁后,其中所有堆内存都会被自动释放。
8.Win32的malloc/new实现实际就是调用了上述堆函数。
六、栈内存
1.每个线程都有自己的栈,默认为1M字节。
2.操作系统负责自动维护栈内存的分配与释放。
3.Windows提供了_alloca函数,用于在栈中分配内存。
七、内存映射文件
1.基本概念
1)将文件映射成内存来使用,即访问内存的方式访问文件。
2)常用于实现进程通信,比直接通过文件I/O效率更高。
2.创建文件
用CreateFile创建,可读可写GENERIC_READ | GENERIC_WRITE。
3.创建映射
HANDLE CreateFileMapping (
  HANDLE hFile,       // 文件句柄
  ...                           // 安全属性,设NULL
  DWORD flProtect, // 访问方式,PAGE_READWRITE,可读可写
  DWORD dwMaximumSizeHigh, // 映射总字节数高32位
  DWORD dwMaximumSizeLow , // 映射总字节数低32位
  LPCTSTR lpName   // 映射名,NULL表示匿名映射,其它进程无法访问
);
成功返回映射句柄,失败返回NULL。
4.加载映射
LPVOID MapViewOfFile (
  HANDLE hFileMappingObject, // 映射句柄
  DWORD dwDesiredAccess,      // 访问方式,FILE_MAP_ALL_ACCESS
  DWORD dwFileOffsetHigh,      // 偏移量高32位
  DWORD dwFileOffsetLow,       // 偏移量低32位
  SIZE_T    dwNumberOfBytesToMap // 映射字节数(不超过映射总字节数)
);
成功返回映射地址,失败返回NULL。
5.使用映射:以内存的方式使用该映射。
6.卸载映射
BOOL UnmapViewOfFile (
  LPCVOID lpBaseAddress // 映射地址
);
成功返回TRUE,失败返回FALSE。
7.销毁映射
CloseHandle (hMap);
8.关闭文件
CloseHandle (hFile);
9.打开映射
HANDLE OpenFileMapping (
  DWORD dwDesiredAccess, // 访问方式,FILE_MAP_ALL_ACCESS
  BOOL     bInheritHandle,    // 子进程是否继承此函数所返回的句柄
  LPCTSTR lpName               // 映射名
);
成功返回映射句柄,失败返回NULL。
10.基于内存映射文件的进程间通信
1)写进程:创建文件->创建映射->加载映射->写入映射->卸载映射->销毁映射->关闭文件
2)读进程:打开映射->加载映射->读取映射->卸载映射->关闭映射
八、关于句柄
句柄就是内存对象地址在句柄表中索引。通过句柄不能直接访问内存,但是可以通过APIs函数操作其标识的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值