WindowsAppSDK
WindowsAppSDK copied to clipboard
Cannot set the taskbar icon
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
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?
This only happens if the app is packaged. If the app is unpackaged, it works just fine.
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!
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 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.
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 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 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
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);
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.
So maybe documentation needs to be updated to match current behavior then? Because, the pinned app behavior has been in Windows since 7.