产品肯定需要迭代,前几天在迭代时就遇到了一个问题:部分用户的老版本无法更新到新版本。我用的MoveFile将老版本改名,然后下载新版本重新应用。
MoveFile失败,GetLastError返回的错误码为5---》权限问题或者操作的对象被占用。几轮排查之后发现是权限的问题,有些用户的安装路径在C:\Program Files\下,有的在其他盘,所以其他盘的可以更新,C:\Program Files\下的无法更新。因为在Windows系统里C盘是系统盘,普通用户只有读的权限没有修改和写入的权限,所以操作其文件或是文件夹需要管理员权限的,故MoveFile改名失败导致更新失败。(不只是该函数,只要是对系统盘的操作都要注意权限问题!!!)
解决方法:
1.手动为普通用户添加权限(测试或者自己用,那这个方法没问题,给用户当然是不行的)
2. 使用GetNamedSecurityInfo、SetEntriesInAcl和SetNamedSecurityInfo三个函数来修改对象的ACL,但前提是你得有管理员权限。(我获取管理员权限一直失败不知道为什么)具体可以参考以下链接:在 C++ 中修改对象的 ACL - Win32 apps | Microsoft Learn
或者博主涟幽516的文章修改 Windows 文件访问权限的多种方法_如何更改文件高级权限-CSDN博客
3.通过icacls命令来修改文件ACL,也需要管理员权限。以下的方法本质上是差不多的,都会弹出来一个UAC窗口,需要用户确认才能获取管理员权限。(目前我是通过②解决问题的)
①创建一个bat脚本执行修改(脚本也可以在程序中调用)
@echo off
rem 通过批处理来更改系统文件夹的文件名
rem icacls将文件权限设置为用户完全控制,rename改名
Net session >nul 2>&1 || mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0","","runas",1)(window.close)&&exit
icacls "C:\Program Files\xxx" /grant users:F /T /Q
②使用ShellExecuteEx函数调用cmd执行修改
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = "runas"; // 请求管理员权限
sei.lpFile = "cmd.exe"; // 要运行的程序
sei.lpParameters = "/c icacls \"C:\\Program Files\\xxx" /grant users:F /T /Q"; // 要执行的命令
sei.hwnd = NULL; // 父窗口句柄
sei.nShow = SW_NORMAL; // 显示方式
if (!ShellExecuteEx(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
// 用户拒绝了UAC对话框
} else {
// 其他错误
}
}
当然提权不止这些方法,这些都是比较简单常见的。还可以通过COM接口来提权,甚至绕过UAC弹窗无需用户确认提权。