|
I tweaked it out with a ton of features:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace StudioControls.Controls
{
public class StudioShieldButton : Button
{
#region Fields
public delegate void EscalationHandler(EscalationGoal escalationGoal, object sender, EventArgs e);
#endregion
#region Properties
#region FlatStyle Appearance Property
[
Category("Appearance"),
Description("Determines the appearance of the control when a user moves the mouse the mouse over the control and clicks."),
DefaultValue(typeof(FlatStyle), "System"),
ReadOnly(true),
Browsable(false)
]
public new FlatStyle FlatStyle
{
get { return base.FlatStyle; }
}
#endregion
#region AlwaysShowShield Appearance Property
private bool alwaysShowShield = false;
[
Category("Appearance"),
Description("Gets or sets if the shield icon should always be visible."),
DefaultValue(typeof(bool), "false"),
]
public bool AlwaysShowShield
{
get { return alwaysShowShield; }
set
{
alwaysShowShield = value;
if (!HasAdminPrivileges() || alwaysShowShield)
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(1));
}
else
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(0));
}
}
}
#region Serialization
private bool ShouldSerializeAlwaysShowShield()
{
return (alwaysShowShield != false);
}
private void ResetAlwaysShowShield()
{
alwaysShowShield = false;
if (HasAdminPrivileges())
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(1));
}
else
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(0));
}
}
#endregion
#endregion
#region EscalationGoal Behavior Property
private EscalationGoal escalationGoal = EscalationGoal.StartAnotherApplication;
[
Category("Behavior"),
Description("Gets or sets the EscalationGoal for this UAC \"shield\" button."),
DefaultValue(typeof(EscalationGoal), "StartAnotherApplication")
]
public EscalationGoal EscalationGoal
{
get { return escalationGoal; }
set { escalationGoal = value; }
}
#region Serialization
private bool ShouldSerializeEscalationGoal()
{
return (escalationGoal != EscalationGoal.StartAnotherApplication);
}
private void ResetEscalationGoal()
{
escalationGoal = EscalationGoal.StartAnotherApplication;
}
#endregion
#endregion
#region EscalationCustomProcessPath Behavior Property
private string escalationCustomProcessPath = String.Empty;
[
Category("Behavior"),
Description("Gets or sets the path to the application that this program starts when hit. Leave it \"\" to load the current Application.ExecutablePath."),
DefaultValue(typeof(string), "\"\""),
Editor(typeof(FilteredFileNameEditor ), typeof(UITypeEditor))
]
public string EscalationCustomProcessPath
{
get { return escalationCustomProcessPath; }
set { escalationCustomProcessPath = value; }
}
#region Serialization
private bool ShouldSerializeEscalationCustomProcessPath()
{
return (escalationCustomProcessPath != String.Empty);
}
private void ResetEscalationCustomProcessPath()
{
escalationCustomProcessPath = String.Empty;
}
#endregion
#endregion
#endregion
#region DllImports
private const uint BCM_SETSHIELD = 0x0000160C;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
#endregion
#region Constructor
public StudioShieldButton()
{
base.FlatStyle = FlatStyle.System;
AlwaysShowShield = alwaysShowShield;
}
#endregion
#region Members
public static bool HasAdminPrivileges()
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}
private ProcessStartInfo EscalationCustomProcessStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.FileName = (escalationCustomProcessPath == String.Empty) ? Application.ExecutablePath : escalationCustomProcessPath;
startInfo.Verb = "runas";
return startInfo;
}
private void AttemptPrivilegeEscalation()
{
if (HasAdminPrivileges())
throw new SecurityException("Already have administrator privileges.");
ProcessStartInfo startInfo = EscalationCustomProcessStartInfo();
OnEscalationStarting(escalationGoal, this, new EventArgs());
try
{
Process.Start(startInfo);
}
catch (System.ComponentModel.Win32Exception)
{
OnEscalationCancelled(escalationGoal, this, new EventArgs());
return;
}
OnEscalationSuccessful(escalationGoal, this, new EventArgs());
if (escalationGoal == EscalationGoal.RestartThisApplication)
Application.Exit();
}
private void OnEscalationStarting(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationStarting != null)
{
EscalationStarting(escalationGoal, sender, e);
}
}
private void OnEscalationCancelled(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationCancelled != null)
{
EscalationCancelled(escalationGoal, sender, e);
}
}
private void OnEscalationSuccessful(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationSuccessful != null)
{
EscalationSuccessful(escalationGoal, sender, e);
}
}
#endregion
#region Overrided Members
protected override void OnClick(EventArgs e)
{
if (HasAdminPrivileges())
{
if(escalationGoal == EscalationGoal.RestartThisApplication)
base.OnClick(e);
else if (escalationGoal == EscalationGoal.StartAnotherApplication)
{
ProcessStartInfo startInfo = EscalationCustomProcessStartInfo();
try
{
Process.Start(startInfo);
}
catch (System.ComponentModel.Win32Exception)
{
}
}
}
else
AttemptPrivilegeEscalation();
}
#endregion
#region Events
#region EscalationStarting Action
[Category("Action")]
[Description("A UAC privilege escalation is going to start next.")]
public event EscalationHandler EscalationStarting;
#endregion
#region EscalationCancelled Action
[Category("Action")]
[Description("The user cancelled the UAC privilege escalation prompt.")]
public event EscalationHandler EscalationCancelled;
#endregion
#region EscalationSuccessful Action
[Category("Action")]
[Description("The user was successful in getting admin privileges.")]
public event EscalationHandler EscalationSuccessful;
#endregion
#endregion
}
public enum EscalationGoal
{
RestartThisApplication,
StartAnotherApplication
}
internal class FilteredFileNameEditor : UITypeEditor
{
private OpenFileDialog ofd = new OpenFileDialog();
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
ofd.FileName = value.ToString();
ofd.Filter = "Programs|*.exe|All Files|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
return ofd.FileName;
}
return base.EditValue(context, provider, value);
}
}
}
|
|
|
|
|
I found many problems with it while refactoring... so that's all fixed.
http://wolfsfiles.googlepages.com/StudioShieldButton.cs[^]
if link is dead, here's a pasted copy:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.IO;
namespace StudioControls.Controls
{
public class StudioShieldButton : Button
{
#region Fields
public delegate void EscalationHandler(EscalationGoal escalationGoal, object sender, EventArgs e);
#endregion
#region Properties
#region FlatStyle Appearance Property
[
Category("Appearance"),
Description("Determines the appearance of the control when a user moves the mouse the mouse over the control and clicks."),
DefaultValue(typeof(FlatStyle), "System"),
ReadOnly(true),
Browsable(false)
]
public new FlatStyle FlatStyle
{
get { return base.FlatStyle; }
}
#endregion
#region AlwaysShowShield Appearance Property
private bool alwaysShowShield = false;
[
Category("Appearance"),
Description("Gets or sets if the shield icon should always be visible."),
DefaultValue(typeof(bool), "false"),
]
public bool AlwaysShowShield
{
get { return alwaysShowShield; }
set
{
alwaysShowShield = value;
if (!UACUtilities.HasAdminPrivileges() || alwaysShowShield)
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(1));
}
else
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(0));
}
}
}
#region Serialization
private bool ShouldSerializeAlwaysShowShield()
{
return (alwaysShowShield != false);
}
private void ResetAlwaysShowShield()
{
alwaysShowShield = false;
if (UACUtilities.HasAdminPrivileges())
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(1));
}
else
{
SendMessage(new HandleRef(this, this.Handle), BCM_SETSHIELD, new IntPtr(0), new IntPtr(0));
}
}
#endregion
#endregion
#region EscalationGoal Behavior Property
private EscalationGoal escalationGoal = EscalationGoal.StartAnotherApplication;
[
Category("Behavior"),
Description("Gets or sets the EscalationGoal for this UAC \"shield\" button."),
DefaultValue(typeof(EscalationGoal), "StartAnotherApplication")
]
public EscalationGoal EscalationGoal
{
get { return escalationGoal; }
set { escalationGoal = value; }
}
#region Serialization
private bool ShouldSerializeEscalationGoal()
{
return (escalationGoal != EscalationGoal.StartAnotherApplication);
}
private void ResetEscalationGoal()
{
escalationGoal = EscalationGoal.StartAnotherApplication;
}
#endregion
#endregion
#region EscalationCustomProcessPath Behavior Property
private string escalationCustomProcessPath = String.Empty;
[
Category("Behavior"),
Description("Gets or sets the path to the application that this program starts when hit. Leave it \"\" to load the current Application.ExecutablePath."),
DefaultValue(typeof(string), "\"\""),
Editor(typeof(FilteredFileNameEditor ), typeof(UITypeEditor))
]
public string EscalationCustomProcessPath
{
get { return escalationCustomProcessPath; }
set { escalationCustomProcessPath = value; }
}
#region Serialization
private bool ShouldSerializeEscalationCustomProcessPath()
{
return (escalationCustomProcessPath != String.Empty);
}
private void ResetEscalationCustomProcessPath()
{
escalationCustomProcessPath = String.Empty;
}
#endregion
#endregion
#endregion
#region DllImports
private const uint BCM_SETSHIELD = 0x0000160C;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
#endregion
#region Constructor
public StudioShieldButton()
{
base.FlatStyle = FlatStyle.System;
AlwaysShowShield = alwaysShowShield;
}
#endregion
#region Members
private string EscalationProcessPath()
{
string path;
if (escalationGoal == EscalationGoal.StartAnotherApplication)
{
if (String.IsNullOrEmpty(escalationCustomProcessPath))
throw new Exception("escalationGoal == EscalationGoal.StartAnotherApplication but escalationCustomProcessPath is null or empty.");
path = escalationCustomProcessPath;
}
else
path = Application.ExecutablePath;
return path;
}
private void OnEscalationStarting(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationStarting != null)
{
EscalationStarting(escalationGoal, sender, e);
}
}
private void OnEscalationCancelled(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationCancelled != null)
{
EscalationCancelled(escalationGoal, sender, e);
}
}
private void OnEscalationSuccessful(EscalationGoal escalationGoal, object sender, EventArgs e)
{
if (EscalationSuccessful != null)
{
EscalationSuccessful(escalationGoal, sender, e);
}
}
#endregion
#region Overrided Members
protected override void OnClick(EventArgs e)
{
if (UACUtilities.HasAdminPrivileges())
base.OnClick(e);
else
{
UACUtilities.AttemptPrivilegeEscalation(
EscalationProcessPath(),
delegate()
{
OnEscalationStarting(escalationGoal, this, new EventArgs());
},
delegate()
{
OnEscalationCancelled(escalationGoal, this, new EventArgs());
},
delegate()
{
OnEscalationSuccessful(escalationGoal, this, new EventArgs());
if (escalationGoal == EscalationGoal.RestartThisApplication)
Application.Exit();
});
}
}
#endregion
#region Events
#region EscalationStarting Action
[Category("Action")]
[Description("A UAC privilege escalation is going to start next.")]
public event EscalationHandler EscalationStarting;
#endregion
#region EscalationCancelled Action
[Category("Action")]
[Description("The user cancelled the UAC privilege escalation prompt.")]
public event EscalationHandler EscalationCancelled;
#endregion
#region EscalationSuccessful Action
[Category("Action")]
[Description("The user was successful in getting admin privileges.")]
public event EscalationHandler EscalationSuccessful;
#endregion
#endregion
}
public class UACUtilities
{
#region Fields
public delegate void EscalationEvent();
#endregion
#region Members
public static bool HasAdminPrivileges()
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}
public static ProcessStartInfo EscalationProcessStartInfo(string path)
{
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
if (!File.Exists(path))
throw new FileNotFoundException("path");
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.FileName = path;
startInfo.Verb = "runas";
return startInfo;
}
public static void AttemptPrivilegeEscalation(string path)
{
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
AttemptPrivilegeEscalation(path, null, null, null);
}
public static void AttemptPrivilegeEscalation(string path, EscalationEvent starting, EscalationEvent cancelled, EscalationEvent successful)
{
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
if (!File.Exists(path))
throw new FileNotFoundException("path");
if (HasAdminPrivileges())
throw new SecurityException("Already have administrator privileges.");
ProcessStartInfo startInfo = EscalationProcessStartInfo(path);
if(starting != null)
starting();
try
{
Process.Start(startInfo);
}
catch (System.ComponentModel.Win32Exception)
{
if(cancelled != null)
cancelled();
return;
}
if(successful != null)
successful();
}
#endregion
}
public enum EscalationGoal
{
RestartThisApplication,
StartAnotherApplication
}
internal class FilteredFileNameEditor : UITypeEditor
{
private OpenFileDialog ofd = new OpenFileDialog();
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
ofd.FileName = value.ToString();
ofd.Filter = "Programs|*.exe|All Files|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
return ofd.FileName;
}
return base.EditValue(context, provider, value);
}
}
}
|
|
|
|
|
Wow... i am sorry i dont want to offend you but posting comments like yours is way annyoing.
Dont you think it would be better to create an article here for that Control or write a Blog-Entry about your Control and just post the link instead of posting the whole code as a comment?
|
|
|
|
|
Maybe its just me but I am glad he posted what he did. It made things easier for me with him creating the class.
At least his comment was useful and helpful unlike mine and yours...
Jason
|
|
|
|
|
Dont know about other editions of Vista but for Vista Home, if you add a second user and make them a member of the administrator group..then do a builtin\Administrator check ..the IsInRole check will return false.
|
|
|
|
|
Nice article, thanks for taking the time to write it.
Firstly I just wanted to get the shield to appear so I added this part to my user control .ctor after the initialize component.
SendMessage(bt.Handle, BCM_SETSHIELD, 0, 0xFFFFFFFF);
and
[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);
however I still see the old battleship grey button.
I compiled using .NET 2, do I need to use v3?
Thanks!
|
|
|
|
|
Ah, no apparently it's the old nugget
Application.EnableVisualStyles();
which I was missing. I could have sworn (actually I will swear right now!) that the msdn docs say EnableVisualStyles() isn't needed in .NET 2 (and presumably 3?!). So is this just a Vista thing now.
Use Application.EnableVisualStyles() when using .NET 1 and XP, or any .NET and Vista. No need to use it with .NET 2 and XP.
And what about all the buggyness related to it?
Ugh, rant over, back to work(arounds).
thanks for the article.
|
|
|
|
|
It also may not work if, under Project Properties (Alt-F7)->Application
Enable Application Framework is not checked
and
Enable XP Visual Styles is not checked
I tried it on one app, and it worked fine not checked, but on another, it didn't work at all unless both were checked. Also, on the app that required both to be checked, it didn't matter if you called Application.EnableVisualStyles() in the form load or not, if those check boxes weren't checked, it just didn't work. Both apps were VB and compiled using .NET 3.5, and all other project settings were the same.
|
|
|
|
|
Nice article. What happens when you run this code on XP?
|
|
|
|
|
Tested it on xp and it works fine, just no shield thats all!
|
|
|
|
|
It works with windows 7 too!
The button shows the win7 version of the shield
Well, not a big suprise... because it's using the same API's but... it works
|
|
|
|
|
|
static internal bool IsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal p = new WindowsPrincipal(id);
return p.IsInRole(@"BUILTIN\Administrators");
}
...does not work on a danish Vista and probably not on any non-english versions of Vista, because "BUILTIN\Administrators" does not exists on these versions. In danish the admin-group is "BUILTIN\Administratorer".
Your should use the WindowsBuildInRole.Administrator enum instead:
static internal bool IsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal p = new WindowsPrincipal(id);
return p.IsInRole(WindowsBuiltInRole.Administrator);
}
This should work on any language.
Best Regards.
|
|
|
|
|
Good point . Article and code have been updated.
|
|
|
|
|