Correct way to deal with UAC in C#

后端 未结 2 1528
终归单人心
终归单人心 2020-12-01 02:56

I have an application (Windows service) that is installed into a directory in the Program Files folder. Alongside this application is another WinForms application that is us

相关标签:
2条回答
  • 2020-12-01 03:59

    This is fairly easy. Put a shield icon on the button that saves changes to the configuration file, instead of the menu item. This follows the Windows behavior of not requesting UAC permissions until the last moment. The button actually will launch your executable again as administrator with a special command line (that you decide) to perform the configuration file saving. Use a named pipe (be sure to give it the correct permissions) to pass the configuration data to your second instance if your don't want to use the command line for data passing.

    For launching your executable:

    ProcessStartInfo info = new ProcessStartInfo();
    info.FileName = "YOUR EXE";
    info.UseShellExecute = true;
    info.Verb = "runas"; // Provides Run as Administrator
    info.Arguments = "YOUR SPECIAL COMMAND LINE";
    
    if (Process.Start(info) != null)
    { 
        // The user accepted the UAC prompt.
    }
    

    This works also when UAC doesn't exist (Windows XP), because it will simply run as administrator if possible, or prompt for credentials. You can check whether the OS requires UAC by simply doing Environment.OSVersion.Version.Major == 6. 6 is both Windows Vista and 7. You can make sure you're using Windows by looking at Environment.OSVersion.Platform.

    For detecting whether you're application is already admin, you can do this:

    public static bool IsAdministrator()
    {
        WindowsIdentity identity = WindowsIdentity.GetCurrent();
    
        if (identity != null)
        {
            WindowsPrincipal principal = new WindowsPrincipal(identity);
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
    
        return false;
    }
    
    0 讨论(0)
  • 2020-12-01 04:00

    Matthew Ferreira's answer goes in to the details on why you need to restart the whole application and what to do when to restart it, however he did not cover how to show the shield icon. Here is some code I use (I think I originally got it from another answer somewhere on this site) that will only show the shield icon when the program is not elevated

    /// <summary>
    /// Is a button with the UAC shield
    /// </summary>
    public partial class ElevatedButton : Button
    {
        /// <summary>
        /// The constructor to create the button with a UAC shield if necessary.
        /// </summary>
        public ElevatedButton()
        {
            FlatStyle = FlatStyle.System;
            if (!IsElevated()) ShowShield();
        }
    
    
        [DllImport("user32.dll")]
        private static extern IntPtr
            SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    
        private uint BCM_SETSHIELD = 0x0000160C;
    
        private bool IsElevated()
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            WindowsPrincipal principal = new WindowsPrincipal(identity);
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
    
    
        private void ShowShield()
        {
            IntPtr wParam = new IntPtr(0);
            IntPtr lParam = new IntPtr(1);
            SendMessage(new HandleRef(this, Handle), BCM_SETSHIELD, wParam, lParam);
        }
    }
    

    The button checks when it is being constructed if it is in a administrative context and if it is not it draws the shield icon on the button.

    If you want the shield icon windows uses, here is a sneaky trick that returns the shield icon as a Bitmap object.

    0 讨论(0)
提交回复
热议问题