Click here to Skip to main content
Licence 
First Posted 22 Apr 2007
Views 80,099
Downloads 726
Bookmarked 62 times

Add a UAC shield to a button when elevation is required for admin tasks

By | 22 Apr 2007 | Article
Add a UAC shield to a button when elevation is required for admin tasks using the API, and elevate the process if required.
Screenshot - VistaSecurity.png

Introduction

Any application that does not always need administrator privileges should not run with them by default. However, when a user wants to perform a task that requires elevation, you need to show them that this is required by displaying the Vista shield icon. When this is clicked, your application will then need to restart with administrator privileges. Interested? Then read on...

Making the VistaSecurity Class

First we need to create a VistaSecurity class. Inside it we need the SendMessage API.

[DllImport("user32")]
public static extern UInt32 SendMessage
    (IntPtr hWnd, UInt32 msg, UInt32 wParam, UInt32 lParam);

internal const int BCM_FIRST = 0x1600; //Normal button
internal const int BCM_SETSHIELD = (BCM_FIRST + 0x000C); //Elevated button

First, before we add a shield, we need to know if the process is elevated or not which is easily done. To add a shield to a button, make sure that the button uses FlatStyle.System and then sends the appropriate message using the API. The important API function parameters are the handle of the button and the BCM_SETSHIELD message.

static internal bool IsAdmin()
{
    WindowsIdentity id = WindowsIdentity.GetCurrent();
    WindowsPrincipal p = new WindowsPrincipal(id);
    return p.IsInRole(WindowsBuiltInRole.Administrator);
}

static internal void AddShieldToButton(Button b)
{
    b.FlatStyle = FlatStyle.System;
    SendMessage(b.Handle, BCM_SETSHIELD, 0, 0xFFFFFFFF);
}

We then need a way to elevate the process if required. We just restart the process with the "runas" Verb. The current unelevated process is then exited unless the System.ComponentModel.Win32Exception is thrown, as this indicates that the user has clicked Cancel on the UAC prompt.

internal static void RestartElevated()
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.UseShellExecute = true;
    startInfo.WorkingDirectory = Environment.CurrentDirectory;
    startInfo.FileName = Application.ExecutablePath;
    startInfo.Verb = "runas";
    try
    {
        Process p = Process.Start(startInfo);
    }
    catch(System.ComponentModel.Win32Exception ex)
    {
        return;
    }

    Application.Exit();
}

That's it for the VistaSecurity class.

Using the code

On the form, you need the following code in your constructor after InitializeComponent which will add the shield.

if (!VistaSecurity.IsAdmin())
{
    this.Text += " (Standard)"; //Unnecessary
    VistaSecurity.AddShieldToButton(buttonGetElevation); //Important
}
else
    this.Text += " (Elevated)";

When the button is clicked we need to check if you have permission to perform the required action or elevate.

if (VistaSecurity.IsAdmin())
{
    DoAdminTask();
}
else
{
    VistaSecurity.RestartElevated();
}

Well, that's how to display a shield and get elevation!

Points of Interest

For the admin task in this demo, I added a file VISTA.TXT to All Users' start menu at \ProgramData\Microsoft\Windows\Start Menu\. To get rid of the file, run the demo again (admin credentials may be required!). The Try Admin Task button just tries to create the file without asking for elevation.

History

  • 22 Apr 07 - Article written
  • 24 Apr 07 - Checking of Administrator account works for non-English versions of Windows by using WindowsBuiltInRole.Administrator instead of a non-localized string. In DoAdminTask(), MessageBoxes show what has been done, more error catching added, and an Environment.SpecialFolder is used to get the path.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

hackman3vilGuy

Software Developer (Senior)

United Kingdom United Kingdom

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionCant get the UAC icon to a button [modified] Pinmemberhanonymouss4:11 1 Mar '12  
QuestionLicense for this Component Pinmemberstreetsjingo10:45 30 Nov '11  
QuestionAwesome! + How wrong can you be? PinmemberVercas4:10 3 Oct '10  
GeneralCode PinmemberBrandon Holland3:21 12 Jul '09  
GeneralRestart application Pinmemberjammmie99922:55 24 May '09  
GeneralRe: Restart application PinmemberMcoreD15:34 30 Aug '09  
AnswerRe: Restart application PinmemberIndivara14:14 28 Jan '10  
Questionhow to remove it ? Pinmembervishal108216:46 21 May '09  
AnswerRe: how to remove it ? Pinmemberjammmie99922:54 24 May '09  
AnswerRe: how to remove it ? PinmemberSky Sanders7:23 27 Dec '09  
GeneralIsAdmin Function - an easier way PinmemberDmex877:51 7 Jan '09  
GeneralRe: IsAdmin Function - an easier way Pinmembervtpdawg8:11 7 Jan '10  
GeneralVb.net PinmemberJorge Rocha15:05 29 Dec '08  
GeneralRe: Vb.net PinmemberJumpyCODE20:55 13 Mar '09  
I just made a translation to VB2008. Here it goes:
 
Make a new form with one button on it and paste in this code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If VistaSecurity.IsAdmin Then
Button1.Text = "Already admin"
Else
Button1.Text = "Restart as admin"
VistaSecurity.AddShieldToButton(Button1)
End If
End Sub
 
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
VistaSecurity.RestartElevated()
End Sub

 
Make a new module called VistaSecurity and paste in this code:
Imports System.Security.Principal
 
Module VistaSecurity
 
'Declare API
Private Declare Ansi Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Private Const BCM_FIRST As Int32 = &H1600
Private Const BCM_SETSHIELD As Int32 = (BCM_FIRST + &HC)
 
Public Function IsVistaOrHigher() As Boolean
Return Environment.OSVersion.Version.Major < 6
End Function
 
' Checks if the process is elevated
Public Function IsAdmin() As Boolean
Dim id As WindowsIdentity = WindowsIdentity.GetCurrent()
Dim p As WindowsPrincipal = New WindowsPrincipal(id)
Return p.IsInRole(WindowsBuiltInRole.Administrator)
End Function
 
' Add a shield icon to a button
Public Sub AddShieldToButton(ByRef b As Button)
b.FlatStyle = FlatStyle.System
SendMessage(b.Handle, BCM_SETSHIELD, 0, &HFFFFFFFF)
End Sub
 
' Restart the current process with administrator credentials
Public Sub RestartElevated()
Dim startInfo As ProcessStartInfo = New ProcessStartInfo()
startInfo.UseShellExecute = True
startInfo.WorkingDirectory = Environment.CurrentDirectory
startInfo.FileName = Application.ExecutablePath
startInfo.Verb = "runas"
Try
Dim p As Process = Process.Start(startInfo)
Catch ex As Exception
Return 'If cancelled, do nothing
End Try
Application.Exit()
End Sub
 
End Module

GeneralRe: Vb.net Pinmemberzerosoft_uk12:14 26 Jul '11  
GeneralExcellant... and i rolled it all into a handy control :D PinmemberFocusedWolf19:32 25 May '08  
GeneralRe: Excellant... and i rolled it all into a handy control :D PinmemberFocusedWolf19:35 25 May '08  
GeneralRe: Excellant... and i rolled it all into a handy control :D PinmemberFocusedWolf10:11 26 May '08  
GeneralRe: Excellant... and i rolled it all into a handy control :D PinmemberFocusedWolf9:40 30 May '08  
GeneralRe: Excellant... and i rolled it all into a handy control :D Pinmemberf r i s c h1:54 19 Aug '08  
RantRe: Excellant... and i rolled it all into a handy control :D Pinmember98z288:48 25 Feb '10  
GeneralWont detect properly except for first user in Vista Pinmemberleifre8:08 11 Apr '08  
Question.NET 3? PinmemberJimShabadoo8:34 2 Nov '07  
AnswerRe: .NET 3? PinmemberJimShabadoo8:48 2 Nov '07  
GeneralRe: .NET 3? PinmemberKyferEz15:28 15 Oct '09  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120529.1 | Last Updated 22 Apr 2007
Article Copyright 2007 by hackman3vilGuy
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid