Cara terbaik untuk menyembunyikan jendela dari pengalih program Alt-Tab?

101

Saya telah menjadi pengembang NET selama beberapa tahun sekarang dan ini masih salah satu hal yang saya tidak tahu bagaimana melakukannya dengan benar. Sangat mudah untuk menyembunyikan jendela dari bilah tugas melalui properti di Formulir Windows dan WPF, tetapi sejauh yang saya tahu, ini tidak menjamin (atau bahkan mempengaruhi) itu disembunyikan dari dialog Alt+ ↹Tab. Saya telah melihat jendela tak terlihat muncul di Alt+ ↹Tab, dan saya hanya bertanya-tanya apa cara terbaik untuk menjamin jendela tidak akan pernah muncul (terlihat atau tidak) di dialog Alt+ ↹Tab.

Pembaruan: Silakan lihat solusi saya yang diposting di bawah ini. Saya tidak diizinkan menandai jawaban saya sendiri sebagai solusi, tetapi sejauh ini hanya satu yang berhasil.

Pembaruan 2: Sekarang ada solusi yang tepat dari Franci Penov yang terlihat cukup bagus, tetapi belum mencobanya sendiri. Melibatkan beberapa Win32, tetapi menghindari pembuatan jendela di luar layar yang timpang.

devios1
sumber
13
Aplikasi System Tray adalah contoh yang bagus
TravisO
3
Saya ingin melakukannya karena satu alasan karena saya menggunakan jendela hitam semitransparan layar penuh untuk memberikan efek "peredupan" saat aplikasi saya menampilkan antarmuka modal, seperti dialog UAC. Karena ini bukan jendela interaktif, tidak ada gunanya menampilkannya di dialog Alt-Tab.
devios1
8
Saya menyarankan agar tidak meredupkan seluruh desktop saat aplikasi Anda menampilkan dialog modal sendiri. Peredupan desktop menyarankan operasi tingkat OS. Kebanyakan orang tidak akan memiliki pengetahuan yang cukup canggih untuk dapat memahami bahwa ini bukanlah desktop yang aman.
Franci Penov
3
"Sangat mudah untuk menyembunyikan jendela dari bilah tugas melalui properti". Properti ini adalah ShowInTaskbar (hanya sebagai catatan).
greenoldman
Pertanyaannya adalah tentang menyembunyikan jendela dari Alt-Tab, bukan dari Taskbar.
Alexandru Dicu

Jawaban:

93

Memperbarui:

Menurut @donovan, WPF modern mendukung ini secara asli, melalui pengaturan ShowInTaskbar="False"dan Visibility="Hidden"di XAML. (Saya belum menguji ini, tetapi memutuskan untuk meningkatkan visibilitas komentar)

Jawaban asli:

Ada dua cara untuk menyembunyikan jendela dari pengalih tugas di Win32 API:

  1. untuk menambahkan WS_EX_TOOLWINDOWgaya jendela yang diperluas - itulah pendekatan yang tepat.
  2. untuk menjadikannya jendela anak dari jendela lain.

Sayangnya, WPF tidak mendukung kontrol fleksibel atas gaya jendela seperti Win32, sehingga jendela dengan WindowStyle=ToolWindowberakhir dengan gaya WS_CAPTIONdan default WS_SYSMENU, yang menyebabkannya memiliki keterangan dan tombol tutup. Di sisi lain, Anda dapat menghapus dua gaya ini dengan mengatur WindowStyle=None, namun itu tidak akan mengatur WS_EX_TOOLWINDOWgaya yang diperluas dan jendela tidak akan disembunyikan dari pengalih tugas.

Untuk memiliki jendela WPF WindowStyle=Noneyang juga tersembunyi dari pengalih tugas, salah satu dari dua cara dapat dilakukan:

  • gunakan kode contoh di atas dan jadikan jendela sebagai jendela anak dari jendela alat kecil yang tersembunyi
  • memodifikasi gaya jendela agar juga menyertakan WS_EX_TOOLWINDOWgaya yang diperluas.

Saya pribadi lebih suka pendekatan kedua. Kemudian lagi, saya melakukan beberapa hal lanjutan seperti memperluas kaca di area klien dan mengaktifkan gambar WPF di caption, jadi sedikit interop bukanlah masalah besar.

Berikut kode contoh untuk pendekatan solusi interop Win32. Pertama, bagian 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" >

Tidak ada yang terlalu mewah di sini, kami hanya mendeklarasikan jendela dengan WindowStyle=Nonedan ShowInTaskbar=False. Kami juga menambahkan penangan ke acara Loaded di mana kami akan memodifikasi gaya jendela diperpanjang. Kami tidak dapat melakukan pekerjaan itu di konstruktor, karena belum ada pegangan jendela pada saat itu. Pengendali acara itu sendiri sangat sederhana:

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

Dan deklarasi interop Win32. Saya telah menghapus semua gaya yang tidak perlu dari enum, hanya untuk menjaga kode contoh di sini tetap kecil. Juga, sayangnya SetWindowLongPtrtitik masuk tidak ditemukan di user32.dll pada Windows XP, oleh karena itu trik dengan merutekan panggilan melalui SetWindowLongalih - alih.

#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
sumber
2
Belum memverifikasi ini tapi sepertinya Anda tahu apa yang Anda bicarakan. :) Saya akan mengingat hal ini jika saya perlu melakukannya lagi, tetapi karena solusi saya yang lain berfungsi dengan baik (dan sudah lama sejak saya menutup buku ini) saya tidak ingin mengutak-atik dan merusak sesuatu . Terima kasih!
devios1
1
Bekerja dengan sempurna! Terima kasih!
Anthony Brien
Berfungsi baik untuk saya. Tapi saya benci harus mengimpor dll seperti ini: P
J4N
8
@ J4N - Tidak ada yang salah dengan sedikit P / Panggil sesekali :-)
Franci Penov
1
Ini tidak berhasil untuk saya di WPF. Tetapi setelah bermain-main saya menemukan solusi yang jauh lebih mudah adalah dengan mengatur ShowInTaskbar = "False" dan Visibility = "Hidden" di XAML. Tidak diperlukan pinvoke khusus.
donovan
40

Di dalam kelas formulir Anda, tambahkan ini:

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

        return Params;
    }
}

Semudah itu; bekerja dengan sangat baik!

Danny Beckett
sumber
3
Juga perlu menyetel ShowInTaskbar ke false agar ini berfungsi.
Nick Spreitzer
20

Saya telah menemukan solusinya, tetapi itu tidak bagus. Sejauh ini, ini adalah satu - satunya hal yang saya coba yang benar-benar berfungsi:

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

Ketemu di sini .

Solusi yang lebih umum dan dapat digunakan kembali akan menyenangkan. Saya kira Anda dapat membuat satu jendela 'w' dan menggunakannya kembali untuk semua jendela di aplikasi Anda yang perlu disembunyikan dari Alt+ ↹Tab.

Pembaruan: Ok jadi apa yang saya lakukan adalah memindahkan kode di atas, minus this.Owner = wbit (dan bergerak w.Hide()segera setelahnya w.Show(), yang berfungsi dengan baik) ke konstruktor aplikasi saya, membuat statis publik yang Windowdisebut OwnerWindow. Setiap kali saya ingin jendela untuk menunjukkan perilaku ini, saya cukup menyetelnya this.Owner = App.OwnerWindow. Bekerja dengan baik, dan hanya melibatkan pembuatan satu jendela ekstra (dan tidak terlihat). Anda bahkan dapat menyetel this.Owner = nulljika ingin jendela tersebut muncul kembali di dialog Alt+ ↹Tab.

Terima kasih kepada Ivan Onuchin di forum MSDN untuk solusinya.

Update 2: Anda juga harus menetapkan ShowInTaskBar=falsepada wuntuk mencegah dari berkedip sebentar di taskbar ketika ditampilkan.

devios1
sumber
Ada juga solusi interop Win32 untuk masalah itu.
Franci Penov
Menarik, saya melakukan pendekatan ini tetapi menghindari jendela tersembunyi (menggunakan jendela aplikasi utama sebagai pemilik), dan itu tidak muncul di Alt-Tab ...
Dave
1
Saya rasa pada konfigurasi monitor ganda, layar kedua juga bisa memiliki koordinat negatif.
Thomas Weller
@Tokopedia Mungkin Anda benar. Menggunakan offset seperti -100000mungkin akan lebih baik.
devios1
Ini benar-benar peretasan yang buruk untuk masalah ini.
Alexandru Dicu
10

Mengapa begitu rumit? Coba ini:

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

Ide diambil dari sini: http://www.csharp411.com/hide-form-from-alttab/

Andrey
sumber
Bekerja untuk saya. Terima kasih atas kontribusinya!
MiBol
Tetapi ToolWindow tidak dapat dimaksimalkan atau diminimalkan. ToolWindow tidak selalu merupakan pilihan yang lebih disukai.
Alexandru Dicu
10

Inilah triknya, terlepas dari gaya jendela yang Anda coba sembunyikan dari Alt+ ↹Tab.

Tempatkan berikut ini ke dalam konstruktor formulir Anda:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Pada dasarnya, Anda membuat formulir Anda menjadi anak dari jendela tak terlihat yang memiliki gaya dan pengaturan ShowInTaskbar yang benar agar tidak masuk ke daftar Alt-Tab. Anda juga harus menyetel properti ShowInTaskbar formulir Anda sendiri ke false. Yang terbaik dari semuanya, tidak masalah gaya apa yang dimiliki formulir utama Anda, dan semua penyesuaian untuk menyelesaikan persembunyian hanyalah beberapa baris dalam kode konstruktor.

Matt Hendricks
sumber
Tunggu ... apakah INI C # atau C atau C ++ ??? Aku benar-benar n00b di keluarga C atau apa pun ...
Sreenikethan I
3

Mengapa mencoba begitu banyak kode? Atur saja FormBorderStylepropety ke FixedToolWindow. Semoga membantu.

Saravanakumar. N
sumber
2

lihat: (dari 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
sumber
Saya akan menambahkan di sini bahwa 'Handle' dapat diperoleh dengan var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu
1

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

Sunting: Itu masih menunjukkannya di Alt + Tab saya kira, hanya saja tidak di bilah tugas.

Philipp Schmid
sumber
Ya, itulah masalahnya: ShowInTaskbar tidak memengaruhi dialog Alt + Tab, seperti yang Anda duga.
devios1
1

Saya mencoba mengatur visibilitas formulir utama menjadi salah setiap kali secara otomatis diubah menjadi benar:

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

Ini bekerja dengan sempurna :)

tiendan
sumber
2
Sejauh ini tidak hanya merupakan solusi termudah, tetapi juga bekerja dengan sangat baik untuk saya.
Daniel McQuiston
1

jika Anda ingin formulir menjadi tanpa batas, maka Anda perlu menambahkan pernyataan berikut ke konstruktor formulir:

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

DAN Anda harus menambahkan metode berikut ke kelas Formulir turunan Anda:

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

keterangan lebih lanjut

Hossein Moradinia
sumber
0

Properti Form1:
FormBorderStyle : WindowState yang cukup besar
:
ShowInTaskbar yang diminimalkan : 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;
}>
Charlie Salts
sumber
-1

Secara pribadi sejauh yang saya tahu ini tidak mungkin tanpa menghubungkan ke jendela dengan cara tertentu, saya bahkan tidak yakin bagaimana itu akan dilakukan atau apakah itu mungkin.

Bergantung pada kebutuhan Anda, mengembangkan konteks aplikasi Anda sebagai aplikasi NotifyIcon (system tray) akan memungkinkannya berjalan tanpa ditampilkan di ALT + TAB. NAMUN, jika Anda membuka formulir, formulir itu masih akan mengikuti fungsionalitas standar.

Saya dapat menggali artikel blog saya tentang membuat aplikasi yang HANYA merupakan NotifyIcon secara default jika Anda mau.

Penjual Mitchel
sumber
Saya sudah berpengalaman dalam NotifyIcons, terima kasih. Masalahnya adalah saya ingin menyembunyikan jendela yang terbuka (non-interaktif, atau paling atas) dari Alt + Tab. Menariknya, saya baru saja memperhatikan bahwa sidebar Vista tidak muncul di Alt + Tab, jadi pasti ada BEBERAPA cara untuk melakukannya.
devios1
Melihat berbagai potongan, tanpa mengubah jenis jendela (seperti yang diposting redbeard), saya tidak tahu cara untuk melakukan ini.
Mitchel Sellers