Best way to hide a window from the Alt-Tab program switcher?
Asked Answered
G

16

118

I've been a .NET developer for several years now and this is still one of those things I don't know how to do properly. It's easy to hide a window from the taskbar via a property in both Windows Forms and WPF, but as far as I can tell, this doesn't guarantee (or necessarily even affect) it being hidden from the Alt+↹Tab dialog. I've seen invisible windows show up in Alt+↹Tab, and I'm just wondering what is the best way to guarantee a window will never appear (visible or not) in the Alt+↹Tab dialog.

Update: Please see my posted solution below. I'm not allowed to mark my own answers as the solution, but so far it's the only one that works.

Update 2: There's now a proper solution by Franci Penov that looks pretty good, but haven't tried it out myself. Involves some Win32, but avoids the lame creation of off-screen windows.

Glantz answered 10/12, 2008 at 18:31 Comment(5)
System Tray apps are a great exampleGuyenne
I want to do it for one reason because I use a full-screen semitransparent black window to provide a "dimming" effect when my app is displaying a modal interface, kind of like the UAC dialog. Since this isn't an interactive window there's no point showing it in the Alt-Tab dialog.Glantz
I would suggest against dimming the whole desktop when your app shows its own modal dialog. Dimming the desktop suggest an OS level operation. Most people wouldn't have sofisticated enough knowledge to be able to understand it's not the secure desktop.Shrier
"It's easy to hide a window from the taskbar via a property". This property is ShowInTaskbar (just for the record).Intermediary
The question is about hiding the window from Alt-Tab, not from Taskbar.Gripping
S
110

Update: [Verified and is not working, ignore the edit]

According to @donovan, modern days WPF supports this natively, through setting ShowInTaskbar="False" and Visibility="Hidden" in the XAML. (I haven't tested this yet, but nevertheless decided to bump the comment visibility)

Original answer:

There are two ways of hiding a window from the task switcher in Win32 API:

  1. to add the WS_EX_TOOLWINDOW extended window style - that's the right approach.
  2. to make it a child window of another window.

Unfortunately, WPF does not support as flexible control over the window style as Win32, thus a window with WindowStyle=ToolWindow ends up with the default WS_CAPTION and WS_SYSMENU styles, which causes it to have a caption and a close button. On the other hand, you can remove these two styles by setting WindowStyle=None, however that will not set the WS_EX_TOOLWINDOW extended style and the window will not be hidden from the task switcher.

To have a WPF window with WindowStyle=None that is also hidden from the task switcher, one can either of two ways:

  • go with the sample code above and make the window a child window of a small hidden tool window
  • modify the window style to also include the WS_EX_TOOLWINDOW extended style.

I personally prefer the second approach. Then again, I do some advanced stuff like extending the glass in the client area and enabling WPF drawing in the caption anyway, so a little bit of interop is not a big problem.

Here's the sample code for the Win32 interop solution approach. First, the XAML part:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300"
    ShowInTaskbar="False" WindowStyle="None"
    Loaded="Window_Loaded" >

Nothing too fancy here, we just declare a window with WindowStyle=None and ShowInTaskbar=False. We also add a handler to the Loaded event where we will modify the extended window style. We can't do that work in the constructor, as there's no window handle at that point yet. The event handler itself is very simple:

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);
}

And the Win32 interop declarations. I've removed all unnecessary styles from the enums, just to keep the sample code here small. Also, unfortunately the SetWindowLongPtr entry point is not found in user32.dll on Windows XP, hence the trick with routing the call through the SetWindowLong instead.

#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
Shrier answered 15/2, 2009 at 23:36 Comment(9)
Haven't verified this but it sounds like you know what you're talking about. :) I'll keep this in mind if I need to do it again, but since my other solution is working fine (and it's been a while since I closed the book on this one) I don't want to fiddle and break something. Thanks!Glantz
Works good for me. But I hate to have to import dll like this :PBedight
@Bedight - There's nothing wrong with a bit of P/Invoke every now and then :-)Shrier
This didn't work for me in WPF. But after playing around I found a much easier solution was to set ShowInTaskbar="False" and Visibility="Hidden" in the XAML. No special pinvoke required.Zagreus
Yeah, it's quite possible that WPF has evolved some in the last six years since I've touched it. :-)Shrier
Worked for me. The tl;dr is "Add WS_EX_TOOLWINDOW to your window via P/Invoke".Cenotaph
@Zagreus For when you set the hide windows and set the element to BitmapCache that will make the WPF stop Render when user lock the screen, please see github.com/easiwin/wpf-issues/tree/master/BitmapCacheTacitus
@FranciPenov - donovan's comment is wrong. and your edit to the answer confuses people (most dont read comments).Blackthorn
Making it a child window of another window worked well for me - in my case I set the Owner to the main window (but could be a different one if required). Have posted a very simple example with code and screenshot as additional answer in case of use to anyone else.Livonia
R
52

Inside your form class, add this:

protected override CreateParams CreateParams
{
    get
    {
        var Params = base.CreateParams;
        Params.ExStyle |= WS_EX_TOOLWINDOW;
        return Params;
    }
}

It's as easy as that; works a charm!

Retrieve answered 27/7, 2013 at 2:19 Comment(3)
Also need to set ShowInTaskbar to false in order for this to work.Tanner
note: WS_EX_TOOLWINDOW = 0x00000080Irisation
This may work for a WinForms app but not for a WPF Window (as it does not have CreateParams property)Livonia
G
24

I've found a solution, but it's not pretty. So far this is the only thing I've tried that actually works:

Window w = new Window(); // Create helper window
w.Top = -100; // Location of new window is outside of visible part of screen
w.Left = -100;
w.Width = 1; // size of window is enough small to avoid its appearance at the beginning
w.Height = 1;
w.WindowStyle = WindowStyle.ToolWindow; // Set window style as ToolWindow to avoid its icon in AltTab 
w.Show(); // We need to show window before set is as owner to our main window
this.Owner = w; // Okey, this will result to disappear icon for main window.
w.Hide(); // Hide helper window just in case

Found it here.

A more general, reusable solution would be nice. I suppose you could create a single window 'w' and reuse it for all windows in your app that need to be hidden from the Alt+↹Tab.

Update: Ok so what I did was move the above code, minus the this.Owner = w bit (and moving w.Hide() immediately after w.Show(), which works fine) into my application's constructor, creating a public static Window called OwnerWindow. Whenever I want a window to exhibit this behavior, I simply set this.Owner = App.OwnerWindow. Works great, and only involves creating one extra (and invisible) window. You can even set this.Owner = null if you want the window to reappear in the Alt+↹Tab dialog.

Thanks to Ivan Onuchin over on MSDN forums for the solution.

Update 2: You should also set ShowInTaskBar=false on w to prevent it from flashing briefly in the taskbar when shown.

Glantz answered 10/12, 2008 at 21:0 Comment(5)
There's alsoa Win32 interop solution to that problem.Shrier
Interesting, I'm doing this approach but avoiding the hidden window (using the main app window as the owner), and it isn't appearing in Alt-Tab...Hadria
I think on dual-monitor configurations, the second screen can also have negative coordinates.Paillette
@ThomasW. You're probably right. Using an offset like -100000 would probably be better.Glantz
This is really a bad hack for this problem.Gripping
C
15

Here's what does the trick, regardless of the style of the window your are trying to hide from Alt+↹Tab.

Place the following into the constructor of your form:

// Keep this program out of the Alt-Tab menu

ShowInTaskbar = false;

Form form1 = new Form ( );

form1.FormBorderStyle = FormBorderStyle.FixedToolWindow;
form1.ShowInTaskbar = false;

Owner = form1;

Essentially, you make your form a child of an invisible window which has the correct style and ShowInTaskbar setting to keep out of the Alt-Tab list. You must also set your own form's ShowInTaskbar property to false. Best of all, it simply doesn't matter what style your main form has, and all tweaking to accomplish the hiding is just a few lines in the constructor code.

Climber answered 30/4, 2010 at 3:33 Comment(2)
Wait... is THIS one C# or C or C++??? I'm really a n00b at the C family or whatever...Speedometer
Best answer! Thank, man! :)Indiscreet
M
13

Why so complex? Try this:

me.FormBorderStyle = FormBorderStyle.SizableToolWindow
me.ShowInTaskbar = false

Idea taken from here:http://www.csharp411.com/hide-form-from-alttab/

Mantegna answered 23/4, 2010 at 11:35 Comment(3)
Works for me. Thanks for the contribution!Hyohyoid
But a ToolWindow can't be maximized or minimized. A ToolWindow is not always a preferable option.Gripping
This didn't work for me until I set me.Owner .Apocynthion
C
4

see it:(from http://bytes.com/topic/c-sharp/answers/442047-hide-alt-tab-list#post1683880)

[DllImport("user32.dll")]
public static extern int SetWindowLong( IntPtr window, int index, int
value);
[DllImport("user32.dll")]
public static extern int GetWindowLong( IntPtr window, int index);


const int GWL_EXSTYLE = -20;
const int WS_EX_TOOLWINDOW = 0x00000080;
const int WS_EX_APPWINDOW = 0x00040000;

private System.Windows.Forms.NotifyIcon notifyIcon1;


// I use two icons depending of the status of the app
normalIcon = new Icon(this.GetType(),"Normal.ico");
alertIcon = new Icon(this.GetType(),"Alert.ico");
notifyIcon1.Icon = normalIcon;

this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.Visible = false;
this.ShowInTaskbar = false;
iconTimer.Start();

//Make it gone frmo the ALT+TAB
int windowStyle = GetWindowLong(Handle, GWL_EXSTYLE);
SetWindowLong(Handle, GWL_EXSTYLE, windowStyle | WS_EX_TOOLWINDOW);
Copperplate answered 11/5, 2010 at 13:9 Comment(1)
I would add here that 'Handle' can be aquired by var handle = new WindowInteropHelper(this).Handle;Gripping
K
3

Why trying so much codes? Just set the FormBorderStyle propety to FixedToolWindow. Hope it helps.

Kauri answered 22/2, 2012 at 11:21 Comment(1)
The question should be split up in a)Windows Forms b)WPF FormsCa
D
2

I tried setting the main form's visibility to false whenever it is automatically changed to true:

private void Form1_VisibleChanged(object sender, EventArgs e)
{
    if (this.Visible)
    {
        this.Visible = false;
    }
}

It works perfectly :)

Dissociate answered 2/1, 2011 at 16:27 Comment(1)
Not only is by far the easiest solution, but it worked very nicely for me.Birdt
S
2

if you want the form to be borderless, then you need to add the following statements to the form’s constructor:

this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;

AND you must add the following method to your derived Form class:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        // turn on WS_EX_TOOLWINDOW style bit
        cp.ExStyle |= 0x80;
        return cp;
    }
}

more details

Salto answered 27/9, 2012 at 18:50 Comment(0)
P
1

In XAML set ShowInTaskbar="False":

<Window x:Class="WpfApplication5.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    ShowInTaskbar="False"    
    Title="Window1" Height="300" Width="300">
    <Grid>

    </Grid>
</Window>

Edit: That still shows it in Alt+Tab I guess, just not in the taskbar.

Pottle answered 10/12, 2008 at 19:25 Comment(1)
Yeah that's the problem: ShowInTaskbar doesn't affect the Alt+Tab dialog, like you might expect.Glantz
M
1

I tried This. It works for me

  private void Particular_txt_KeyPress(object sender, KeyPressEventArgs e)
    {
        Form1 frm = new Form1();         
        frm.Owner = this;
        frm.Show();
    }
Mount answered 28/1, 2021 at 13:2 Comment(0)
R
0

Don't show a form. Use invisibility.

More here: http://code.msdn.microsoft.com/TheNotifyIconExample

Ranger answered 10/12, 2008 at 18:31 Comment(0)
C
0

Solution for those who want a WPF window to stay visible while hidden from the Alt+Tab switcher:

Hide a WPF window from Alt+Tab

Checkrow answered 21/5, 2022 at 15:3 Comment(0)
L
0

The simplest way that I found to do this with WPF (although only fairly briefly tested so far) was just to set the owner to the main window within the new Window. This essentially makes the Window appear like a sort of modal dialog or overlay without it appearing in the taskbar or from alt-tab.

Example:

enter image description here

In code behind for the Window:

public partial class OverlayWindow : Window
{
    public OverlayWindow()
    {
        Owner = Application.Current.MainWindow;
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = true;
    }
}

And in the XAML for the Window:

<Window x:Class="WPFSandbox.OverlayWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             Height="200" Width="300" ShowInTaskbar="False" WindowStyle="None" WindowStartupLocation="CenterOwner">

    <!-- Window content (for test) -->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Content="Title" HorizontalAlignment="Center" Grid.Row="0"/>
        <Label Grid.Row="1" Content="Content" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <Button Content="Close" Grid.Row="2" Click="Button_Click" Width="50" HorizontalAlignment="Right" Margin="5"/>
    </Grid>
</Window>

The Window above could then be called from elsewhere simply with the standard ShowDialog() method as follows (or Show() if not treating as a dialog):

private void Button_Click(object sender, RoutedEventArgs e)
{
    var result = new OverlayWindow().ShowDialog();

    // Do something with result if required
}

With the example above in a very basic test app, this should appear something like this:

enter image description here

Livonia answered 11/8, 2023 at 10:11 Comment(0)
A
-1

Personally as far as I know this is not possible without hooking into windows in some fashion, I'm not even sure how that would be done or if it is possible.

Depending on your needs, developing your application context as a NotifyIcon (system tray) application will allow it to be running without showing in ALT + TAB. HOWEVER, if you open a form, that form will still follow the standard functionality.

I can dig up my blog article about creating an application that is ONLY a NotifyIcon by default if you want.

Asci answered 10/12, 2008 at 19:2 Comment(3)
you mean this one? mitchelsellers.com/blogs/articletype/articleview/articleid/…Dulce
I'm already well-versed in NotifyIcons, thanks. The problem is I want to hide open (non-interactive, or topmost) windows from Alt+Tab. Interestingly, I just noticed that the Vista sidebar does not appear in Alt+Tab, so there must be SOME way to do it.Glantz
Looking at the various bits and pieces, without changing the type of window (as redbeard posted), I do not know of a way to do this.Asci
M
-1

Form1 Properties:
FormBorderStyle: Sizable
WindowState: Minimized
ShowInTaskbar: False

private void Form1_Load(object sender, EventArgs e)
{
   // Making the window invisible forces it to not show up in the ALT+TAB
   this.Visible = false;
}>
Moonseed answered 23/4, 2009 at 20:38 Comment(1)
Setting WindowState property to Minimized would mean the form doesn't show up at all. How in the world would anyone use such a form.Cb

© 2022 - 2024 — McMap. All rights reserved.