管理员权限下C#访问C:\Windows\System32\sru\SRUDB被拒绝的问题
核心原因分析
- 文件系统重定向(64位系统):如果你的程序是32位,Windows会自动将
C:\Windows\System32的访问重定向到C:\Windows\SysWOW64,但SRUDB文件实际位于原生System32目录,导致你访问的是错误路径,触发权限拒绝。 - 操作顺序错误:代码中先尝试下载文件到目标路径,此时目标路径的文件可能未配置好权限,甚至被系统锁定,直接下载会先抛出异常。
- 系统文件锁定:SRUDB是系统资源使用数据库文件,大概率被
srums.exe等系统进程占用,直接读写或移动会被系统阻止。
解决方案
1. 禁用文件系统重定向(仅32位程序需要)
在访问System32路径前禁用重定向,操作完成后恢复:
[DllImport("kernel32.dll", SetLastError = true)] static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); [DllImport("kernel32.dll", SetLastError = true)] static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
2. 调整操作顺序
先配置目标目录和文件的权限,再将文件下载到临时目录,最后处理移动/替换操作,避免直接操作被锁定的系统文件。
3. 处理系统文件锁定
使用MoveFileEx设置延迟移动/删除,让系统在重启后完成操作,绕过当前进程的文件占用:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); [Flags] enum MoveFileFlags { MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004 }
修改后的代码示例
// 调用示例 DownloadAndMoveFile("https://test.com/SRUDB", @"C:\Windows\System32\sru", "SRUDB.dat"); private void DownloadAndMoveFile(string url, string targetDir, string newFileName) { IntPtr redirectPtr = IntPtr.Zero; try { // 禁用64位文件系统重定向(仅32位程序需要) if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess) { Wow64DisableWow64FsRedirection(ref redirectPtr); } // 确保目标目录存在并配置权限 if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); var dirSecurity = Directory.GetAccessControl(targetDir); var currentAccount = new NTAccount(WindowsIdentity.GetCurrent().Name); dirSecurity.AddAccessRule(new FileSystemAccessRule( currentAccount, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); Directory.SetAccessControl(targetDir, dirSecurity); } // 下载到临时文件,避免直接写入被锁定的目标路径 string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); using (WebClient client = new WebClient()) { client.DownloadFile(url, tempFilePath); } string targetFilePath = Path.Combine(targetDir, newFileName); string originalSRUDBPath = Path.Combine(targetDir, "SRUDB"); // 配置原SRUDB文件权限(如果存在) if (File.Exists(originalSRUDBPath)) { var fileSecurity = File.GetAccessControl(originalSRUDBPath); var currentAccount = new NTAccount(WindowsIdentity.GetCurrent().Name); fileSecurity.RemoveAccessRule(new FileSystemAccessRule(currentAccount, FileSystemRights.FullControl, AccessControlType.Deny)); fileSecurity.AddAccessRule(new FileSystemAccessRule(currentAccount, FileSystemRights.FullControl, AccessControlType.Allow)); File.SetAccessControl(originalSRUDBPath, fileSecurity); } // 配置目标文件权限(如果存在) if (File.Exists(targetFilePath)) { var fileSecurity = File.GetAccessControl(targetFilePath); var currentAccount = new NTAccount(WindowsIdentity.GetCurrent().Name); fileSecurity.RemoveAccessRule(new FileSystemAccessRule(currentAccount, FileSystemRights.FullControl, AccessControlType.Deny)); fileSecurity.AddAccessRule(new FileSystemAccessRule(currentAccount, FileSystemRights.FullControl, AccessControlType.Allow)); File.SetAccessControl(targetFilePath, fileSecurity); } // 处理被锁定的文件,延迟到重启后操作 if (File.Exists(targetFilePath)) { MoveFileEx(targetFilePath, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); } // 移动临时文件到目标路径 if (File.Exists(originalSRUDBPath)) { MoveFileEx(originalSRUDBPath, targetFilePath, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); } else { File.Move(tempFilePath, targetFilePath); } } finally { // 恢复文件系统重定向 if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess && redirectPtr != IntPtr.Zero) { Wow64RevertWow64FsRedirection(redirectPtr); } } } // 导入必要的系统API [DllImport("kernel32.dll", SetLastError = true)] static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); [DllImport("kernel32.dll", SetLastError = true)] static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); [Flags] enum MoveFileFlags { MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004 }
额外注意事项
- 确保程序清单中已设置
requestedExecutionLevel level="requireAdministrator",强制以管理员身份运行。 - SRUDB是系统核心文件,修改或替换可能导致系统资源统计功能异常,操作前务必备份原文件。
内容的提问来源于stack exchange,提问作者St1nger
相关产品推荐
相关产品推荐

