Il modo migliore per nascondere una finestra dal selettore di programmi Alt-Tab?


101

Sono uno sviluppatore .NET da diversi anni ormai e questa è ancora una di quelle cose che non so come fare correttamente. È facile nascondere una finestra dalla barra delle applicazioni tramite una proprietà sia in Windows Form che in WPF, ma per quanto ne so, questo non garantisce (o necessariamente influisce) che sia nascosto dalla finestra di dialogo Alt+ ↹Tab. Ho visto finestre invisibili apparire in Alt+ ↹Tabe mi chiedo solo qual è il modo migliore per garantire che una finestra non apparirà mai (visibile o meno) nella finestra di dialogo Alt+ ↹Tab.

Aggiornamento: vedere la mia soluzione pubblicata di seguito. Non sono autorizzato a contrassegnare le mie risposte come la soluzione, ma finora è l'unica che funziona.

Aggiornamento 2: ora c'è una soluzione adeguata di Franci Penov che sembra abbastanza buona, ma non l'ho provata io stesso. Coinvolge un po 'di Win32, ma evita la creazione di finestre fuori schermo.


13
Le app della barra delle applicazioni sono un ottimo esempio
TravisO

3
Voglio farlo per un motivo perché utilizzo una finestra nera semitrasparente a schermo intero per fornire un effetto di "attenuazione" quando la mia app visualizza un'interfaccia modale, un po 'come la finestra di dialogo UAC. Poiché questa non è una finestra interattiva, non ha senso mostrarla nella finestra di dialogo Alt-Tab.
devios1

8
Suggerirei di non oscurare l'intero desktop quando l'app mostra la propria finestra di dialogo modale. L'oscuramento del desktop suggerisce un'operazione a livello di sistema operativo. La maggior parte delle persone non avrebbe una conoscenza abbastanza sofisticata per essere in grado di capire che non è il desktop sicuro.
Franci Penov

3
"È facile nascondere una finestra dalla barra delle applicazioni tramite una proprietà". Questa proprietà è ShowInTaskbar (solo per la cronaca).
greenoldman

La domanda riguarda nascondere la finestra da Alt-Tab, non dalla barra delle applicazioni.
Alexandru Dicu

Risposte:


93

Aggiornare:

Secondo @donovan, i giorni nostri WPF lo supporta in modo nativo, tramite l'impostazione ShowInTaskbar="False"e Visibility="Hidden"nel XAML. (Non l'ho ancora testato, ma ho comunque deciso di aumentare la visibilità dei commenti)

Risposta originale:

Esistono due modi per nascondere una finestra dal selettore di attività nell'API Win32:

  1. per aggiungere lo WS_EX_TOOLWINDOWstile della finestra estesa: questo è l'approccio giusto.
  2. per renderlo una finestra figlia di un'altra finestra.

Sfortunatamente, WPF non supporta un controllo flessibile sullo stile della finestra come Win32, quindi una finestra con WindowStyle=ToolWindowfinisce con l'impostazione predefinita WS_CAPTIONe gli WS_SYSMENUstili, il che fa sì che abbia una didascalia e un pulsante di chiusura. D'altra parte, puoi rimuovere questi due stili impostando WindowStyle=None, tuttavia ciò non imposterà lo WS_EX_TOOLWINDOWstile esteso e la finestra non sarà nascosta dal selettore di attività.

Per avere una finestra WPF con WindowStyle=Noneche è anche nascosta dal selettore di attività, si può in due modi:

  • vai con il codice di esempio sopra e rendi la finestra una finestra figlia di una piccola finestra degli strumenti nascosta
  • modificare lo stile della finestra per includere anche lo WS_EX_TOOLWINDOWstile esteso.

Personalmente preferisco il secondo approccio. Poi di nuovo, eseguo alcune cose avanzate come estendere il vetro nell'area client e abilitare comunque il disegno WPF nella didascalia, quindi un po 'di interoperabilità non è un grosso problema.

Ecco il codice di esempio per l'approccio alla soluzione di interoperabilità Win32. Innanzitutto, 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" >

Niente di speciale qui, dichiariamo solo una finestra con WindowStyle=Nonee ShowInTaskbar=False. Aggiungiamo anche un gestore all'evento Loaded dove modificheremo lo stile della finestra estesa. Non possiamo fare quel lavoro nel costruttore, poiché non ci sono ancora handle di finestra a quel punto. Il gestore di eventi stesso è molto semplice:

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

E le dichiarazioni di interoperabilità Win32. Ho rimosso tutti gli stili non necessari dalle enumerazioni, solo per mantenere piccolo il codice di esempio. Inoltre, sfortunatamente il SetWindowLongPtrpunto di ingresso non si trova in user32.dll su Windows XP, da qui il trucco con l'instradamento della chiamata attraverso SetWindowLonginvece.

#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

2
Non l'ho verificato, ma sembra che tu sappia di cosa stai parlando. :) Lo terrò a mente se avrò bisogno di farlo di nuovo, ma poiché l'altra mia soluzione funziona bene (ed è passato un po 'di tempo da quando ho chiuso il libro su questa) non voglio giocherellare e rompere qualcosa . Grazie!
devios1

1
Funziona perfettamente! Grazie!
Anthony Brien

Funziona bene per me. Ma odio dover importare dll in questo modo: P
J4N

8
@ J4N - Non c'è niente di sbagliato in un po 'di P / Invoke ogni tanto :-)
Franci Penov

1
Questo non ha funzionato per me in WPF. Ma dopo aver giocato ho scoperto che una soluzione molto più semplice era impostare ShowInTaskbar = "False" e Visibility = "Hidden" in XAML. Nessun pinvoke speciale richiesto.
donovan

40

All'interno della classe del modulo, aggiungi questo:

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

        return Params;
    }
}

È così facile; funziona un fascino!


3
È inoltre necessario impostare ShowInTaskbar su false affinché funzioni.
Nick Spreitzer

20

Ho trovato una soluzione, ma non è carina. Finora questa è l' unica cosa che ho provato che funziona davvero:

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

L'ho trovato qui .

Sarebbe utile una soluzione più generale e riutilizzabile. Suppongo che potresti creare una singola finestra "w" e riutilizzarla per tutte le finestre della tua app che devono essere nascoste dal Alt+ ↹Tab.

Aggiornamento: Ok, quello che ho fatto è stato spostare il codice sopra, meno il this.Owner = wbit (e spostarlo w.Hide()immediatamente dopo w.Show(), il che funziona bene) nel costruttore della mia applicazione, creando una statica pubblica Windowchiamata OwnerWindow. Ogni volta che voglio che una finestra mostri questo comportamento, mi limito a impostare this.Owner = App.OwnerWindow. Funziona alla grande e implica solo la creazione di una finestra aggiuntiva (e invisibile). Puoi anche impostare this.Owner = nullse desideri che la finestra venga visualizzata nuovamente nella finestra di dialogo Alt+ ↹Tab.

Grazie a Ivan Onuchin sui forum MSDN per la soluzione.

Update 2: Si dovrebbe anche impostare ShowInTaskBar=falsesu wper evitare che a lampeggiare brevemente nella barra delle applicazioni quando indicato.


C'è anche una soluzione di interoperabilità Win32 a questo problema.
Franci Penov

Interessante, sto eseguendo questo approccio ma evito la finestra nascosta (utilizzando la finestra principale dell'app come proprietario) e non viene visualizzata in Alt-Tab ...
Dave

1
Penso che nelle configurazioni a doppio monitor, il secondo schermo possa anche avere coordinate negative.
Thomas Weller

@ThomasW. Probabilmente hai ragione. -100000Probabilmente sarebbe meglio usare un offset come .
devios1

Questo è davvero un brutto trucco per questo problema.
Alexandru Dicu


10

Ecco cosa fa il trucco, indipendentemente dallo stile della finestra da cui stai cercando di nasconderti Alt+ ↹Tab.

Inserisci quanto segue nel costruttore del tuo modulo:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

In sostanza, rendi il tuo modulo un figlio di una finestra invisibile che ha lo stile corretto e l'impostazione ShowInTaskbar da tenere fuori dall'elenco Alt-Tab. È inoltre necessario impostare la proprietà ShowInTaskbar del modulo su false. Soprattutto, semplicemente non importa quale stile abbia il tuo modulo principale, e tutte le modifiche per completare l'occultamento sono solo poche righe nel codice del costruttore.


Aspetta ... QUESTO è C # o C o C ++ ??? Sono davvero un n00b della famiglia C o qualsiasi altra cosa ...
Sreenikethan I

3

Perché provare così tanti codici? Basta impostare la proprietà FormBorderStylesu FixedToolWindow. Spero che sia d'aiuto.


2

guardalo: (da 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);

Vorrei aggiungere qui che 'Handle' può essere acquisito da var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu

1

In XAML impostare 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>

Modifica: questo lo mostra ancora in Alt + Tab immagino, ma non nella barra delle applicazioni.


Sì, questo è il problema: ShowInTaskbar non influisce sulla finestra di dialogo Alt + Tab, come ci si potrebbe aspettare.
devios1

1

Ho provato a impostare la visibilità del modulo principale su false ogni volta che viene automaticamente modificata in true:

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

Funziona perfettamente :)


2
Non solo è di gran lunga la soluzione più semplice, ma ha funzionato molto bene per me.
Daniel McQuiston

1

se vuoi che il modulo sia senza bordi, devi aggiungere le seguenti istruzioni al costruttore del modulo:

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

E devi aggiungere il seguente metodo alla tua classe Form derivata:

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

più dettagli



0

Proprietà Form1:
FormBorderStyle:
WindowState ridimensionabile :
ShowInTaskbar minimizzato : 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;
}>

-1

Personalmente per quanto ne so questo non è possibile senza agganciarsi in qualche modo alle finestre, non sono nemmeno sicuro di come sarebbe fatto o se è possibile.

A seconda delle esigenze, lo sviluppo del contesto dell'applicazione come applicazione NotifyIcon (barra delle applicazioni) consentirà di essere eseguito senza essere visualizzato in ALT + TAB. TUTTAVIA, se apri un modulo, quel modulo continuerà a seguire la funzionalità standard.

Posso scavare nel mio articolo del blog sulla creazione di un'applicazione che è SOLO una NotifyIcon per impostazione predefinita, se lo desideri.



Sono già esperto in NotifyIcons, grazie. Il problema è che desidero nascondere le finestre aperte (non interattive o in alto) da Alt + Tab. È interessante notare che ho appena notato che la barra laterale di Vista non appare in Alt + Tab, quindi ci deve essere un modo per farlo.
devios1

Guardando i vari frammenti, senza cambiare il tipo di finestra (come postato da Barbabietola), non conosco un modo per farlo.
Mitchel Sellers
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.