WPF Fenster im Windows Task Switcher verstecken

Eine meiner Applikationen sollte neulich parallel und ohne Benutzereingabe neben einigen Standardapplikationen (Folien, Videos, Webbrowser usw.) ihren Dienst verrichten, um vom Nutzer je nach Bedarf in den Vordergrund geholt werden zu können. Leider waren die Nutzer nicht in der Lage die ALT-Tab-Funktionalität von Windows korrekt zu nutzen und ärgerten sich lautstark (über mich), wann immer sie mit ALT-Tab auf meiner Applikation landeten anstatt auf den gewünschten Powerpoint Folien. *schnauff* Ok, also musste meine Applikation aus dem Task Switcher verschwinden. Das erwies sich als gar nicht mal so einfach.

Alle Fenster die das Flag „WS_EX_TOOLWINDOW“ besitzen, also ein „Toolwindow“ sind, werden nicht im Task-Switcher angezeigt. Allerdings besitzen sie eine Überschriftenleiste und ein „Schließen“ Symbol, was ich normalerweise in XAML explizit durch WindowStyle=None verhinderte. Ich suchte also eine Möglichkeit ein Toolwindow ohne diese Fensterdekorationen zu erzeugen. Zum Glück brachte ein Tipp aus dem StackOverflow Forum die Lösung.

Man benötigt zunächst das WindowHandle des eigenen Fensters und setzt die nötigen Flags einfach von Hand. Hierzu ist ein wenig user32.dll Magic nötig, die man jedoch einfach in die eigene View-Klasse kopieren kann.

#region Window styles
[Flags]
public enum ExtendedWindowStyles
{
	// ...
	WS_EX_TOOLWINDOW = 0x00000080,
	// ...
}

public enum GetWindowLongFields
{
	// ...
	GWL_EXSTYLE = (-20),
	// ...
}

[DllImport("user32.dll")]
public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);

public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
	int error = 0;
	IntPtr result = IntPtr.Zero;
	// Win32 SetWindowLong doesn't clear error on success
	SetLastError(0);

	if (IntPtr.Size == 4)
	{
		// use SetWindowLong
		Int32 tempResult = IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong));
		error = Marshal.GetLastWin32Error();
		result = new IntPtr(tempResult);
	}
	else
	{
		// use SetWindowLongPtr
		result = IntSetWindowLongPtr(hWnd, nIndex, dwNewLong);
		error = Marshal.GetLastWin32Error();
	}

	if ((result == IntPtr.Zero) && (error != 0))
	{
		throw new System.ComponentModel.Win32Exception(error);
	}

	return result;
}

[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
private static extern Int32 IntSetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);

private static int IntPtrToInt32(IntPtr intPtr)
{
	return unchecked((int)intPtr.ToInt64());
}

[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(int dwErrorCode);
#endregion

Die Methoden werden im WindowLoaded-Eventhandler angewandt, denn erst dort existiert das benötigte Window Handle meiner WPF Applikation. Über dieses Handle (Zeile 3) gelangen wir an den Window Style (Zeile 5) und setzen das Flag (Zeile 7) welches Windows mitteilt, dass es sich bei besagtem Fenster fortan um ein Tool Window handelt, das nicht im Task Switcher aufzutauchen braucht.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
	WindowInteropHelper wndHelper = new WindowInteropHelper(this);

	int exStyle = (int)GetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE);

	exStyle |= (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW;
	SetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
}

Kolja Engelmann

Technikfan, Freizeitprogrammierer, selbsternannter Toolking und vermutlich größter Drachenfan Deutschlands blogged hier die Lösungen zu IT-Problemen die ihm über den Weg laufen, kleine Softwaretools, nostalgische Anfälle und missbraucht das Ganze gern auch mal als privates Tagebuch und Fotoalbum.

Das könnte dich auch interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert