After a long period since I wrote part 2 of this article I decided to add some extra information. There is one thing that was missed by the previous two articles: the design of UAC enabled applications.
If you use Windows Vista/7 then you know that buttons and links which elevate privileges are preceded by a shield icon. This is the way Microsoft decided to inform the user about the effect of clicking that control.
The first idea that might pop up is the reinvention of the wheel (or shield). In other words you could draw the shield on a button. This is OK except that:
- Is not easy
- Will require you to recompile the interface if Microsoft decides to change the icon
- You need the icon in many sizes 16x16, 24x24, 32x32, etc. (extract it from MS' DLLs)
- Will create a lot of overhead with layout (position icon relative to text size/position)
The second method is easier, safer and recommended by MS. All you need to do is send a specific message (BCM_SETSHIELD) to the button if the user has limited privileges and pressing that button will trigger the UAC window. Actually there is a second, tricky, thing that must be done: the style of the button must be "System" (in C# "System.Windows.FlatStyle.System"). Without this you will not be able to see the shield.
The code provided in part 1 of this article will be modified in order to display the shield on the two buttons. Moreover, the shield will be displayed only when the user runs under an account with limited privileges or non-elevated administrator.
In order to display the shield one needs to send the BCM_SETSHIELD (=0x0000160C) message to the button. This can be done by using the SendMessage function from user32.dll. This article will not cover what is and how to use SendMessage, if you need more information about it follow the previous link.
To set the shield of the "Elevate this application" button one needs to send the message in the following way:
The first parameter is the handle of the button, the second one is the message, the third one is not used and must be '0' and the last argument must be non-zero in order to draw the shield, zero otherwise.
If you try this it will not work :) Remember the 'tricky' thing told before? This is the full code to display the shield for btnElevate:
There is only one thing that must be done in order to work properly. Remove the shield if the user has elevated privileges. I don't know if this is against MS' recommendation but in my opinion one must not be shown information that cannot be used in that context; in our case don't show the elevate shield if there is nothing to elevate.
Part 1 described how to check if a user has full rights. Now we are just using that boolean variable:
Where SetUACShields will send the message to all buttons that require the shield drawn.
The full updated code from Part 1: download.