隐藏任务栏中的应用程序

12

我一直在努力让我的应用程序从任务栏中隐藏另一个应用程序。
我一直在使用SetWindowLong函数来设置/删除扩展样式中的WS_EX_APPWINDOW

我尝试了分别设置和删除属性,以及获取当前的WindowLong,然后将其添加/删除,就像这样:

SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow) & WS_EX_APPWINDOW);

然后尝试这样删除它:

SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow) & ~WS_EX_APPWINDOW);

我也尝试过这两种方法,但没有先获取窗口长度。这是我的整个代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    [DllImport("User32.dll")]
    public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    [DllImport("User32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private const int SW_HIDE = 0x00;
    private const int SW_SHOW = 0x05;

    private const int WS_EX_APPWINDOW = 0x40000;
    private const int GWL_EXSTYLE = -0x14;

    private void HideWindowFromTaskbar(IntPtr pMainWindow)
    {
        SetWindowLong(pMainWindow, GWL_EXSTYLE, ~WS_EX_APPWINDOW);

        ShowWindow(pMainWindow, SW_HIDE);
        ShowWindow(pMainWindow, SW_SHOW);
    }

    private void ButtonHide_Click(object sender, RoutedEventArgs e)
    {
        HideWindowFromTaskbar(Process.GetProcessesByName("notepad")[0].MainWindowHandle);
    }
}

我注意到在查看属性时,Spy++发生了变化。我有很多不同的结果,比如添加了WS_EX_APPWINDOW,但也会随机消失其他属性等。
在查看消息时,我还看到它确实收到了像STYLE_CHANGED这样的消息。


你尝试过使用SW_HIDE和SetWindowPlacement吗? - Alex
我没有,但那不是只隐藏整个窗口吗?我只想删除它的任务栏条/项目。 - René Sackers
我没有尝试过这个,但看起来它可能适合你:http://alanbondo.wordpress.com/2008/06/22/creating-a-system-tray-app-with-c/ - Dirk Dastardly
我一直在努力将另一个应用程序从任务栏中隐藏起来。正如我所说,我想隐藏一个不同的应用程序,否则这种方法本来是行得通的。 - René Sackers
4个回答

4
确定哪些窗口在任务栏上显示的规则记录在MSDN上。雷蒙德·陈(Raymond Chen)对这些规则给出了以下总结:
基本规则如下:
  • 如果设置了WS_EX_APPWINDOW扩展样式,则它将显示(可见时)。
  • 如果窗口是顶级未拥有窗口,则它将显示(可见时)。
  • 否则不显示。
您试图修改另一个应用程序中的窗口,这严重地妨碍了您。您正在删除WS_EX_APPWINDOW扩展样式。这还不够,因为所讨论的窗口将是一个顶级未拥有窗口(参见第2个要点)。一旦窗口被创建,您就无法更改窗口的所有者,并且由于该窗口由另一个进程控制,因此您几乎无能为力。
唯一的选择是删除 WS_EX_APPWINDOW 扩展样式,并将其替换为 WS_EX_TOOLWINDOW。这确实可以使窗口不再出现在任务栏上,但会改变窗口的 外观

该窗口旨在用作浮动工具栏。工具窗口的标题栏比普通标题栏短,窗口标题使用较小的字体绘制。工具窗口不会出现在任务栏或用户按下 ALT+TAB 时出现的对话框中。如果工具窗口有系统菜单,则其图标不会显示在标题栏上。但是,您可以通过右键单击或输入 ALT+SPACE 来显示系统菜单。


我想知道当你将自己的应用程序的ShowInTaskbar设置为false时,它是如何工作的。 - René Sackers
我认为它重新创建了窗口并更改了所有者。 - David Heffernan
啊哈!有趣!也许我需要通过发送这样的消息来通知窗口。 - René Sackers
不可能有那样的工作。另一个应用程序创建窗口并确定所有权。 - David Heffernan
也许我在这里误解了,但是您确实可以在创建后更改窗口的所有者,即使它是另一个进程中的窗口-尝试一下,它有效。而且这将从任务栏/ alt + tab 中删除该窗口。 - Maurice Flanagan
@Maurice,文档已经很清楚了。“创建拥有窗口后,应用程序无法将窗口的所有权转移给另一个窗口。”你具体在做什么? - David Heffernan

3

我是如何做到这一点的。

1. Create a window (hwndOwner) with WS_POPUP style and WS_EX_TOOLWINDOW
2. Call SetWindowLong(hwnd, GWL_HWNDPARENT, hwndOwner)
3. Call SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) |     ~WS_EX_APPWINDOW)

这将从任务栏和alt+tab中移除目标窗口。自WS2000以来,每个操作系统都可以使用此功能。
现在,David Heffernan指向了MSDN文档,其中说您无法这样做。嗯,我不知道为什么会这样说,但它是不准确的。您可以这样做,事实上.NET Framework就是这样做的,只需使用.NET Reflector检查System.Windows.Forms.Form.Owner属性的代码 - 它使用SetWindowLong进行所有权转移,您可以随意使用!
而且,为了更多证据表明MSDN文档的不正确性,只需查看Owner属性的文档即可,它说“顶级窗口不能有所有者。” 它应该是完全相反的,只有顶级窗口可以有所有者!

1
@MathiasLykkegaardLorenzen,您能详细说明一下,到底哪里不正确吗? - Maurice Flanagan

2
private const int SW_HIDE = 0x00;
private const int SW_SHOW = 0x05;
private const int WS_EX_APPWINDOW = 0x40000;
private const int GWL_EXSTYLE = -0x14;
private const int WS_EX_TOOLWINDOW = 0x0080;

  private static void HideAppinTaskBar()
  {
  var Handle = FindWindowByCaption(IntPtr.Zero, "Untitled - Notepad");
  ShowWindow(Handle, SW_HIDE);
  SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) |     WS_EX_TOOLWINDOW);
  ShowWindow(Handle, SW_SHOW);
  }

这对我来说有效-经过notepad测试。 WinXp 32位机器。


将其设置为工具窗口还有其他含义。理想情况下,您需要使窗口拥有才能将其从任务栏中移除。 - David Heffernan
我同意这并不是最理想的情况 - 我将其从这里提出的 Delphi 问题中移植过来。 - Alex
谢谢,这至少接近我正在寻找的东西,但我仍在寻找更好的方法。 - René Sackers

0
这段代码适用于 WinUI3,需要在 .NET 6.0 上使用 PInvoke.User32 nuget 包:
代码改编自 Alex 的回答。
private void HideAppFromTaskBar(MainWindow window)
{
    //Get the Window's HWND
    var windowNative = window.As<IWindowNative>();
    var windowHandle = windowNative.WindowHandle;

    User32.ShowWindow(windowHandle, User32.WindowShowStyle.SW_HIDE);
    var flags = (User32.SetWindowLongFlags)User32.GetWindowLong(windowHandle, User32.WindowLongIndexFlags.GWL_EXSTYLE);
    User32.SetWindowLong(windowHandle, User32.WindowLongIndexFlags.GWL_EXSTYLE, flags | User32.SetWindowLongFlags.WS_EX_TOOLWINDOW);
    User32.ShowWindow(windowHandle, User32.WindowShowStyle.SW_SHOW);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接