Alt-Tab program değiştiriciden bir pencereyi gizlemenin en iyi yolu nedir?


101

Birkaç yıldır .NET geliştiricisiyim ve bu hala nasıl düzgün yapacağımı bilmediğim şeylerden biri. Hem Windows Formları hem de WPF'deki bir özellik aracılığıyla bir pencereyi görev çubuğundan gizlemek kolaydır, ancak anlayabildiğim kadarıyla bu, Alt+ ↹Tabiletişim kutusundan gizlenmesini garanti etmez (veya hatta etkilemez) . + ' Da görünmez pencerelerin göründüğünü gördüm ve bir pencerenin + iletişim kutusunda asla görünmemesini (görünür veya görünmez) garantilemenin en iyi yolunun ne olduğunu merak ediyorum .Alt↹TabAlt↹Tab

Güncelleme: Lütfen aşağıda yayınlanan çözümüme bakın. Çözüm olarak kendi cevaplarımı işaretlememe izin verilmiyor, ancak şu ana kadar işe yarayan tek cevap bu.

Güncelleme 2: Şimdi Franci Penov tarafından oldukça iyi görünen ancak kendim denemedim uygun bir çözüm var. Bazı Win32'yi içerir, ancak ekran dışı pencerelerin topal oluşumunu önler.


13
Sistem Tepsisi uygulamaları harika bir örnek
TravisO

3
Bunu bir nedenden dolayı yapmak istiyorum çünkü uygulamam UAC iletişim kutusu gibi bir modal arayüz görüntülerken "karartma" efekti sağlamak için tam ekran yarı saydam siyah bir pencere kullanıyorum. Bu etkileşimli bir pencere olmadığından, onu Alt-Tab iletişim kutusunda göstermenin bir anlamı yoktur.
devios1

8
Uygulamanız kendi kalıcı iletişim kutusunu gösterdiğinde tüm masaüstünün karartılmasını önermem. Masaüstünün karartılması, işletim sistemi düzeyinde bir işlem önerir. Çoğu insan, bunun güvenli masaüstü olmadığını anlayacak kadar bilgili olamazdı.
Franci Penov

3
"Bir özellik aracılığıyla bir pencereyi görev çubuğundan gizlemek kolaydır". Bu özellik ShowInTaskbar'dır (sadece kayıt içindir).
greenoldman

Soru, pencereyi Görev Çubuğundan değil Alt-Tab'den gizlemekle ilgilidir.
Alexandru Dicu

Yanıtlar:


94

Güncelleme:

@Donovan'a göre, modern günlerde WPF bunu XAML'de ayarlayarak ShowInTaskbar="False"ve yerel olarak destekliyor Visibility="Hidden". (Bunu henüz test etmedim, ancak yine de yorum görünürlüğünü artırmaya karar verdim)

Orijinal cevap:

Win32 API'de görev değiştiriciden bir pencere gizlemenin iki yolu vardır:

  1. WS_EX_TOOLWINDOWgenişletilmiş pencere stilini eklemek için - bu doğru yaklaşımdır.
  2. onu başka bir pencerenin alt penceresi yapmak için.

Ne yazık ki, WPF pencere stili üzerinde Win32 kadar esnek kontrolü desteklemiyor, bu nedenle WindowStyle=ToolWindowvarsayılan WS_CAPTIONve WS_SYSMENUstillere sahip bir pencere , bir başlık ve bir kapatma düğmesine sahip olmasına neden oluyor. Öte yandan, bu iki stili ayarlayarak kaldırabilirsiniz WindowStyle=None, ancak bu WS_EX_TOOLWINDOWgenişletilmiş stili ayarlamaz ve pencere görev değiştiriciden gizlenmez.

WindowStyle=NoneGörev değiştiriciden de gizlenmiş bir WPF penceresine sahip olmak için iki yoldan biri yapılabilir:

  • yukarıdaki örnek kodla gidin ve pencereyi küçük bir gizli araç penceresinin alt penceresi yapın
  • WS_EX_TOOLWINDOWgenişletilmiş stili de içerecek şekilde pencere stilini değiştirin .

Şahsen ikinci yaklaşımı tercih ederim. Sonra yine, camı istemci alanında genişletmek ve yine de altyazıda WPF çizimini etkinleştirmek gibi bazı gelişmiş şeyler yapıyorum, bu nedenle biraz birlikte çalışma büyük bir sorun değil.

İşte Win32 birlikte çalışma çözümü yaklaşımı için örnek kod. İlk olarak, XAML bölümü:

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

Burada çok süslü bir şey yok, sadece WindowStyle=Noneve ile bir pencere ilan ediyoruz ShowInTaskbar=False. Ayrıca, genişletilmiş pencere stilini değiştireceğimiz Loaded olayına bir işleyici de ekliyoruz. Henüz o noktada bir pencere kolu olmadığından, bu işi yapıcıda yapamayız. Olay işleyicisinin kendisi çok basittir:

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

Ve Win32 birlikte çalışma bildirimleri. Buradaki örnek kodu küçük tutmak için, tüm gereksiz stilleri numaralandırmalardan kaldırdım. Ayrıca, maalesef SetWindowLongPtrgiriş noktası Windows XP'de user32.dll'de bulunamadı, bu nedenle aramayı SetWindowLongbunun yerine yönlendirmenin hilesi .

#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
Bunu doğrulamadım ama neden bahsettiğini biliyor gibisin. :) Tekrar yapmam gerekirse bunu aklımda tutacağım, ancak diğer çözümüm iyi çalıştığı için (ve bu konuda kitabı kapatmayalı epey oldu) bir şeyi keman etmek ve kırmak istemiyorum . Teşekkürler!
devios1

1
Mükemmel çalışıyor! Teşekkürler!
Anthony Brien

Benim için iyi çalışıyor. Ama
dll'yi

8
@ J4N - Ara sıra biraz P / Invoke ile ilgili yanlış bir şey yok :-)
Franci Penov

1
Bu WPF'de benim için işe yaramadı. Ancak etrafta oynadıktan sonra, XAML'de ShowInTaskbar = "False" ve Visibility = "Hidden" olarak ayarlamak çok daha kolay bir çözüm buldum. Özel bir pinvoke gerekmez.
donovan

40

Form sınıfınızın içine şunu ekleyin:

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

        return Params;
    }
}

Bu kadar kolay; harika çalışıyor!


3
Bunun çalışması için ShowInTaskbar'ı da false olarak ayarlamanız gerekir.
Nick Spreitzer

20

Bir çözüm buldum ama hiç hoş değil. Şimdiye kadar denediğim tek şey gerçekten işe yarıyor:

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

Buldum burada .

Daha genel, yeniden kullanılabilir bir çözüm iyi olurdu. Sanırım tek bir pencere 'w' oluşturabilir ve uygulamanızda Alt+ ' dan gizlenmesi gereken tüm pencereler için yeniden kullanabilirsiniz ↹Tab.

Güncelleme: Tamam, yaptığım şey, yukarıdaki kodu, eksi this.Owner = wbiti (ve w.Hide()hemen ardından hareket eden w.Show(), iyi çalışıyor) uygulamamın kurucusuna taşımak ve Windowadlı genel bir statik oluşturmaktı OwnerWindow. Bu davranışı sergileyen bir pencere istediğimde, basitçe ayarlıyorum this.Owner = App.OwnerWindow. Harika çalışıyor ve yalnızca fazladan (ve görünmez) bir pencere oluşturmayı içeriyor. this.Owner = nullPencerenin Alt+ ↹Tabiletişim kutusunda yeniden görünmesini isteyip istemediğinizi bile ayarlayabilirsiniz .

Çözüm için MSDN forumlarında Ivan Onuchin'e teşekkürler.

Güncelleme 2: Ayrıca belirlesin ShowInTaskBar=falseüzerinde wgösterildiğinde görev çubuğunda kısaca yanıp sönen engellemek için.


Bu soruna bir Win32 birlikte çalışma çözümü de var.
Franci Penov

İlginç, bu yaklaşımı yapıyorum, ancak gizli pencereden kaçınıyorum (sahip olarak ana uygulama penceresini kullanarak) ve Alt-
Dave

1
Çift monitörlü konfigürasyonlarda ikinci ekranın da negatif koordinatlara sahip olabileceğini düşünüyorum.
Thomas Weller

@ThomasW. Muhtemelen haklısın. Böyle bir ofset kullanmak -100000muhtemelen daha iyi olacaktır.
devios1

Bu, bu sorun için gerçekten kötü bir hack.
Alexandru Dicu


10

İşte Alt+ ' dan saklanmaya çalıştığınız pencerenin tarzı ne olursa olsun, püf noktası nedir ↹Tab.

Aşağıdakileri formunuzun kurucusuna yerleştirin:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Esasen, formunuzu Alt-Tab listesinin dışında tutmak için doğru stile ve ShowInTaskbar ayarına sahip görünmez bir pencerenin çocuğu yaparsınız. Ayrıca kendi formunuzun ShowInTaskbar özelliğini de false olarak ayarlamalısınız. Hepsinden iyisi, ana formunuzun hangi stile sahip olduğu önemli değildir ve gizlemeyi başarmak için tüm ince ayarlar yapıcı kodunda sadece birkaç satırdır.


Bekle ... BU C # veya C veya C ++ mı ??? C ailesinde gerçekten bir n00b değilim ya da her neyse ...
2017

3

Neden bu kadar çok kod deniyorsun? Sadece FormBorderStyleuygunluğu ayarlayın FixedToolWindow. Umarım yardımcı olur.


2

görün: ( http://bytes.com/topic/c-sharp/answers/442047-hide-alt-tab-list#post1683880 adresinden )

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

Buraya 'Tutamaç'ın var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu

1

XAML'de ShowInTaskbar = "False" olarak ayarlayın:

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

Düzenleme: Bu hala Alt + Tab'ta gösteriyor sanırım, sadece görev çubuğunda değil.


Evet sorun bu: ShowInTaskbar, beklediğiniz gibi Alt + Tab iletişim kutusunu etkilemez.
devios1

1

Otomatik olarak true değerine değiştirildiğinde ana formun görünürlüğünü yanlış olarak ayarlamayı denedim:

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

Mükemmel çalışıyor :)


2
Sadece açık arayla en kolay çözüm değil, aynı zamanda benim için çok iyi çalıştı.
Daniel McQuiston

1

formun kenarlıksız olmasını istiyorsanız, aşağıdaki ifadeleri formun yapıcısına eklemeniz gerekir:

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

VE türetilmiş Form sınıfınıza aşağıdaki yöntemi eklemelisiniz:

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

daha fazla detay



0

Form1 Özellikleri:
FormBorderStyle: Boyutlandırılabilir
WindowState: Simge Durumuna Küçültülmüş
ShowInTaskbar: Yanlış

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

Kişisel olarak bildiğim kadarıyla, bir şekilde pencerelere takılmadan bunun mümkün olmadığını biliyorum, bunun nasıl yapılacağından veya mümkün olup olmadığından bile emin değilim.

İhtiyaçlarınıza bağlı olarak, uygulama bağlamınızı bir NotifyIcon (sistem tepsisi) uygulaması olarak geliştirmek, uygulamanın ALT + TAB'de gösterilmeden çalışmasına izin verecektir. ANCAK, bir formu açarsanız, bu form yine de standart işlevselliği izleyecektir.

İsterseniz, varsayılan olarak YALNIZCA NotifyIcon olan bir uygulama oluşturma hakkındaki blog makalemi inceleyebilirim.



NotifyIcons konusunda zaten bilgiliyim, teşekkürler. Sorun şu ki, açık (etkileşimli olmayan veya en üstteki) pencereleri Alt + Tab'den gizlemek istiyorum. İlginç bir şekilde, Vista kenar çubuğunun Alt + Tab'de görünmediğini fark ettim, bu yüzden bunu yapmanın BAZI bir yolu olmalı.
devios1

Pencerenin türünü değiştirmeden (kızılsakalın yazdığı gibi) çeşitli parçalara baktığımda, bunu yapmanın bir yolunu bilmiyorum.
Mitchel Sellers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.