从Alt-Tab程序切换器隐藏窗口的最佳方法?


101

我已经成为.NET开发人员数年了,但这仍然是我不知道如何正确执行的事情之一。通过Windows窗体和WPF中的属性从任务栏隐藏窗口很容易,但是据我所知,这不能保证(或什至影响)它从Alt+ ↹Tab对话框中被隐藏。我已经看到不可见的窗口显示在Alt+中↹Tab,而我只是想知道什么是最好的方法来确保一个窗口永远不会在Alt+ ↹Tab对话框中出现(可见或不可见)。

更新:请在下面查看我发布的解决方案。我不允许将自己的答案标记为解决方案,但到目前为止,这是唯一可行的方法。

更新2:弗朗西·佩诺夫(Franci Penov)现在提供了一个适当的解决方案,看起来不错,但我自己还没有尝试过。涉及一些Win32,但避免了创建不合时宜的屏幕外窗口的麻烦。


13
系统任务栏应用程序就是一个很好的例子
TravisO

3
我之所以要这样做,是因为我使用全屏半透明的黑色窗口在我的应用程序显示模式界面(例如UAC对话框)时提供“变暗”效果。由于这不是交互式窗口,因此在Alt-Tab对话框中没有显示它的意义。
devios1

8
当您的应用程序显示其自己的模式对话框时,建议不要使整个桌面变暗。调暗桌面建议进行OS级操作。大多数人没有足够的知识来理解它不是安全的桌面。
2009年

3
“很容易通过属性从任务栏隐藏窗口”。此属性是ShowInTaskbar(仅用于记录)。
greenoldman 2010年

问题是关于从Alt-Tab(而不是任务栏)隐藏窗口。
Alexandru Dicu

Answers:


93

更新:

根据@donovan的说法,现代WPF通过设置 ShowInTaskbar="False"Visibility="Hidden" XAML在。(我尚未对此进行测试,但是仍然决定提高评论可见度)

原始答案:

在Win32 API中,有两种方法可以从任务切换器中隐藏窗口:

  1. 添加WS_EX_TOOLWINDOW扩展的窗口样式-这是正确的方法。
  2. 使其成为另一个窗口的子窗口。

不幸的是,WPF不像Win32那样支持对窗口样式的灵活控制,因此WindowStyle=ToolWindow,具有默认WS_CAPTIONWS_SYSMENU样式的窗口最终会带有标题和关闭按钮。另一方面,您可以通过设置删除这两种样式WindowStyle=None,但是这不会设置WS_EX_TOOLWINDOW扩展样式,并且窗口也不会从任务切换器中隐藏。

要使WPF窗口WindowStyle=None也隐藏在任务切换器中,可以使用以下两种方法之一:

  • 与上面的示例代码一起使用,并使该窗口成为小型隐藏工具窗口的子窗口
  • 修改窗口样式以包括WS_EX_TOOLWINDOW扩展样式。

我个人更喜欢第二种方法。再说一遍,我做了一些高级的工作,例如在工作区中扩展玻璃,并无论如何在标题中启用WPF绘图,因此,一点点互操作不是什么大问题。

这是Win32互操作解决方案方法的示例代码。首先,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" >

这里没什么好想的,我们只是用WindowStyle=None和声明一个窗口ShowInTaskbar=False。我们还将一个处理程序添加到Loaded事件,在此我们将修改扩展的窗口样式。我们无法在构造函数中执行此操作,因为那时还没有窗口句柄。事件处理程序本身非常简单:

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

和Win32互操作声明。我已从枚举中删除了所有不必要的样式,只是为了使此处的示例代码小。同样,不幸的SetWindowLongPtr是,在Windows XP上的user32.dll中找不到入口点,因此这是通过调用路由呼叫的技巧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

2
尚未验证,但听起来您知道您在说什么。:)如果需要再次执行此操作,我会记住这一点,但是由于我的其他解决方案运行良好(而且自从我关闭该书已经有一段时间了),我不想摆弄和破坏某些东西。谢谢!
devios1,2009年

1
完美的作品!谢谢!
Anthony Brien'9

对我有用。但我讨厌必须像这样导入dll:P
J4N

8
@ J4N-偶尔进行一点P / Invoke并没有错:-)
Franci Penov

1
在WPF中,这对我不起作用。但是在玩转之后,我发现一个更简单的解决方案是在XAML中设置ShowInTaskbar =“ False”和Visibility =“ Hidden”。无需特殊的点名。
donovan 2015年

40

在您的表单类中,添加以下内容:

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

        return Params;
    }
}

就这么简单;很有魅力!


3
还需要将ShowInTaskbar设置为false才能起作用。
Nick Spreitzer

20

我找到了一个解决方案,但这并不漂亮。到目前为止,这是我尝试过的唯一有效的方法:

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

在这里找到它。

一个更通用,可重用的解决方案将是不错的选择。我想您可以创建一个单独的窗口“ w”,并将其重用于应用程序中所有需要从Alt+ 隐藏的窗口↹Tab

更新:好的,所以我要做的就是将上面的代码移到我的应用程序的构造函数中this.Owner = w(减去之后的代码,然后w.Hide()立即移动w.Show(),这很正常),创建了一个Window称为的公共静态变量OwnerWindow。每当我想要一个窗口表现出这种行为时,我都会简单地设置this.Owner = App.OwnerWindow。效果很好,仅涉及创建一个额外的(且不可见的)窗口。您甚至可以设置this.Owner = null是否要在Alt+ ↹Tab对话框中重新显示该窗口。

感谢MSDN论坛上的Ivan Onuchin提供该解决方案。

更新2:您还应该设置为ShowInTaskBar=false打开,w以防止其在显示时在任务栏中短暂闪烁。


还有一个Win32互操作解决方案可以解决该问题。
弗朗西·佩诺夫09年

有趣的是,我正在执行此方法,但是要避免使用隐藏窗口(使用主应用程序窗口作为所有者),并且它不会出现在Alt-Tab中...
Dave

1
我认为在双显示器配置中,第二个屏幕也可以具有负坐标。
Thomas Weller

@ThomasW。你也许是对的。使用偏移量-100000可能会更好。
devios1 2014年

对于这个问题,这确实是一个糟糕的技巧。
Alexandru Dicu


10

这就是诀窍,无论您尝试从Alt+ 隐藏的窗口样式如何↹Tab

将以下内容放入表单的构造函数中:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

本质上,您使窗体成为不可见窗口的子窗口,该窗口具有正确的样式和ShowInTaskbar设置,以使其不在Alt-Tab列表中。您还必须将自己的窗体的ShowInTaskbar属性设置为false。最棒的是,您的主要表单具有什么样式都没关系,并且完成隐藏的所有调整只是构造函数代码中的几行。


等等...这是C#还是C或C ++ ???我真的是C家庭的n00b或其他人……
Sreenikethan,我

3

为什么要尝试那么多代码?只是设定FormBorderStyle理由FixedToolWindow。希望能帮助到你。


2

看到它:(来自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);

我将在此处添加,可以通过var handle = new WindowInteropHelper(this).Handle;获取“ Handle”。
Alexandru Dicu

1

在XAML中,设置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>

编辑:我猜仍然在Alt + Tab中显示它,只是不在任务栏中。


是的,这就是问题所在:ShowInTaskbar不会像您期望的那样影响Alt + Tab对话框。
devios1

1

每当自动更改为true时,我都尝试将主窗体的可见性设置为false:

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

它完美地工作:)


2
到目前为止,这不仅是最简单的解决方案,而且对我来说非常有效。
丹尼尔·麦奎斯特

1

如果希望表单是无边界的,则需要在表单的构造函数中添加以下语句:

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

并且,您必须将以下方法添加到派生的Form类中:

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

更多细节



0

Form1属性:
FormBorderStyle:可调整的
WindowState:最小的
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;
}>

-1

就我个人而言,据我所知,如果不以某种方式挂入窗户,这是不可能的,我什至不知道该怎么做或是否有可能。

根据您的需要,将应用程序上下文开发为NotifyIcon(系统任务栏)应用程序将允许其运行,而无需在ALT + TAB中显示。但是,如果您打开一个表单,该表单仍将遵循标准功能。

如果需要,我可以阅读有关创建默认情况下仅是NotifyIcon的应用程序的博客文章。



谢谢,我已经精通NotifyIcons。问题是我想从Alt + Tab中隐藏打开的窗口(非交互式或最顶部)。有趣的是,我只是注意到Vista侧栏没有出现在Alt + Tab中,因此必须有一些方法可以做到。
devios1

在不改变窗口类型的情况下,仔细观察各种细节(如红胡子所述),我不知道这样做的方法。
米切尔卖家
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.