摘要
在對winform打包,進行安裝的時候,一般會采用默認的安裝路徑,默認安裝在C:\Program Files\xx或者C:\Program Files(x86)目錄下,但windows有一種安全策略,默認是不允許操作c盤文件或者文件夾的。
解決辦法
在軟件發布的時候,一般會對軟件exe進行簽名的,使其發布者顯示為某某公司,這里建議另建一個軟件啟動程序,對啟動程序進行簽名。這樣你的軟件如果更新,就不需要反復的對軟件進行簽名了。
1、啟動程序可以,在配置文件中,設置啟動的exe名稱。可以多個軟件公用一個啟動程序,而改變啟動程序名稱對簽名是沒有影響的。
2、可以在啟動程序中,對軟件目錄進行權限驗證。如果沒有權限,可以讓其彈出UAC窗口,以管理員身份運行,並在主程序中,對軟件所在目錄進行授權操作。
核心代碼
啟動程序
class Program { static string _exeName = ConfigurationManager.AppSettings["exeName"]; static string _exeDir = AppDomain.CurrentDomain.BaseDirectory; static string _startExePath = Path.Combine(_exeDir, _exeName); static EventLog log = new EventLog() { Source = Path.GetFileNameWithoutExtension(_exeName) }; static void Main(string[] args) { try { if (string.IsNullOrEmpty(_exeName)) { log.WriteEntry("no set exe name", EventLogEntryType.Error); } else { if (!IsAdmin()) { //是否有完全控制權限 if (CheckFolderPermissions(_exeDir, FileSystemRights.FullControl)) { //運行主進程,不彈出UAC窗口 RunAsAdmin(false); } else { //彈出UAC窗口,以管理員身份運行程序,並在主程序中,進行文件夾授權 RunAsAdmin(true); } } else { //運行主進程,不彈出UAC窗口 RunAsAdmin(false); } } } catch (Exception ex) { log.WriteEntry(ex.Message, EventLogEntryType.Error); } } /// <summary> /// 檢查文件夾權限 /// </summary> /// <param name="dirPath"></param> /// <param name="accessType"></param> /// <returns></returns> public static bool CheckFolderPermissions(string dirPath, FileSystemRights accessType) { bool havePermission = false; try { AuthorizationRuleCollection collection = Directory. GetAccessControl(dirPath) .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)); foreach (FileSystemAccessRule rule in collection) { if ((rule.FileSystemRights & accessType) > 0) { havePermission=true;
break; } } } catch { havePermission = false; } return havePermission; } /// <summary> /// 以管理員身份運行,彈出UAC控制窗口 /// </summary> /// <param name="isRunAsAdmin">是否彈出uac控制</param> private static void RunAsAdmin(bool isRunAsAdmin) { //創建啟動對象 System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); //設置運行文件 startInfo.FileName = _startExePath; if (isRunAsAdmin) { //設置啟動動作,確保以管理員身份運行 startInfo.Verb = "runas"; } if (File.Exists(_startExePath)) { //如果不是管理員,則啟動UAC System.Diagnostics.Process.Start(startInfo); } else { log.WriteEntry("not find the appication to run", EventLogEntryType.Error); } } /// <summary> /// 是否是管理員 /// </summary> /// <returns></returns> static bool IsAdmin() { try { System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent(); System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity); return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); } catch { return false; } } }
主程序在Main函數中進行授權
SetAccess("Users", StaticParameter.ExeDir);
/// <summary> /// 為指定用戶組,授權目錄指定完全訪問權限 /// </summary> /// <param name="user">用戶組,如Users</param> /// <param name="folder">實際的目錄</param> /// <returns></returns> public static bool SetAccess(string user, string folder) { //定義為完全控制的權限 const FileSystemRights Rights = FileSystemRights.FullControl; //添加訪問規則到實際目錄 var AccessRule = new FileSystemAccessRule(user, Rights, InheritanceFlags.None, PropagationFlags.NoPropagateInherit, AccessControlType.Allow); var Info = new DirectoryInfo(folder); var Security = Info.GetAccessControl(AccessControlSections.Access); bool Result; Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result); if (!Result) return false; //總是允許再目錄上進行對象繼承 const InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit; //為繼承關系添加訪問規則 AccessRule = new FileSystemAccessRule(user, Rights, iFlags, PropagationFlags.InheritOnly, AccessControlType.Allow); Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result); if (!Result) return false; Info.SetAccessControl(Security); return true; }
在授權的時候,需要保證是管理員身份運行的。所在在啟動程序中,可以先判斷目錄的權限,如果還未授權,則彈出UAC窗口,使其以管理員身份運行,首次運行授權,之后運行就可以跳過這個過程。
總結
文件及文件夾提權,在C/s中是經常遇到的一個問題。比如,如果你沒有讀寫權限,如果操作sqlite就會提示沒權限操作數據庫的bug。
參考
