Лучший способ скрыть окно от переключателя программ Alt-Tab?

Я был разработчиком .NET уже несколько лет, и до сих пор это одна из тех вещей, которые я не знаю, как делать правильно. Окно с панели задач легко скрыть через свойство в Windows Forms и WPF, но, насколько я могу судить, это не гарантирует (или даже не влияет) его скрытие в диалоге Alt+ ↹Tab. Я видел невидимые окна, отображаемые в Alt+ ↹Tab, и мне просто интересно, каков наилучший способ гарантировать, что окно никогда не появится (видимое или нет) в диалоге Alt+ ↹Tab.

Обновление: пожалуйста, смотрите мое опубликованное решение ниже. Мне не разрешено отмечать мои собственные ответы как решение, но пока оно работает единственно.

Обновление 2: теперь есть подходящее решение от Франциска Пенова, которое выглядит довольно неплохо, но я не пробовал его сам. Включает в себя некоторые Win32, но избегает неудачного создания закадровых окон.

10.12.2008 18:31:39
Приложения System Tray - отличный пример
TravisO 10.12.2008 18:34:40
Я хочу сделать это по одной причине, потому что я использую полноэкранное полупрозрачное черное окно, чтобы обеспечить эффект «затемнения», когда мое приложение отображает модальный интерфейс, вроде диалогов UAC. Поскольку это не интерактивное окно, нет смысла показывать его в диалоге Alt-Tab.
devios1 10.12.2008 19:03:26
Я бы рекомендовал не затемнять весь рабочий стол, когда ваше приложение показывает свой модальный диалог. Затемнение рабочего стола предполагает работу на уровне ОС. У большинства людей не было бы достаточно сложных знаний, чтобы понять, что это не безопасный рабочий стол.
Franci Penov 16.02.2009 07:31:13
Msgstr "Легко спрятать окно из панели задач через свойство". Это свойство ShowInTaskbar (только для записи).
greenoldman 7.08.2010 11:03:09
Вопрос в том, чтобы скрыть окно от Alt-Tab, а не от панели задач.
Alexandru Dicu 7.01.2020 09:43:17
13 ОТВЕТОВ
РЕШЕНИЕ

Обновить:

Согласно @donovan, в наши дни WPF поддерживает это изначально, через настройки ShowInTaskbar="False"и Visibility="Hidden"в XAML. (Я еще не проверял это, но тем не менее решил уменьшить видимость комментария)

Оригинальный ответ:

Есть два способа скрыть окно от переключателя задач в Win32 API:

  1. добавить WS_EX_TOOLWINDOWрасширенный стиль окна - это правильный подход.
  2. сделать это дочерним окном другого окна.

К сожалению, WPF не поддерживает такой гибкий контроль над стилем окна, как Win32, поэтому окно с окном WindowStyle=ToolWindowзаканчивается стилями по умолчанию WS_CAPTIONи WS_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точка входа не найдена в user32.dll в Windows XP, поэтому существует хитрость с маршрутизацией вызова через нее 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
90
5.05.2015 12:45:41
Не проверял это, но похоже, вы знаете, о чем говорите. :) Я буду иметь это в виду, если мне понадобится сделать это снова, но поскольку мое другое решение работает нормально (и прошло уже много времени с тех пор, как я закрыл книгу по этому вопросу), я не хочу что-то возиться и ломать , Спасибо!
devios1 25.02.2009 03:36:28
Работает отлично! Спасибо!
Anthony Brien 3.09.2010 22:32:45
Работает хорошо для меня. Но я ненавижу импортировать dll следующим образом: P
J4N 23.02.2011 12:59:45
@ J4N - Нет ничего плохого в том, чтобы время от времени использовать P / Invoke :-)
Franci Penov 23.02.2011 16:18:42
Это не сработало для меня в WPF. Но после игры я обнаружил, что гораздо более простым решением было установить ShowInTaskbar = "False" и Visibility = "Hidden" в XAML. Специальный пинвоук не требуется.
donovan 5.05.2015 05:38:20

Лично, насколько я знаю, это невозможно без того, чтобы каким-то образом подключиться к окнам, я даже не уверен, как это будет сделано или возможно ли это.

В зависимости от ваших потребностей, разработка контекста вашего приложения как приложения NotifyIcon (системный трей) позволит ему работать без отображения в ALT + TAB. ОДНАКО, если вы откроете форму, эта форма будет по-прежнему соответствовать стандартной функциональности.

Я могу выкопать мою статью в блоге о создании приложения, которое по умолчанию является ТОЛЬКО NotifyIcon, если хотите.

-1
10.12.2008 19:02:58
Steven A. Lowe 10.12.2008 19:13:39
Я уже хорошо разбираюсь в NotifyIcons, спасибо. Проблема в том, что я хочу скрыть открытые (неинтерактивные или самые верхние) окна из Alt + Tab. Интересно, что я только заметил, что боковая панель Vista не появляется в Alt + Tab, поэтому должен быть НЕКОТОРЫЙ способ сделать это.
devios1 10.12.2008 19:17:17
Глядя на различные фрагменты, не меняя тип окна (как опубликовал redbeard), я не знаю, как это сделать.
Mitchel Sellers 10.12.2008 19:21:02

В 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, я думаю, но не на панели задач.

1
10.12.2008 19:32:48
Да, это проблема: ShowInTaskbar не влияет на диалог Alt + Tab, как вы могли ожидать.
devios1 10.12.2008 19:41:01

Я нашел решение, но это не красиво. Пока это единственное, что я пробовал, это действительно работает:

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.

Update 2: Вы должны также установить ShowInTaskBar=falseна , wчтобы предотвратить его мигания кратко на панели задач , когда показано на рисунке.

20
16.08.2017 09:59:35
Существует также Win32 решение для взаимодействия этой проблемы.
Franci Penov 15.02.2009 23:36:58
Интересно, я делаю этот подход, но избегаю скрытого окна (использующего главное окно приложения в качестве владельца), и оно не появляется в Alt-Tab ...
Dave 7.10.2010 00:53:09
Я думаю, что в конфигурациях с двумя мониторами второй экран также может иметь отрицательные координаты.
Thomas Weller 28.02.2014 12:19:22
@ThomasW. Возможно Вы правы. Использование смещения вроде -100000бы, вероятно, было бы лучше.
devios1 28.02.2014 23:11:11
Это действительно плохой взлом для этой проблемы.
Alexandru Dicu 7.01.2020 09:35:35

Не показывать форму. Используйте невидимость.

Подробнее здесь: http://code.msdn.microsoft.com/TheNotifyIconExample

0
29.12.2008 16:32:36

Свойства Form1:
FormBorderStyle:
Sizable 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;
}>
0
8.12.2009 16:46:46

Почему так сложно? Попробуй это:

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

Идея взята отсюда: http://www.csharp411.com/hide-form-from-alttab/

10
11.06.2017 04:18:50
Работает для меня. Спасибо за вклад!
MiBol 9.06.2016 12:54:18
Но окно инструментов не может быть развернуто или свернуто. Окно инструментов не всегда является предпочтительным вариантом.
Alexandru Dicu 7.01.2020 09:36:57

Вот что делает трюк, независимо от стиля окна, которое вы пытаетесь скрыть от 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. Лучше всего то, что просто не имеет значения, какой стиль имеет ваша основная форма, и все настройки для скрытия - это всего лишь несколько строк в коде конструктора.

8
16.08.2017 10:00:00
Подождите ... это один C # или C или C ++ ??? Я действительно n00b в семье C или что-то еще ...
Sreenikethan I 30.06.2017 09:31:48

увидеть его: (из 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);
2
11.05.2010 13:09:37
Я бы добавил, что 'Handle' можно получить с помощью var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu 15.03.2019 10:11:26

Я пытался установить видимость главной формы на false, когда она автоматически меняется на true:

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

Работает отлично :)

1
2.01.2011 16:27:19
Это не только самое простое решение, но оно очень хорошо сработало для меня.
Daniel McQuiston 22.03.2012 18:46:57

Зачем пытаться так много кодов? Просто установите это FormBorderStyleзначение FixedToolWindow. Надеюсь, поможет.

3
22.02.2012 12:51:48

если вы хотите, чтобы форма была без полей, вам нужно добавить следующие операторы в конструктор формы:

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
27.09.2012 18:50:13

Внутри вашего класса формы добавьте это:

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

Это так просто; работает шарм!

39
22.09.2014 19:27:46
Также необходимо установить для ShowInTaskbar значение false, чтобы это работало.
Nick Spreitzer 23.08.2013 19:00:27