编译程序的时候设置一下
在项目属性--链接器--清单文件--UAC执行级别改成requireAdministratorc++
void GainAdminPrivileges(CString strApp, UINT idd) { CString strCmd; strCmd.Format (_T("/adminoption %d"), idd); SHELLEXECUTEINFO execinfo; memset(&execinfo, 0, sizeof(execinfo)); execinfo.lpFile = strApp; execinfo.cbSize = sizeof(execinfo); execinfo.lpVerb = _T("runas"); execinfo.fMask = SEE_MASK_NO_CONSOLE; execinfo.nShow = SW_SHOWDEFAULT; execinfo.lpParameters = strCmd; ShellExecuteEx(&execinfo); }
strApp是应用程序的路径idd我传的是1,但好像传几都没问题shell
BOOL ElevateCurrentProcess(CString sCmdLine) { TCHAR szPath[MAX_PATH] = {0}; if (::GetModuleFileName(NULL, szPath, MAX_PATH)) { // Launch itself as administrator. SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) }; sei.lpVerb = _T("runas"); sei.lpFile = szPath; sei.lpParameters = (LPCTSTR)sCmdLine; // sei.hwnd = hWnd; sei.nShow = SW_SHOWNORMAL; if (!ShellExecuteEx(&sei)) { DWORD dwStatus = GetLastError(); if (dwStatus == ERROR_CANCELLED) { // The user refused to allow privileges elevation. return FALSE; } else if (dwStatus == ERROR_FILE_NOT_FOUND) { // The file defined by lpFile was not found and // an error message popped up. return FALSE; } return FALSE; } return TRUE; } return FALSE; }
当咱们那些在Windows 7以前设计的应用程序遇到UAC Virtualization问题的时候,咱们须要重新设计咱们的代码,将文件写入到合适的位置。在改善既有代码,使之能够与Windows 7兼容的时候,咱们应该确保如下几点:编程
——在运行的时候,应用程序只会将数据保存到每一个用户预先定义的位置或者是%alluserprofile% 中定义的普通用户拥有访问权限的位置。windows
——肯定你要写入数据的“已知文件夹”(Knownfolders)。一般,全部用户共用的公共数据文件应该写入到一个全局的公共的位置,这样全部用户均可以访问到。而其它数据则应该写入每一个用户本身的文件夹。api
1 公共数据文件包括日志文件,配置文件(一般是INI或者XML文件),应用程序状态文件,好比保存的游戏进程等等。函数
2 而属于每一个用户的文档,则应该保持在文档目录下,或者是用户本身指定的目录。ui
——当你肯定合适的文件保存位置后,不要在代码中明文写出(Hard-code)你选择的路径。为了更好地保持兼容性,咱们应该采用下面这些API来得到操做系统“已知文件夹(Knownfolders)”的正确路径。操作系统
1 C/C++非托管代码: 使用SHGetKnownFolderPath函数,经过指定“已知文件夹”的KNOWNFOLDERID做为参数来得到正确的文件夹路径。.net
FOLDERID_ProgramData –全部用户均可以访问的应用程序数据适合放置在这个目录下。 FOLDERID_LocalAppData – 每一个用户单独访问的应用程序数据适合放置在这个目录下。 FOLDERID_RoamingAppData – 每一个用户单独访问的应用程序数据适合放置在这个目录下。 与上面一个目录不一样的是,放置在这个目录下的文件会随着用户迁移,当一个用户在同一个域中的其余计算机登陆的时候,这些文件会被复制到当前登陆的机器上,就像用户随身携带的公文包同样。
下面这段代码演示了在非托管代码中如何调用shell函数,SHGetKnownFolderPath函数得到正确的文件保存路径(SHGetFolderLocation, SHGetFolderPath, SHGetSpecialFolderLocation, SHGetSpecialFolderPath):设计
#include "shlobj.h" #include "shlwapi.h" //… #define AppFolderName _T("YourApp") #define DataFileName _T("SomeFile.txt") // 构造一个数据文件路径 // dataFilePath指向一个长度为MAX_PATH,类型为TCHAR的字符串数值 // hwndDlg是消息对话框的父窗口句柄 // 当有错误发生的时候用于显示错误提示 // includeFileName用于表示是否在路径后面扩展文件名 BOOL MakeDataFilePath(TCHAR *dataFilePath, HWND hwndDlg, BOOL includeFileName) { // 初始化工做 memset(dataFilePath, 0, MAX_PATH * sizeof(TCHAR)); PWSTR pszPath = NULL; // SHGetKnownFolderPath函数能够返回一个已知文件见的路径, // 例如个人文档(My Documents),桌面(Desktop), // 应用程序文件夹(Program Files)等等。 // 对于数据文件来讲,FOLDERID_ProgramFiles并非一个合适的位置 // 使用FOLDERID_ProgramFiles保存全部用户共享的数据文件 // 使用FOLDERID_LocalAppData保存属于每一个用户本身的文件(non-roaming). // 使用FOLDERID_RoamingAppData保存属于每一个用户本身的文件(roaming). // 对于“随身文件”(Roaming files), // 当一个用户在一个域中的其余计算机登录的时候, // 这些文件会被复制到当前登陆的机器上,就像用户随身携带的公文包同样 // 获取文件夹路径 if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &pszPath))) // 错误的作法: if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFiles, // 0, NULL, &pszPath))) { // 提示错误 MessageBox(hwndDlg, _T("SHGetKnownFolderPath没法获取文件路径"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } // 复制路径到目标变量 _tcscpy_s(dataFilePath, MAX_PATH, pszPath); ::CoTaskMemFree(pszPath); //错误的作法: _tcscpy_s(dataFilePath, MAX_PATH, _T("C:\\")); // 在路径后面扩展应用程序所在文件夹 if (!::PathAppend(dataFilePath, AppFolderName)) { // 提示错误 MessageBox(hwndDlg, _T("PathAppend没法扩展路径"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } // 是否添加文件名 if (includeFileName) { // 在路径后扩展文件名 if (!::PathAppend(dataFilePath, DataFileName)) { // 提示错误 MessageBox(hwndDlg, _T("PathAppend没法扩展文件名"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } } return TRUE; }
2 托管代码: 使用System.Environment.GetFolderPath函数,经过指定咱们想要获取的“已知文件夹”为参数,从而获取相应的文件夹的正确路径。
Environment.SpecialFolder.CommonApplicationData – 全部用户均可以访问的应用程序数据适合放置在这个目录下。 Environment.SpecialFolder.LocalApplicationData – 每一个用户单独访问的应用程序数据适合放置在这个目录下。 Environment.SpecialFolder.ApplicationData – 每一个用户单独访问的应用程序数据适合放置在这个目录下。这是“随身文件夹”。
下面这段代码展现了如何在托管代码中获取正确的文件路径:
internal class FileIO { private const string AppFolderName = "YourApp"; private const string DataFileName = "SomeFile.txt"; private static string _dataFilePath; /// <summary> /// 构建路径 /// </summary> static FileIO() { // Environment.GetFolderPath返回一个“已知文件夹”的路径 // Path.Combine能够合并两个路径成一个合法的路径 // … _dataFilePath = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.ProgramFiles), AppFolderName); //错误的作法: //_dataFilePath = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.CommonApplicationData), AppFolderName); // 扩展文件名 _dataFilePath = Path.Combine(_dataFilePath, DataFileName); } public static void Save(string text) { // 检查要保存的字符串是否为空 if (String.IsNullOrEmpty(text)) { MessageBox.Show("字符串为空,没法保持.", "空字符串", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { // 获取文件保存的路径 string dirPath = Path.GetDirectoryName(_dataFilePath); // 检查文件夹是否存在 if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); // 建立文件夹 } catch (Exception ex) { MessageBox.Show(ex.Message, "文件夹建立失败", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { // 保存字符串到文件 StreamWriter sw = new StreamWriter(_dataFilePath); try { sw.Write(text); } finally { // 关闭文件 sw.Close(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "文件写入失败", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // … } }
若是上面的方法都不适合你,你还可使用环境变量,使用getenv()或GetEnvironmentVariable()获取相应的文件夹路径:
%ALLUSERSPROFILE% – 全部用户均可以访问的应用程序数据适合放置在这个目录下。 %LOCALAPPDATA% – 每一个用户单独访问的应用程序数据适合放置在这个目录下。 - (Windows Vista 或者Windows 7) %APPDATA% – 每一个用户单独访问的应用程序数据适合放置在这个目录下。这是“随身文件夹”。- (Windows Vista 或者Windows 7)