如何通过代码获取Windows磁盘设备的写入权限?
解决Windows磁盘/驱动器写入访问被拒的问题
问题场景
向物理磁盘或逻辑驱动器写入数据时,频繁遇到访问被拒错误。即使调用FSCTL_DISMOUNT_VOLUME卸载卷后,问题依然存在。希望复刻Windows磁盘管理的功能:检测到进程占用卷时,强制获取写入权限完成操作。
相关代码示例:
// 打开物理磁盘或逻辑驱动器 HANDLE hd=CreateFile("\\\\.\\PhysicalDrive1",GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); // HANDLE hd=CreateFile("\\\\.\\C:",GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); // 尝试卸载卷后写入 DeviceIoControl(hd,FSCTL_DISMOUNT_VOLUME,NULL,NULL,NULL,NULL,NULL,NULL); WriteFile(hd,...);
核心实现方案
要实现磁盘管理的强制写入逻辑,需通过以下步骤锁定卷、解除挂载并处理占用进程,关键API如下:
1. 锁定卷(阻止其他进程访问)
调用FSCTL_LOCK_VOLUME控制码,通过DeviceIoControl执行,锁定后其他进程无法对该卷进行读写操作:
BOOL bLocked = DeviceIoControl( hd, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, NULL, NULL );
如果锁定失败,说明有进程正在占用该卷,需先处理这些进程。
2. 彻底卸载卷与挂载点
仅调用FSCTL_DISMOUNT_VOLUME可能无法完全解除系统关联,针对逻辑卷还需移除驱动器号,使用IOCTL_DISK_DELETE_DRIVE_LETTER:
// 以C盘为例,计算驱动器号对应的索引 DWORD dwDriveLetter = 'C' - 'A'; BOOL bRemoved = DeviceIoControl( hd, IOCTL_DISK_DELETE_DRIVE_LETTER, &dwDriveLetter, sizeof(dwDriveLetter), NULL, 0, NULL, NULL );
这一步会让系统彻底解除卷的挂载,大幅降低被进程占用的概率。
3. 检测并终止占用进程
若锁定卷失败,需枚举并终止占用该卷的进程:
- 使用
CreateToolhelp32Snapshot枚举系统内所有进程 - 通过
NtQuerySystemInformation(底层API)枚举每个进程的句柄,匹配目标卷的句柄 - 调用
OpenProcess获取进程权限,再用TerminateProcess终止占用进程
简化示例代码:
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe32)) { do { // 此处需补充句柄枚举逻辑,判断进程是否占用目标卷 HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID); if (hProcess && IsProcessUsingVolume(hProcess, hd)) { // 自定义判断函数 TerminateProcess(hProcess, 0); CloseHandle(hProcess); } } while (Process32Next(hSnapshot, &pe32)); } CloseHandle(hSnapshot);
注意:句柄枚举需要调用未公开的NtQuerySystemInformation,实现时需处理权限问题,且终止进程会导致数据丢失,需提前提示用户确认。
4. 确保管理员权限
所有操作必须以管理员权限运行,否则会持续出现访问被拒。可在程序清单中添加:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
完整流程
- 以管理员权限启动程序
- 打开磁盘/驱动器句柄(携带
FILE_FLAG_BACKUP_SEMANTICS和GENERIC_WRITE权限) - 尝试调用
FSCTL_LOCK_VOLUME锁定卷 - 锁定失败则检测并终止占用进程,重新尝试锁定
- 调用
FSCTL_DISMOUNT_VOLUME卸载卷 - 逻辑卷需调用
IOCTL_DISK_DELETE_DRIVE_LETTER移除驱动器号 - 执行
WriteFile完成写入 - 操作结束后,调用
FSCTL_UNLOCK_VOLUME解锁卷,按需恢复驱动器号
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

