Le meilleur moyen de masquer une fenêtre du sélecteur de programme Alt-Tab?

101

Je suis développeur .NET depuis plusieurs années maintenant et c'est toujours une de ces choses que je ne sais pas faire correctement. Il est facile de masquer une fenêtre de la barre des tâches via une propriété dans Windows Forms et WPF, mais pour autant que je sache, cela ne garantit pas (ou n'affecte pas nécessairement) qu'elle soit cachée de la boîte de dialogue Alt+ ↹Tab. J'ai vu des fenêtres invisibles apparaître dans Alt+ ↹Tab, et je me demande simplement quel est le meilleur moyen de garantir qu'une fenêtre n'apparaîtra jamais (visible ou non) dans la boîte de dialogue Alt+ ↹Tab.

Mise à jour: veuillez voir ma solution publiée ci-dessous. Je ne suis pas autorisé à marquer mes propres réponses comme la solution, mais jusqu'à présent, c'est la seule qui fonctionne.

Mise à jour 2: Il existe maintenant une solution appropriée de Franci Penov qui semble plutôt bonne, mais je ne l'ai pas essayée moi-même. Implique certains Win32, mais évite la création boiteuse de fenêtres hors écran.

devios1
la source
13
Les applications de la
barre d'état
3
Je veux le faire pour une raison parce que j'utilise une fenêtre noire semi-transparente en plein écran pour fournir un effet de «gradation» lorsque mon application affiche une interface modale, un peu comme la boîte de dialogue UAC. Comme ce n'est pas une fenêtre interactive, il ne sert à rien de l'afficher dans la boîte de dialogue Alt-Tab.
devios1
8
Je suggérerais de ne pas assombrir tout le bureau lorsque votre application affiche sa propre boîte de dialogue modale. La gradation du bureau suggère une opération au niveau du système d'exploitation. La plupart des gens n'auraient pas de connaissances suffisamment sophistiquées pour comprendre que ce n'est pas le bureau sécurisé.
Franci Penov
3
"Il est facile de masquer une fenêtre de la barre des tâches via une propriété". Cette propriété est ShowInTaskbar (juste pour l'enregistrement).
greenoldman
La question est de cacher la fenêtre de Alt-Tab, pas de la barre des tâches.
Alexandru Dicu le

Réponses:

94

Mettre à jour:

Selon @donovan, WPF moderne prend en charge cela de manière native, via la configuration ShowInTaskbar="False"et Visibility="Hidden"dans le XAML. (Je n'ai pas encore testé cela, mais j'ai néanmoins décidé d'augmenter la visibilité des commentaires)

Réponse originale:

Il existe deux façons de masquer une fenêtre du sélecteur de tâches dans l'API Win32:

  1. pour ajouter le WS_EX_TOOLWINDOWstyle de fenêtre étendu - c'est la bonne approche.
  2. pour en faire une fenêtre enfant d'une autre fenêtre.

Malheureusement, WPF ne prend pas en charge un contrôle aussi flexible sur le style de fenêtre que Win32, donc une fenêtre avec WindowStyle=ToolWindowse termine avec la valeur par défaut WS_CAPTIONet les WS_SYSMENUstyles, ce qui lui donne une légende et un bouton de fermeture. D'un autre côté, vous pouvez supprimer ces deux styles en définissant WindowStyle=None, mais cela ne définira pas le WS_EX_TOOLWINDOWstyle étendu et la fenêtre ne sera pas masquée du sélecteur de tâches.

Pour avoir une fenêtre WPF avec WindowStyle=Nonequi est également masquée dans le sélecteur de tâches, vous pouvez de deux manières:

  • allez avec l'exemple de code ci-dessus et faites de la fenêtre une fenêtre enfant d'une petite fenêtre d'outils cachée
  • modifiez le style de fenêtre pour inclure également le WS_EX_TOOLWINDOWstyle étendu.

Personnellement, je préfère la deuxième approche. Là encore, je fais des choses avancées comme étendre la vitre dans la zone client et activer le dessin WPF dans la légende de toute façon, donc un peu d'interopérabilité n'est pas un gros problème.

Voici l'exemple de code pour l'approche de solution d'interopérabilité Win32. Tout d'abord, la partie 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" >

Rien d'extraordinaire ici, nous déclarons simplement une fenêtre avec WindowStyle=Noneet ShowInTaskbar=False. Nous ajoutons également un gestionnaire à l'événement Loaded où nous modifierons le style de fenêtre étendu. Nous ne pouvons pas faire ce travail dans le constructeur, car il n'y a pas encore de handle de fenêtre à ce stade. Le gestionnaire d'événements lui-même est très 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);
}

Et les déclarations d'interopérabilité Win32. J'ai supprimé tous les styles inutiles des énumérations, juste pour garder l'exemple de code ici petit. De plus, malheureusement, le SetWindowLongPtrpoint d'entrée ne se trouve pas dans user32.dll sous Windows XP, d'où l'astuce consistant à acheminer l'appel via le 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
la source
2
Je n'ai pas vérifié cela, mais il semble que vous savez de quoi vous parlez. :) Je garderai cela à l'esprit si je dois le refaire, mais comme mon autre solution fonctionne bien (et cela fait un moment que j'ai fermé le livre sur celle-ci), je ne veux pas tripoter et casser quelque chose . Merci!
devios1
1
Fonctionne parfaitement! Merci!
Anthony Brien
Fonctionne bien pour moi. Mais je déteste avoir à importer des dll comme ceci: P
J4N
8
@ J4N - Il n'y a rien de mal avec un peu de P / Invoke de temps en temps :-)
Franci Penov
1
Cela n'a pas fonctionné pour moi dans WPF. Mais après avoir joué, j'ai trouvé qu'une solution beaucoup plus simple était de définir ShowInTaskbar = "False" et Visibility = "Hidden" dans le XAML. Aucun pinvoke spécial requis.
donovan
40

Dans votre classe de formulaire, ajoutez ceci:

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

        return Params;
    }
}

C'est aussi simple que ça; fonctionne un charme!

Danny Beckett
la source
3
Vous devez également définir ShowInTaskbar sur false pour que cela fonctionne.
Nick Spreitzer
20

J'ai trouvé une solution, mais ce n'est pas joli. Jusqu'à présent, c'est la seule chose que j'ai essayée qui fonctionne réellement:

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

Je l'ai trouvé ici .

Une solution plus générale et réutilisable serait bien. Je suppose que vous pouvez créer une seule fenêtre «w» et la réutiliser pour toutes les fenêtres de votre application qui doivent être masquées par le Alt+ ↹Tab.

Mise à jour: Ok, donc ce que j'ai fait a été de déplacer le code ci-dessus, moins le this.Owner = wbit (et de le déplacer w.Hide()immédiatement après w.Show(), ce qui fonctionne bien) dans le constructeur de mon application, en créant une statique publique WindowappeléeOwnerWindow . Chaque fois que je veux qu'une fenêtre présente ce comportement, je définis simplement this.Owner = App.OwnerWindow. Fonctionne très bien et n'implique que la création d'une fenêtre supplémentaire (et invisible). Vous pouvez même définir this.Owner = nullsi vous souhaitez que la fenêtre réapparaisse dans la boîte de dialogue Alt+ ↹Tab.

Merci à Ivan Onuchin sur les forums MSDN pour la solution.

Mise à jour 2: Vous devriez également mettre ShowInTaskBar=falsesur wpour l' empêcher de clignoter brièvement dans la barre des tâches lorsque indiqué.

devios1
la source
Il existe également une solution d'interopérabilité Win32 à ce problème.
Franci Penov
Intéressant, je fais cette approche mais en évitant la fenêtre cachée (en utilisant la fenêtre principale de l'application en tant que propriétaire), et elle n'apparaît pas dans Alt-Tab ...
Dave
1
Je pense que sur les configurations à deux moniteurs, le deuxième écran peut également avoir des coordonnées négatives.
Thomas Weller
@ThomasW. Tu as probablement raison. Utiliser un offset comme ce -100000serait probablement mieux.
devios1
C'est vraiment un mauvais hack pour ce problème.
Alexandru Dicu le
10

Pourquoi si complexe? Essaye ça:

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

Idée tirée d'ici: http://www.csharp411.com/hide-form-from-alttab/

Andreï
la source
Travaille pour moi. Merci pour la contribution!
MiBol le
Mais un ToolWindow ne peut pas être maximisé ou minimisé. Une ToolWindow n'est pas toujours une option préférable.
Alexandru Dicu le
10

Voici ce qui fait l'affaire, quel que soit le style de la fenêtre à laquelle vous essayez de vous cacher Alt+ ↹Tab.

Placez ce qui suit dans le constructeur de votre formulaire:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Essentiellement, vous faites de votre formulaire un enfant d'une fenêtre invisible qui a le style et le paramètre ShowInTaskbar corrects pour rester en dehors de la liste Alt-Tab. Vous devez également définir la propriété ShowInTaskbar de votre propre formulaire sur false. Mieux encore, peu importe le style de votre formulaire principal, et toutes les modifications pour accomplir le masquage ne sont que quelques lignes dans le code du constructeur.

Matt Hendricks
la source
Attendez ... est-ce un C # ou C ou C ++ ??? Je suis vraiment un n00b dans la famille C ou autre chose ...
Sreenikethan I
3

Pourquoi essayer autant de codes? FormBorderStyleRéglez simplement la propriété sur FixedToolWindow. J'espère que ça aide.

Saravanakumar. N
la source
2

voir: (depuis 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
la source
J'ajouterais ici que 'Handle' peut être acquis par var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu
1

En XAML, définissez 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: Cela le montre toujours dans Alt + Tab, je suppose, mais pas dans la barre des tâches.

Philipp Schmid
la source
Ouais, c'est le problème: ShowInTaskbar n'affecte pas la boîte de dialogue Alt + Tab, comme vous pouvez vous y attendre.
devios1
1

J'ai essayé de définir la visibilité du formulaire principal sur false chaque fois qu'il est automatiquement changé en true:

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

Cela fonctionne parfaitement :)

Tiendan
la source
2
Non seulement c'est de loin la solution la plus simple, mais cela a très bien fonctionné pour moi.
Daniel McQuiston
1

si vous souhaitez que le formulaire soit sans bordure, vous devez ajouter les instructions suivantes au constructeur du formulaire:

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

ET vous devez ajouter la méthode suivante à votre classe Form dérivée:

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

plus de détails

Hossein Moradinia
la source
0

Propriétés Form1:
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;
}>
Sels de Charlie
la source
-1

Personnellement, pour autant que je sache, cela n'est pas possible sans accrocher les fenêtres d'une manière ou d'une autre, je ne sais même pas comment cela serait fait ou si cela est possible.

Selon vos besoins, le développement de votre contexte d'application en tant qu'application NotifyIcon (barre d'état système) lui permettra de s'exécuter sans s'afficher dans ALT + TAB. CEPENDANT, si vous ouvrez un formulaire, ce formulaire suivra toujours la fonctionnalité standard.

Je peux consulter mon article de blog sur la création d'une application qui est UNIQUEMENT un NotifyIcon par défaut si vous le souhaitez.

Vendeurs Mitchel
la source
Je connais déjà bien NotifyIcons, merci. Le problème est que je souhaite masquer les fenêtres ouvertes (non interactives ou les plus en haut) de Alt + Tab. Fait intéressant, je viens de remarquer que la barre latérale de Vista n'apparaît pas dans Alt + Tab, il doit donc y avoir un moyen de le faire.
devios1
En regardant les différents morceaux, sans changer le type de fenêtre (comme Redbeard l'a posté), je ne connais pas de moyen de le faire.
Mitchel Sellers