在我們一些Winform程序中,往往需要具有一些特殊的權限才能操作系統文件,我們可以設置運行程序具有管理員權限或者設置運行程序的目錄具有寫入的權限,如果是在操作系統里面,我們可以設置運行程序以管理員身份運行,或者設置Users用戶組在運行目錄中具有寫入權限都可以解決問題,不過如果我們想通過C#代碼進行自動的處理,那么應該如何實現呢?
1、系統設置管理員權限或者目錄寫入權限
如果我們需要讓程序以管理員身份運行,那么可以通過設置快捷方式的屬性或者應用程序的屬性為【以管理員身份運行此程序】即可實現,如下所示。
如果我們需要一些寫入文件的權限,如我們程序可能需要操作SQLite文件數據庫,那么也可以通過設置Users用戶組在運行目錄中具有寫入權限都可以解決問題,否則可能會出現【 attempt to write a readonly database】的錯誤。
我們設置步驟如下所示:找到SQLite數據庫所在的文件夾,單擊右鍵,屬性->安全,為Users用戶組添加寫入權限。
2、使用C#代碼實現
上面的步驟可以解決我們實際碰到的權限訪問問題,那么我們如果使用C#代碼,應該如何實現這些操作呢?
對於第一個以管理員身份運行程序的處理操作,我們是可以通過程序修改配置的方式實現,這樣可以避免一些Winform程序運行時刻的權限問題:
1)在通過winform程序執行cmd命令時,某些情況下如果不是以管理員身份運行,則會提示命令無效。
2)或者通過winform程序執行Windows Service 服務時,也需要以管理員身份才能調用Service服務。
3)處理其他需要管理員身份的相關操作。
我們如果是編譯Winform程序,只需要幾步就可以在讓程序在運行的時候獲得管理員身份,如下所示在我們Winform的UI項目【屬性】【安全性】里面,勾選ClickOne的設置。
然后我們就可以看到在UI項目【Properties】目錄里面,生成了一個app.manifest文件。
這個app.manifest文件是自動生成的,我們修改其中的一項設置,然后取消上面勾選ClickOne的設置就可以了。
把其中app.manifest文件的內容:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
改為:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
即可,這樣取消上面勾選ClickOne的設置,然后重新編譯整個程序即可。
在程序運行的時候,會提示“用戶賬戶控制”來獲取管理員權限運行,點擊“是”則獲取了管理員權限。
對於需要為指定目錄設置用戶組權限,那么也是可以通過C#代碼進行處理的。
一般情況下,我們可以在程序安裝或者啟動的時候,對目錄進行用戶組權限的處理,這樣程序運行起來就自然具有對應目錄的讀寫權限了。
如我們在程序啟動的時候處理,那么我們可以在Main函數的里面進行設置。
/// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] private static void Main() { }
為了方便處理,我們添加一個公共的函數,用來處理用戶組的目錄權限訪問操作,C#代碼如下所示。
/// <summary> /// 為指定用戶組,授權目錄指定完全訪問權限 /// </summary> /// <param name="user">用戶組,如Users</param> /// <param name="folder">實際的目錄</param> /// <returns></returns> private 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; }
然后我們在Main函數里面進行調用就可以了。
/// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] private static void Main() { //為用戶組指定對應目錄的完全訪問權限 SetAccess("Users", Application.StartupPath); //界面漢化 System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("zh-Hans"); DevExpress.UserSkins.BonusSkins.Register(); DevExpress.Skins.SkinManager.EnableFormSkins(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //登錄界面 Login dlg = new Login(); dlg.StartPosition = FormStartPosition.CenterScreen; if (DialogResult.OK == dlg.ShowDialog()) { if (dlg.bLogin) { SplashScreen.Splasher.Show(typeof(SplashScreen.frmSplash)); gc.MainDialog = new MainForm(); gc.MainDialog.StartPosition = FormStartPosition.CenterScreen; Application.Run(gc.MainDialog); } } dlg.Dispose(); }
這樣在程序運行后,我們就可以看到對應目錄具有完全的讀寫操作權限了,這樣對於一些如讀寫SQLite出錯的問題,也就迎刃而解了。
以上就是我對於兩種不同權限訪問的處理經驗總結,希望給在Winform開發中的同行參考,感謝耐心的閱讀和支持。