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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/357076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:47:22  来源:igfitidea点击:

Best way to hide a window from the Alt-Tab program switcher?

.netwpfwinformsalt-tab

提问by devios1

I've been a .NET developer for several years now and this is still one of those things I don't know how to do properly. It's easy to hide a window from the taskbar via a property in both Windows Forms and WPF, but as far as I can tell, this doesn't guarantee (or necessarily even affect) it being hidden from the Alt+?Tabdialog. I've seen invisiblewindows show up in Alt+?Tab, and I'm just wondering what is the best way to guarantee a window will neverappear (visible or not) in the Alt+?Tabdialog.

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

Update:Please see my posted solution below. I'm not allowed to mark my own answers as the solution, but so far it's the only one that works.

更新:请参阅下面我发布的解决方案。我不允许将自己的答案标记为解决方案,但到目前为止它是唯一有效的答案。

Update 2:There's now a proper solution by Franci Penov that looks pretty good, but haven't tried it out myself. Involves some Win32, but avoids the lame creation of off-screen windows.

更新 2:Franci Penov 现在有一个合适的解决方案,看起来不错,但我自己还没有尝试过。涉及一些 Win32,但避免了屏幕外窗口的蹩脚创建。

采纳答案by Franci Penov

Update:

更新:

According to @donovan, modern days WPF supports this natively, through setting ShowInTaskbar="False"and Visibility="Hidden"in the XAML. (I haven't tested this yet, but nevertheless decided to bump the comment visibility)

根据@donovan 的说法,现代 WPF 通过设置ShowInTaskbar="False"Visibility="Hidden"在 XAML 中本地支持这一点 。(我还没有测试过这个,但还是决定提高评论的可见性)

Original answer:

原答案:

There are two ways of hiding a window from the task switcher in Win32 API:

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

  1. to add the WS_EX_TOOLWINDOWextended window style - that's the right approach.
  2. to make it a child window of another window.
  1. 添加WS_EX_TOOLWINDOW扩展窗口样式 - 这是正确的方法。
  2. 使其成为另一个窗口的子窗口。

Unfortunately, WPF does not support as flexible control over the window style as Win32, thus a window with WindowStyle=ToolWindowends up with the default WS_CAPTIONand WS_SYSMENUstyles, which causes it to have a caption and a close button. On the other hand, you can remove these two styles by setting WindowStyle=None, however that will not set the WS_EX_TOOLWINDOWextended style and the window will not be hidden from the task switcher.

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

To have a WPF window with WindowStyle=Nonethat is also hidden from the task switcher, one can either of two ways:

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

  • go with the sample code above and make the window a child window of a small hidden tool window
  • modify the window style to also include the WS_EX_TOOLWINDOWextended style.
  • 使用上面的示例代码,使窗口成为一个小的隐藏工具窗口的子窗口
  • 修改窗口样式以包括WS_EX_TOOLWINDOW扩展样式。

I personally prefer the second approach. Then again, I do some advanced stuff like extending the glass in the client area and enabling WPF drawing in the caption anyway, so a little bit of interop is not a big problem.

我个人更喜欢第二种方法。再说一次,我做了一些高级的东西,比如在客户区扩展玻璃,无论如何在标题中启用 WPF 绘图,所以一点点互操作不是大问题。

Here's the sample code for the Win32 interop solution approach. First, the XAML part:

下面是 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" >

Nothing too fancy here, we just declare a window with WindowStyle=Noneand ShowInTaskbar=False. We also add a handler to the Loaded event where we will modify the extended window style. We can't do that work in the constructor, as there's no window handle at that point yet. The event handler itself is very simple:

这里没什么特别的,我们只是用WindowStyle=Noneand声明一个窗口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);
    }

And the Win32 interop declarations. I've removed all unnecessary styles from the enums, just to keep the sample code here small. Also, unfortunately the SetWindowLongPtrentry point is not found in user32.dll on Windows XP, hence the trick with routing the call through the SetWindowLonginstead.

和 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

回答by Danny Beckett

Inside your form class, add this:

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

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

It's as easy as that; works a charm!

就这么简单;很有魅力!

回答by devios1

I've found a solution, but it's not pretty. So far this is the onlything I've tried that actually works:

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

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

Found it here.

在这里找到

A more general, reusable solution would be nice. I suppose you could create a single window 'w' and reuse it for all windows in your app that need to be hidden from the Alt+?Tab.

一个更通用的、可重用的解决方案会很好。我想您可以创建一个窗口 'w' 并将其重用于应用程序中需要从Alt+ 中隐藏的所有窗口?Tab

Update:Ok so what I did was move the above code, minus the this.Owner = wbit (and moving w.Hide()immediately after w.Show(), which works fine) into my application's constructor, creating a public static Windowcalled OwnerWindow. Whenever I want a window to exhibit this behavior, I simply set this.Owner = App.OwnerWindow. Works great, and only involves creating one extra (and invisible) window. You can even set this.Owner = nullif you want the window to reappear in the Alt+?Tabdialog.

更新:好的,所以我所做的是将上面的代码,减去this.Owner = w位(并在w.Hide()之后立即移动w.Show(),工作正常)到我的应用程序的构造函数中,创建一个Window名为OwnerWindow. 每当我想要一个窗口表现出这种行为时,我只需将this.Owner = App.OwnerWindow. 效果很好,只需要创建一个额外的(并且不可见的)窗口。您甚至可以设置this.Owner = null是否希望窗口重新出现在Alt+?Tab对话框中。

Thanks to Ivan Onuchin over on MSDN forums for the solution.

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

Update 2:You should also set ShowInTaskBar=falseon wto prevent it from flashing briefly in the taskbar when shown.

更新2:你也应该设置ShowInTaskBar=falsew,以防止它显示在任务栏上闪烁简要介绍。

回答by Andrey

Why so complex? Try this:

为什么这么复杂?尝试这个:

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

Idea taken from here:http://www.csharp411.com/hide-form-from-alttab/

从这里采取的想法:http: //www.csharp411.com/hide-form-from-alttab/

回答by Matt Hendricks

Here's what does the trick, regardless of the style of the window your are trying to hide from Alt+?Tab.

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

Place the following into the constructor of your form:

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

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Essentially, you make your form a child of an invisible window which has the correct style and ShowInTaskbar setting to keep out of the Alt-Tab list. You must also set your own form's ShowInTaskbar property to false. Best of all, it simply doesn't matter what style your main form has, and all tweaking to accomplish the hiding is just a few lines in the constructor code.

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

回答by Saravanakumar. N

Why trying so much codes? Just set the FormBorderStylepropety to FixedToolWindow. Hope it helps.

为什么要尝试这么多代码?只需将FormBorderStyle属性设置为FixedToolWindow. 希望能帮助到你。

回答by Behnam Shomali

see it:(from http://bytes.com/topic/c-sharp/answers/442047-hide-alt-tab-list#post1683880)

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

回答by tiendan

I tried setting the main form's visibility to false whenever it is automatically changed to true:

我尝试将主窗体的可见性设置为 false,只要它自动更改为 true:

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

It works perfectly :)

它完美地工作:)

回答by Hossein Moradinia

if you want the form to be borderless, then you need to add the following statements to the form's constructor:

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

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

AND you must add the following method to your derived Form class:

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

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

more details

更多细节

回答by Philipp Schmid

In XAML set ShowInTaskbar="False":

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

Edit: That still shows it in Alt+Tab I guess, just not in the taskbar.

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