Найкращий спосіб приховати вікно від перемикача програм Alt-Tab?


101

Я декілька років розробник .NET, і це все ще одна з тих речей, які я не знаю, як правильно зробити. Приховати вікно за допомогою панелі завдань за допомогою властивості як у Windows Forms, так і в WPF, але наскільки я можу сказати, це не гарантує (або обов'язково навіть впливає) на те, що воно приховане від діалогу Alt+ ↹Tab. Я бачив, як невидимі вікна відображаються в Alt+ ↹Tab, і мені просто цікаво, який найкращий спосіб гарантувати, що вікно ніколи не з’явиться (видиме чи ні) у діалозі Alt+ ↹Tab.

Оновлення: Будь ласка, дивіться моє розміщене рішення нижче. Мені не дозволяється відзначати власні відповіді як рішення, але поки що це єдине, що працює.

Оновлення 2: Зараз є правильне рішення Франці Пенова, яке виглядає досить непогано, але я сам не пробував це. Залучає деяку програму Win32, але уникає кульгавого створення вікон поза екраном.


13
Програми System Tray - прекрасний приклад
TravisO

3
Я хочу це зробити з однієї причини, тому що я використовую повний екран напівпрозоре чорне вікно, щоб забезпечити ефект "затемнення", коли в моєму додатку відображається модальний інтерфейс, подібний до діалогу UAC. Оскільки це не інтерактивне вікно, немає сенсу показувати це у діалоговому вікні Alt-Tab.
devios1

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

3
"Легко сховати вікно на панелі завдань через властивість". Це властивість ShowInTaskbar (лише для запису).
greenoldman

Питання полягає у приховуванні вікна від Alt-Tab, а не від панелі завдань.
Олександру Діку

Відповіді:


93

Оновлення:

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

Оригінальна відповідь:

Існує два способи приховування вікна від перемикача завдань в API Win32:

  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

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 для цієї проблеми.
Франці Пенов

Цікаво, що я займаюся цим підходом, але уникаю прихованого вікна (використовую головне вікно програми як власника), і він не відображається в Alt-Tab ...
Дейв

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

@ThomasW. Ви, мабуть, праві. Використання компенсації на зразок -100000, мабуть, було б краще.
devios1

Це справді поганий злом для цієї проблеми.
Олександру Діку

10

Чому так складно? Спробуйте це:

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

Ідея взята звідси: http://www.csharp411.com/hide-form-from-alttab/


Працює для мене. Дякуємо за внесок!
MiBol

Але вікно інструментів не можна збільшити чи мінімізувати. Вікно інструментів не завжди є кращим варіантом.
Олександру Діку

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. Найкраще, що просто не має значення, який стиль має ваша основна форма, і все налаштування для виконання приховування - це лише кілька рядків у коді конструктора.


Зачекайте ... це ЦІ або С, або С ++ ??? Я справді n00b в сім'ї С або що завгодно ...
Sreenikethan I I

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

Я додам тут, що 'Handle' може бути отриманий за допомогою var handle = new WindowInteropHelper (це) .Handle;
Олександру

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
Це не тільки найпростіше рішення, але це дуже добре спрацювало для мене.
Даніель МакКуістон

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 : Здатне вікноСтатус
: Мінімізований
показInTaskbar: 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

Дивлячись на різні шматочки та шматки, не змінюючи тип вікна (як розміщена червона борода), я не знаю, як це зробити.
Мітчел Продавці
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.