
8 September 2008, 20:16 von
klaus_b2460 mal gelesen.Wer hat es nicht schon oft gesehen wenn irgendeine administrative Aufgabe unter Vista erledigt werden soll: das VistaShield. Wenn die eigene Anwendung eine Bestätigung des Benutzer einholen soll, ist das Darstellen des VistaShield auf dem auslösenden Button Pflicht. Doch wie bekomme ich dieses ominöse Symbol auf meinen Button?
Die meisten Ansätze, inklusive der Dokumentation zum Windows SDK, verwenden SendMessage der Win32-API. Da ich das VistaShield nicht nur auf Buttons verwenden möchte, sondern auch z.B. in einem Menü oder einfach in einem Dialog, habe ich nach einer anderen Möglichkeit gesucht.
Um das Symbol überhaupt irgendwo darstellen zu können, muss man es erst einmal haben. Es ist in der user32.dll als Icon in verschiedenen Größen vorhanden. Um auf die Größen 16x16 und 32x32 zugreifen zu können, verwende ich die Funktion ExtraxtIconEx aus der user32.dll.
[DllImport("shell32.dll", EntryPoint = "ExtractIconExW",
CallingConvention = CallingConvention.StdCall)]
public static extern int ExtractIconEx(
[In]
[MarshalAsAttribute(UnmanagedType.LPWStr)]
string lpszFile,
int nIconIndex,
ref IntPtr phiconLarge,
ref IntPtr phiconSmall,
int nIcons);Wie die Dokumentation schon sagt, werden Zeiger sowohl auf die kleine als auch auf die große Version eines Icons referenziert. Zurückgegeben wird die Anzahl der referenzierten Icons. Das ganze wird jetzt in eine Methode verpackt die wahlweise das große oder kleine Symbol zurückgibt. Man muss nur den Index des Symbols in der Datei kennen. Im falle des VistaShield in der user32.dll befindet sich dieses unter Index 6.
private static Image GetVistaShield(bool smallIcon)
{
int icoIdx = 6;
Image img = null;
Icon icon = null;
IntPtr iconLargePtr = IntPtr.Zero;
IntPtr iconSmallPtr = IntPtr.Zero;
string path = Environment.GetFolderPath(Environment.SpecialFolder.System) + Path.DirectorySeparatorChar + "user32.dll";
try
{
int result = NativeMethods.ExtractIconEx(
path,
icoIdx,
ref iconLargePtr,
ref iconSmallPtr,
1);
if (result < 1)
{
return null;
}
if (smallIcon && iconSmallPtr != IntPtr.Zero)
{
icon = Icon.FromHandle(iconSmallPtr);
}
else if (iconLargePtr != IntPtr.Zero)
{
icon = Icon.FromHandle(iconLargePtr);
}
else
{
return null;
}
img = (Image)icon.ToBitmap();
}
catch (Win32Exception)
{
return null;
}
finally
{
iconLargePtr = IntPtr.Zero;
iconSmallPtr = IntPtr.Zero;
}
return img;
}Um das ganze schön in einer Klasse zu handeln, wird die Methode von zwei Eigenschaften maskiert.
public static Image SmallVistaShield
{
get { return UacManager.GetVistaShield(true); }
}
public static Image LargeVistaShield
{
get { return UacManager.GetVistaShield(false); }
}Jetzt muss nur noch einen Methode her, die das VistaShield direkt auf einem Button darstellt. Die halbe Arbeit ist vom .NET-Framework mit der Eigenschaft Image der Button-Klasse schon erledigt. Also warum soll dies Eigenschaft nicht verwendet werden?
public static void SetShieldOnButton(Control ctrl, bool smallIcon)
{
Button btn = (Button)ctrl;
if (smallIcon)
{
btn.Image = UacManager.SmallVistaShield;
}
else
{
btn.Image = UacManager.LargeVistaShield;
}
btn.TextImageRelation = TextImageRelation.ImageBeforeText;
}Angenommen die beschriebenen Methoden sind in einer Klasse namens UacManager enthalten, kann auf jedem beliebigen Button aus einer Form das Vistashield dargestellt werden.
if (this.onVista)
{
UacManager.SetShieldOnButton(this.buttonEndProcess, true);
}Hier ein Screenshot der beschriebenen Methode.

Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitte "kicken" sie ihn.
