Question

I have been struggling to hide another application from the taskbar from my application.
I have been using the SetWindowLong function in order to set/remove WS_EX_APPWINDOW on the extended style.

I have tried both setting and removing the property individually as well as taking the current WindowLong, and removing/adding it to that one, like so:

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

And tried removing it like so:

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

Also tried both those methods without first getting the window long. Here is my entire code:

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

I have noticed changes in Spy++ looking at the properties. I had a bunch of different results, like WS_EX_APPWINDOW being added, but also randomly have other attributes disappearing, etc.
When looking at the messages, I also saw that it DID get messages like STYLE_CHANGED.

Any help would be appreciated,
René

Was it helpful?

Solution

The rules for determining which windows have buttons on the taskbar are documented on MSDN. Raymond Chen gives the following summary of these rules:

There are some basic rules on which windows go into the taskbar. In short:

  • If the WS_EX_APPWINDOW extended style is set, then it will show (when visible).
  • If the window is a top-level unowned window, then it will show (when visible).
  • Otherwise it doesn't show.

The fact that you are trying to modify a window in another app severely hampers you. You are removing the WS_EX_APPWINDOW extended style. This is not enough because the window in question will be a top-level unowned window (see bullet point 2). You cannot change the owner of a window once it has been created and since the window is controlled by another process you are pretty much stuck.

The only option remaining is to remove the WS_EX_APPWINDOW extended style and replace it with WS_EX_TOOLWINDOW. This will indeed get the window off the taskbar but it will change the appearance of the window:

The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE.

OTHER TIPS

Here is how I do this.

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)

This will remove the target window from the taskbar and alt tab. This will work on every OS since WS2000 at least.

Now, David Heffernan pointed to the MSDN documentation which says you can't do this. Well, I don't know why it says that but its inaccurate. You can do this and INFACT the .NET Framework does this, just use .NET Reflector to examine the code for System.Windows.Forms.Form.Owner property - it uses SetWindowLong to transfer ownership, as often as you would like!

And for more evidence of incorrect MSDN documentation, look no further than the docs for the Owner property, it says "A top-level window cannot have an owner." it should be the exact opposite of this, ONLY top-level windows can have an owner!

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

This works for me - tested with notepad. WinXp 32 Bit machine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top