說明
Windows從Vista開始引進UAC (User Account Control),這是一項不錯的機制,雖然有點煩人,但是至少可以通知使用者目前的動作是會影響到系統的「安全性」。但是對我們這些寫程式的人來說,UAC可就是常常出問題的點了。
例如下面「呼叫特定Windows Service」的程式碼:
1: // WindowsServiceStart: 啟動視窗服務2: #region3: public static bool WindowsServiceStart(string strServiceName)4: {5: // 回傳值6: bool bln = true;7:8: // 服務管理員9: ServiceController svc = new ServiceController();10:11: // 取得服務啟動之Timeout12: TimeSpan timeout = TimeSpan.FromMilliseconds(int.Parse(Program.SettingRead(LL.Setting_Service_Timeout)));13:14: try15: {16: // 設定ServiceName17: svc.ServiceName = strServiceName;18:19: // 檢查目前狀態,若不在執行中,或是啟動中,則啟動之20: if ((svc.Status != ServiceControllerStatus.Running) && (svc.Status != ServiceControllerStatus.StartPending))21: {22: svc.Start();23: svc.WaitForStatus(ServiceControllerStatus.Running, timeout);24: }25:26: bln = (svc.Status == ServiceControllerStatus.Running);27: }28: catch (InvalidOperationException)29: {30: bln = false;31: }32:33: return bln;34: }35: #endregion36:
在Windows XP中運作正常,但是放到了Windows 7的環境中,就會出現以下的錯誤:
只要看到了圖中的「存取被拒」,問題點在哪兒,心中已有了答案。反正不是權限不足,就是被UAC給擋住了。
就算目前的使用者是屬於「Administrators」群組,只要您不是透過以下二種方式執行程式,那麼,預設您就是沒有修改「Windows Service」的權限:
- 右點捷徑選取「以系統管理員身份執行」
- 點選「UAC」確認視窗
解決方法
但是我們是程式設計師,需要以程式來解決這項問題。解法有二:
- 利用Manifest檔,自動跳出UAC確認視窗,讓使用者在繼續程式前,先行確認 (建議作法)
- 利用程式,自動重新執行一個可經過使用者授權之程式 (會多出一個程式實體)
1. 在Program.cs中加入以下程式碼
1: // IsRunAsAdministrator: 是否以Administrator權限執行2: #region3: public static bool IsRunAsAdministrator()4: {5: // 取得目前執行之使用者權限6: WindowsIdentity wi = WindowsIdentity.GetCurrent();7:8: // 檢查是否為Null9: if (wi == null)10: {11: return false;12: }13: else14: {15: return (new WindowsPrincipal(wi)).IsInRole(WindowsBuiltInRole.Administrator);16: }17: }18: #endregion19:20: // ProgramElevateToAdministrator: 詢問使用者是否可將目前程序提昇至Administrator身份21: #region22: public static void ProgramElevateToAdministrator()23: {24: // 檢查是否已用Admin身份執行25: if (!IsRunAsAdministrator())26: {27: // 將此程序改為以Admin身份執行28: ProcessStartInfo prc = new ProcessStartInfo();29: prc.UseShellExecute = true;30: prc.WorkingDirectory = Environment.CurrentDirectory;31: prc.FileName = Application.ExecutablePath;32: // 指定「runas」屬性33: prc.Verb = "runas";34:35: try36: {37: // 將會跳出UAC詢問視窗38: Process.Start(prc);39: }40: catch41: {42: // 若使用者拒絕,跳出43: return;44: }45: }46: }47: #endregion
2. 在程式中加入以下程式碼,用以執行新的程式實體 (例如按鈕的事件,或是工具列的事件)
1: // SystemUAC: 進行UAC確認2: #region3: private void SystemUAC()4: {5: // 檢查是否為Vista或以上之系統,若是則進行UAC確認6: if (Environment.OSVersion.Version.Major >= 6)7: {8: Program.ProgramElevateToAdministrator();9: }10: }11: #endregion12:
參考
http://stackoverflow.com/questions/3892088/servicecontroller-permissions-in-windows-7
http://stackoverflow.com/questions/916714/how-to-run-c-application-with-admin-creds
http://www.codeproject.com/KB/cs/cpimpersonation1.aspx
http://csharptuning.blogspot.com/2007/06/impersonation-in-c.html
http://msdn.microsoft.com/en-us/library/1w45z383(vs.71).aspx
http://social.msdn.microsoft.com/Forums/da-DK/winforms/thread/db6647a3-85ca-4dc4-b661-fbbd36bd561f
沒有留言:
張貼留言