Can the taskbar icon of a Unity game be hidden?

I want to hide/remove the game’s taskbar icon without hiding the game window itself. Since there is no simple option in Unity to do this, I have tried hiding the icon using WS_EX_TOOLWINDOW, following this example:
c# - Hiding an application from the taskbar - Stack Overflow, but had no luck.
Here: Make application close to the tray. - Questions & Answers - Unity Discussions, it is suggested that “-batchmode” can hide the taskbar icon, which is true but this command hides the window too.

Achieving this should be possible since here: c# - Place an application's icon into system tray - Stack Overflow, using WS_EX_TOOLWINDOW someone was able to hide the icon so I am definitely doing something wrong. This is how my code looks like right now:

        [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 GWL_EXSTYLE = -0x14;
        private const int WS_EX_TOOLWINDOW = 0x0080;
  
        void Start()
        {
            IntPtr pMainWindow = Process.GetProcessesByName("Game")[0].MainWindowHandle;
            ShowWindow(pMainWindow, SW_HIDE);
            SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | ~WS_EX_TOOLWINDOW);
            ShowWindow(pMainWindow, SW_SHOW);
        }

Just to be clear, I’m talking about this taskbar icon:

Did you check the logs?
you can find the logs here (replace username, CompanyName, ProductName): C:\Users\username\AppData\LocalLow\CompanyName\ProductName\Player.log

It is likely that the process cannot be found and throws an exception. But you are trying to access the currentProcess anyway I guess, so you could simply use Process.GetCurrentProcess().

For the actual interop and logic I am not an expert and cannot tell you if that code would work or not.

1 Like

Line 17 looks problem-prone to me. When I’ve done this sort of thing in the past I’ve used:

        [DllImport("user32.dll")]
        static extern IntPtr GetActiveWindow();

maybe try that instead to assign your pMainWindow?

1 Like

Thanks a lot, got it working. Part of the problem was indeed that the process/window could not be found, but with @StarManta ‘s suggestion, using GetActiveWindow() the window can be found and then to hide the taskbar you have to make the window a tool window using WS_EX_TOOLWINDOW. It’s important that you DON’T use the "~’" character because that is I assume for removing attributes. So anyway thanks a lot for the help and here is the final code to remove the taskbar icon of a Unity application:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using UnityEngine;

public class HideTaskbarIcon : MonoBehaviour
{
    [DllImport("user32.dll")]
    static extern IntPtr GetActiveWindow();
    [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);

    private const int GWL_EXSTYLE = -0x14;
    private const int WS_EX_TOOLWINDOW = 0x0080;

    void Start()
    {
        IntPtr pMainWindow = GetActiveWindow();
        SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);  
    }
}
2 Likes

.

Be careful that your game is indeed the Active Window. Not always true if some other window is active (like running your game through another process). Also, ~ is a bitwise inversion, ~WS_EX_TOOLWINDOW means ‘all bits EXCEPT WS_EX_TOOLWINDOW’.

1 Like

Right, you would use it as a mask to get rid of the bit. However for that you would use the bitwise and operator. So while this line does set the bit:

SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);

this line would remove it:

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

but still keep all other bits that were set before.