WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Cannot set the taskbar icon

Open Boontje opened this issue 2 years ago • 10 comments

Describe the bug

Setting the icon for the app/window using the net 'SetIcon' function on the AppWindow, sets the icon for the title bar but not for the Windows Taskbar.

Steps to reproduce the bug

Create a new blank WinUI project.

Replace the code for 'mybutton_click' with:

private void myButton_Click(object sender, RoutedEventArgs e) { // set icon in taskbar string iconPath = @"C:\Program Files\Internet Explorer\images\bing.ico";

        IntPtr hWnd = WindowNative.GetWindowHandle(this);
        WindowId myWndId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
        var appWindow = AppWindow.GetFromWindowId(myWndId);
        appWindow.SetIcon(iconPath);

        myButton.Content = "Clicked";
    }

Run the project. Click the button, the icon in the title bar will be updated to Bing icon. But the icon in the Taskbar will stay the same.

Expected behavior

Icon in the taskbar to be updated as well

Screenshots

No response

NuGet package version

1.1.2

Packaging type

Packaged (MSIX)

Windows version

Windows 11 version 21H2 (22000)

IDE

Visual Studio 2022

Additional context

No response

Boontje avatar Jul 14 '22 09:07 Boontje

Probably belongs in the https://github.com/microsoft/microsoft-ui-xaml repository.

Repro project for others: issue_2730.zip

@rkarman suspect this is in your area. MUX bug or WM_SETICON regression?

riverar avatar Jul 14 '22 17:07 riverar

This only happens if the app is packaged. If the app is unpackaged, it works just fine.

Link1J avatar Jul 14 '22 20:07 Link1J

This only happens if the app is packaged.

In that case, this behavior is by design. If you are running packaged, you need to edit the assets referenced in your AppX manifest. Other ways of setting the taskbar icon will not be honored. Unfortunately, getting this right is very difficult, due to how many different PNGs are needed, and the fact that VS will not generate all of them. IIRC the manifest editor would generate “regular” unplated assets, but not light-mode unplated assets. Without separate light-mode unplated assets, the user will see a colored box instead of your precisely drawn icon if they are running the Start menu in light mode, which I believe has been the default for many Windows builds now. You will need to manually duplicate the altform_unplated assets and change the names of the copies to altform_lightunplated. Hope this helps!

wjk avatar Jul 20 '22 21:07 wjk

The reason why I want to dynamically set the taskbar icon, is that the application needs to show a status or count as a small 'icon in icon'. If the taskbar icon is out of control of the app, is there another way to display an overlay icon?

Boontje avatar Jul 22 '22 10:07 Boontje

@Boontje Maybe ITaskbarList3::SetOverlayIcon is want you wanted? And it does work on Packaged Win32 Apps. https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setoverlayicon

EDIT: I would note that what the author of the issue was trying to do (set the taskbar icon) isn't even documented as something that WM_SETICON or AppWindow.SetIcon say they do. How the taskbar icon is set is undocumented and could change. In fact, since Windows 7, windows icon and taskbar icon aren't always the same thing. I was surprised to find that explorer.exe doesn't have a special trick to avoid changing icon on the taskbar, but that pinning the app to the taskbar is what did it.

Link1J avatar Jul 22 '22 11:07 Link1J

This only happens if the app is packaged.

In that case, this behavior is by design. If you are running packaged, you need to edit the assets referenced in your AppX manifest. Other ways of setting the taskbar icon will not be honored. [...]

@wjk Not sure I agree with that conclusion. If that's the case, this API should fail appropriately.

riverar avatar Aug 11 '22 05:08 riverar

@riverar But it is working as intended, as it is setting the window icon. They were relying on undocumented behavior, because the API doesn't say it sets the taskbar icon. In fact there is a scenario where the API fails to set the taskbar icon with unpackaged apps, pinning the app to the taskbar. And that scenario has been around since Windows 7.

What is needed is a SetOverlayIcon function on AppWindow, but that probably needs a its own issue.

Link1J avatar Aug 11 '22 14:08 Link1J

@Link1J No it's not.

The system displays a window's large class icon in the task-switch window that appears when the user presses ALT+TAB, and in the large icon views of the task bar and explorer. The small class icon appears in a window's title bar and in the small icon views of the task bar and explorer. [...] You can override the large or small class icon for a particular window by using the WM_SETICON message. You can retrieve the current large or small class icon by using the WM_GETICON message.

https://docs.microsoft.com/windows/win32/winmsg/about-window-classes#class-icons

riverar avatar Aug 11 '22 14:08 riverar

Also, looking under the covers (Microsoft.UI.Windowing.Core.dll), we can see AppWindow::SetIcon is implemented roughly as such. It seems the intent is to indeed set the taskbar icon.

iconHandleFromPath = Windowing::Icon::GetIconHandleFromPath(path);
Windowing::Icon::SetTaskBarIcon(hwnd, iconHandleFromPath);
Windowing::Icon::SetTitleBarIcon(hwnd, iconHandleFromPath);

riverar avatar Aug 11 '22 14:08 riverar

Well then, both AppWindow.SetIcon and WM_SETICON do a really bad job at setting the taskbar icon. Because here is an unpackaged app, where the taskbar icon and the window icon do not match. All I did was pin the app to the taskbar. image

So maybe documentation needs to be updated to match current behavior then? Because, the pinned app behavior has been in Windows since 7.

Link1J avatar Aug 11 '22 15:08 Link1J