¿La mejor manera de ocultar una ventana del conmutador de programas Alt-Tab?

101

He sido desarrollador de .NET durante varios años y esta sigue siendo una de esas cosas que no sé cómo hacer correctamente. Es fácil ocultar una ventana de la barra de tareas a través de una propiedad tanto en Windows Forms como en WPF, pero por lo que puedo decir, esto no garantiza (ni necesariamente afecta) que se oculte del cuadro de diálogo Alt+ ↹Tab. He visto aparecer ventanas invisibles en Alt+ ↹Tab, y me pregunto cuál es la mejor manera de garantizar que una ventana nunca aparecerá (visible o no) en el cuadro de diálogo Alt+ ↹Tab.

Actualización: consulte mi solución publicada a continuación. No puedo marcar mis propias respuestas como la solución, pero hasta ahora es la única que funciona.

Actualización 2: Ahora hay una solución adecuada de Franci Penov que se ve bastante bien, pero no la he probado yo mismo. Incluye algo de Win32, pero evita la creación poco convincente de ventanas fuera de la pantalla.

devios1
fuente
13
Las aplicaciones de la bandeja del sistema son un gran ejemplo
TravisO
3
Quiero hacerlo por una razón porque utilizo una ventana negra semitransparente de pantalla completa para proporcionar un efecto de "atenuación" cuando mi aplicación muestra una interfaz modal, algo así como el cuadro de diálogo UAC. Dado que esta no es una ventana interactiva, no tiene sentido mostrarla en el cuadro de diálogo Alt-Tab.
devios1
8
Sugeriría no atenuar todo el escritorio cuando su aplicación muestra su propio diálogo modal. Atenuar el escritorio sugiere una operación a nivel de sistema operativo. La mayoría de la gente no tendría un conocimiento lo suficientemente sofisticado como para poder entender que no es un escritorio seguro.
Franci Penov
3
"Es fácil ocultar una ventana de la barra de tareas a través de una propiedad". Esta propiedad es ShowInTaskbar (solo para el registro).
greenoldman
La pregunta es sobre cómo ocultar la ventana de Alt-Tab, no de la barra de tareas.
Alexandru Dicu

Respuestas:

93

Actualizar:

Según @donovan, en la actualidad WPF admite esto de forma nativa, a través de la configuración ShowInTaskbar="False"y Visibility="Hidden"en el XAML. (No he probado esto todavía, pero sin embargo decidí aumentar la visibilidad de los comentarios)

Respuesta original:

Hay dos formas de ocultar una ventana del conmutador de tareas en la API de Win32:

  1. para agregar el WS_EX_TOOLWINDOWestilo de ventana extendida, ese es el enfoque correcto.
  2. para convertirla en una ventana secundaria de otra ventana.

Desafortunadamente, WPF no admite un control tan flexible sobre el estilo de la ventana como Win32, por lo que una ventana WindowStyle=ToolWindowtermina con los estilos WS_CAPTIONy predeterminados WS_SYSMENU, lo que hace que tenga un título y un botón de cierre. Por otro lado, puede eliminar estos dos estilos configurando WindowStyle=None, sin embargo, eso no establecerá el WS_EX_TOOLWINDOWestilo extendido y la ventana no se ocultará del selector de tareas.

Para tener una ventana de WPF WindowStyle=Noneque también esté oculta en el selector de tareas, se puede de dos maneras:

  • vaya con el código de muestra anterior y convierta la ventana en una ventana secundaria de una pequeña ventana de herramientas oculta
  • modifique el estilo de la ventana para incluir también el WS_EX_TOOLWINDOWestilo extendido.

Personalmente prefiero el segundo enfoque. Por otra parte, hago algunas cosas avanzadas como extender el cristal en el área del cliente y habilitar el dibujo de WPF en el título de todos modos, por lo que un poco de interoperabilidad no es un gran problema.

Aquí está el código de muestra para el enfoque de la solución de interoperabilidad de Win32. Primero, la parte XAML:

<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" >

Nada demasiado sofisticado aquí, solo declaramos una ventana con WindowStyle=Noney ShowInTaskbar=False. También agregamos un controlador al evento Loaded donde modificaremos el estilo de la ventana extendida. No podemos hacer ese trabajo en el constructor, ya que todavía no hay un identificador de ventana en ese punto. El controlador de eventos en sí es muy 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);
}

Y las declaraciones de interoperabilidad de Win32. He eliminado todos los estilos innecesarios de las enumeraciones, solo para mantener pequeño el código de muestra aquí. Además, desafortunadamente, el SetWindowLongPtrpunto de entrada no se encuentra en user32.dll en Windows XP, de ahí el truco de enrutar la llamada a través de SetWindowLong.

#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
Franci Penov
fuente
2
No lo he verificado, pero parece que sabe de lo que está hablando. :) Tendré esto en cuenta si necesito hacerlo de nuevo, pero como mi otra solución está funcionando bien (y ha pasado un tiempo desde que cerré el libro sobre esta) no quiero jugar y romper algo . ¡Gracias!
devios1
1
¡Funciona perfectamente! ¡Gracias!
Anthony Brien
Funciona bien para mi. Pero odio tener que importar dll como este: P
J4N
8
@ J4N - No hay nada de malo con un poco de P / Invoke de vez en cuando :-)
Franci Penov
1
Esto no funcionó para mí en WPF. Pero después de jugar, encontré que una solución mucho más fácil era establecer ShowInTaskbar = "False" y Visibility = "Hidden" en el XAML. No se requiere un pinvoke especial.
donovan
40

Dentro de su clase de formulario, agregue esto:

protected override CreateParams CreateParams
{
    get
    {
        var Params = base.CreateParams;
        Params.ExStyle |= 0x80;

        return Params;
    }
}

Es tan fácil como eso; funciona de maravilla!

Danny Beckett
fuente
3
También es necesario establecer ShowInTaskbar en falso para que esto funcione.
Nick Spreitzer
20

Encontré una solución, pero no es bonita. Hasta ahora, esto es lo único que he probado que realmente funciona:

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

Lo encontré aquí .

Una solución reutilizable más general estaría bien. Supongo que podría crear una sola ventana 'w' y reutilizarla para todas las ventanas de su aplicación que deben ocultarse del signo Alt+ ↹Tab.

Actualización: Ok, entonces lo que hice fue mover el código anterior, menos el this.Owner = wbit (y mover w.Hide()inmediatamente después w.Show(), que funciona bien) en el constructor de mi aplicación, creando una estática pública Windowllamada OwnerWindow. Siempre que quiero que una ventana muestre este comportamiento, simplemente configuro this.Owner = App.OwnerWindow. Funciona muy bien y solo implica la creación de una ventana adicional (e invisible). Incluso puede establecer this.Owner = nullsi desea que la ventana vuelva a aparecer en el cuadro de diálogo Alt+ ↹Tab.

Gracias a Ivan Onuchin en los foros de MSDN por la solución.

Actualización 2: Usted también debe establecer ShowInTaskBar=falseen wpara evitar que parpadear brevemente en la barra de tareas cuando se muestra.

devios1
fuente
También hay una solución de interoperabilidad Win32 para ese problema.
Franci Penov
Interesante, estoy haciendo este enfoque pero evitando la ventana oculta (usando la ventana principal de la aplicación como propietario), y no aparece en Alt-Tab ...
Dave
1
Creo que en las configuraciones de dos monitores, la segunda pantalla también puede tener coordenadas negativas.
Thomas Weller
@ThomasW. Probablemente tengas razón. -100000Probablemente sería mejor usar un desplazamiento como .
devios1
Este es realmente un mal truco para este problema.
Alexandru Dicu
10

¿Por qué tan complejo? Prueba esto:

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

Idea tomada de aquí: http://www.csharp411.com/hide-form-from-alttab/

Andrey
fuente
Funciona para mi. ¡Gracias por la contribución!
MiBol
Pero una ToolWindow no se puede maximizar ni minimizar. Una ventana de herramientas no siempre es una opción preferible.
Alexandru Dicu
10

Esto es lo que hace el truco, independientemente del estilo de la ventana de la que intentas esconderte Alt+ ↹Tab.

Coloque lo siguiente en el constructor de su formulario:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Esencialmente, convierte su formulario en un elemento secundario de una ventana invisible que tiene el estilo correcto y la configuración ShowInTaskbar para mantenerse fuera de la lista Alt-Tab. También debe establecer la propiedad ShowInTaskbar de su propio formulario en falso. Lo mejor de todo es que simplemente no importa qué estilo tenga su formulario principal, y todos los ajustes para lograr la ocultación son solo unas pocas líneas en el código del constructor.

Matt Hendricks
fuente
Espera ... ¿ES ESTE C # o C o C ++ ??? Realmente soy un n00b en la familia C o lo que sea ...
Sreenikethan I
3

¿Por qué probar tantos códigos? Simplemente configure la FormBorderStylepropiedad en FixedToolWindow. Espero eso ayude.

Saravanakumar. norte
fuente
2

verlo: (de 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);
Behnam Shomali
fuente
Agregaría aquí que 'Handle' puede ser adquirido por var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu
1

En XAML, establezca 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>

Editar: Eso todavía lo muestra en Alt + Tab, supongo, pero no en la barra de tareas.

Philipp Schmid
fuente
Sí, ese es el problema: ShowInTaskbar no afecta el cuadro de diálogo Alt + Tab, como es de esperar.
devios1
1

Intenté configurar la visibilidad del formulario principal en falso cada vez que se cambia automáticamente a verdadero:

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

Funciona perfectamente :)

tiendan
fuente
2
No solo es, con mucho, la solución más fácil, sino que funcionó muy bien para mí.
Daniel McQuiston
1

si desea que el formulario no tenga bordes, debe agregar las siguientes declaraciones al constructor del formulario:

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

Y debe agregar el siguiente método a su clase de formulario derivada:

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

más detalles

Hossein Moradinia
fuente
0

Propiedades de Form1:
FormBorderStyle: Sizable
WindowState: Minimizado
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;
}>
Sales de Charlie
fuente
-1

Personalmente, hasta donde yo sé, esto no es posible sin engancharlo a las ventanas de alguna manera, ni siquiera estoy seguro de cómo se haría o si es posible.

Dependiendo de sus necesidades, desarrollar el contexto de su aplicación como una aplicación NotifyIcon (bandeja del sistema) permitirá que se ejecute sin mostrarse en ALT + TAB. SIN EMBARGO, si abre un formulario, ese formulario seguirá la funcionalidad estándar.

Puedo indagar en el artículo de mi blog sobre la creación de una aplicación que SÓLO es un NotifyIcon por defecto si lo desea.

Vendedores de Mitchel
fuente
Ya soy un experto en NotifyIcons, gracias. El problema es que quiero ocultar las ventanas abiertas (no interactivas o superiores) desde Alt + Tab. Curiosamente, acabo de notar que la barra lateral de Vista no aparece en Alt + Tab, por lo que debe haber ALGUNA forma de hacerlo.
devios1
Mirando las diversas partes y piezas, sin cambiar el tipo de ventana (como publicó Redbeard), no conozco una forma de hacerlo.
Mitchel Sellers