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


101

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

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

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


13
Приложения в системном трее - отличный пример
TravisO,

3
Я хочу сделать это по одной причине, потому что я использую полноэкранное полупрозрачное черное окно, чтобы обеспечить эффект «затемнения», когда мое приложение отображает модальный интерфейс, вроде диалога UAC. Поскольку это не интерактивное окно, нет смысла показывать его в диалоговом окне Alt-Tab.
devios1

8
Я бы посоветовал не затемнять весь рабочий стол, когда ваше приложение показывает собственное модальное диалоговое окно. Затемнение рабочего стола предполагает операцию на уровне ОС. У большинства людей не было бы достаточно сложных знаний, чтобы понять, что это не безопасный рабочий стол.
Франси Пенов,

3
«С помощью свойства легко скрыть окно на панели задач». Это свойство ShowInTaskbar (только для записи).
greenoldman

Вопрос в том, чтобы скрыть окно с Alt-Tab, а не с панели задач.
Александру Дику,

Ответы:


94

Обновить:

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

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

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

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

К сожалению, WPF не поддерживает такое гибкое управление стилем окна, как Win32, поэтому окно со стилями и WindowStyle=ToolWindowпо умолчанию заканчивается , что приводит к появлению заголовка и кнопки закрытия. С другой стороны, вы можете удалить эти два стиля, установив , однако при этом не будет установлен расширенный стиль, и окно не будет скрыто от переключателя задач.WS_CAPTIONWS_SYSMENUWindowStyle=NoneWS_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

2
Не проверял, но похоже, что вы понимаете, о чем говорите. :) Я буду иметь это в виду, если мне нужно будет сделать это снова, но поскольку мое другое решение работает нормально (и прошло некоторое время с тех пор, как я закрыл книгу по этому поводу), я не хочу возиться и что-то ломать . Спасибо!
devios1

1
Прекрасно работает! Спасибо!
Энтони Брайен,

У меня работает хорошо. Но я ненавижу импортировать dll вот так: P
J4N

8
@ J4N - Нет ничего плохого в том, чтобы время от времени использовать P / Invoke :-)
Фрэнси Пенов

1
У меня это не сработало в WPF. Но после экспериментов я обнаружил, что гораздо более простым решением было установить ShowInTaskbar = "False" и Visibility = "Hidden" в XAML. Никаких специальных пинвок не требуется.
Донован

40

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

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

        return Params;
    }
}

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


3
Также необходимо установить для ShowInTaskbar значение false, чтобы это работало.
Ник Спрейцер,

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 за решение.

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


Также есть решение этой проблемы с помощью взаимодействия Win32.
Franci Penov

Интересно, что я использую этот подход, но избегаю скрытого окна (используя главное окно приложения в качестве владельца), и оно не отображается в Alt-Tab ...
Дэйв

1
Я думаю, что в конфигурациях с двумя мониторами второй экран также может иметь отрицательные координаты.
Томас Веллер

@ThomasW. Возможно ты прав. -100000Возможно, было бы лучше использовать смещение вроде .
devios1

Это действительно плохой способ решить эту проблему.
Александру Дику,

10

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

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

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


Работает для меня. Спасибо за вклад!
MiBol 09

Но ToolWindow нельзя развернуть или свернуть. ToolWindow - не всегда предпочтительный вариант.
Александру Дику,

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 или еще где-то ...
Sreenikethan I


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

Я бы добавил, что «Handle» можно получить с помощью var handle = new WindowInteropHelper (this) .Handle;
Alexandru

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

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

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

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


2
Это не только самое простое решение, но и очень хорошо сработало для меня.
Daniel McQuiston

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:
Sizable WindowState: Minimized
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

Глядя на различные детали, не меняя тип окна (как написал redbeard), я не знаю, как это сделать.
Митчел Селлерс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.