deployment-tools icon indicating copy to clipboard operation
deployment-tools copied to clipboard

Pinned taskbar app is orphaned after update

Open desjarlais opened this issue 4 years ago • 53 comments

Scenario: I publish a .NET 5 app using ClickOnce and then pin the app to the Windows taskbar. After pinning to the taskbar, if I update the app, it will be orphaned to the old version. The Start Menu app icon works fine after the update, it just seems to be the taskbar. Is there any way to work around having to unpin/repin the app icon post update?

desjarlais avatar Dec 06 '20 03:12 desjarlais

Investigating.

NikolaMilosavljevic avatar Dec 09 '20 21:12 NikolaMilosavljevic

This seemed to be working after installing VS 16.9.4, but that isn't the case anymore. For some reason the first update I pushed through ClickOnce seemed fine, but the next update after that, the issue came back.

desjarlais avatar May 03 '21 18:05 desjarlais

Do you have any update on when this issue will be resolved?

ckorlinchak avatar Sep 15 '21 15:09 ckorlinchak

I'm not sure what the current plan or status is for this, but I'm currently using a workaround of comparing the target of the shortcut with the current executing assembly path of my app.

The location of the pinned app is: C:\Users<username>\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar<appname.lnk

The target of that particular shortcut .lnk file is something like this: C:\Users<username>\AppData\Local\Apps\2.0\1LZPH5VH.RQ0\GQ7Z7W3A.ADA<abbreviated app folder name + long guid like value>\appname.exe

Not sure if there is a better way to do it, but I use Shell32 to pull the target location for comparison and then change that if they are different. Seems to work so far, but there is some extra work to make sure I'm not changing during debug mode.

desjarlais avatar Nov 01 '21 03:11 desjarlais

Not sure if you guys already knew this but there seems to be a difference in how the pinning is done. If you right-click the desktop icon and pin it that way, it runs and updates fine. If you run the application first then right-click to pin it from the taskbar then it always runs directly and bypasses update checking.

You can check the Properties/Details to compare - the former is a .appref-ms and the latter is a .lnk

simmotech avatar Nov 17 '21 11:11 simmotech

Indeed, i got the same issue. The crux of the problem is that in .NET (core) the application is separate from the launcher (Launcher.exe).

To work around this problem i plan to add the following logic into my application:

  • at every startup/shutdown check if the user has a *.lnk file to my application in the %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar folder
  • if they do, it means they created the "wrong" link to my app, because that link points to the local copy of the application
  • copy my app's proper link file from %appdata%\Microsoft\Windows\Start Menu\Programs\...\*.appref-ms into the %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar folder and remove the useless *.lnk file

e-master avatar Jan 21 '22 17:01 e-master

.appref-ms is the proper link and should be pinned. Pinning a running application would pin a link to app exe - subsequent runs would not go through ClickOnce.

NikolaMilosavljevic avatar Jan 21 '22 19:01 NikolaMilosavljevic

Fully agree. Except as of now it is impossible for users to pin .appref-ms when they right-click on a running .NET 5/6 ClickOnce app in the task bar and select Pin to taskbar. That's why i suggested to do an ugly workaround above.

e-master avatar Jan 21 '22 22:01 e-master

Does this work fine for .NET FX apps? Have you tried to enable shortcut creation for ClickOnce deployment?

NikolaMilosavljevic avatar Jan 21 '22 22:01 NikolaMilosavljevic

yes, i have the exact same app (multi-targeted to .net 4.5.2 and .net 5) and the .net 4.5.2 deployment can be pinned properly, but the .net 5 one cannot (well, links the local .exe instead).

Have you tried to enable shortcut creation for ClickOnce deployment?

I'm not sure exactly what you mean. I can see that both .net 4.5.2 and .net 5 create a shortcut in the Start menu, but i don't see anything shortcut related in my ClickOnceProfile.pubxml file, so i assume shortcut creation is on by default? Or perhaps is there some flag i can turn on in the .pubxml file?

e-master avatar Jan 21 '22 22:01 e-master

i assume you talked about the CreateDesktopShortcut flag. No, i don't use that in my .pubxml file. Do you think that would fix this issue? I can give it a try.

e-master avatar Jan 21 '22 22:01 e-master

Indeed, i got the same issue. The crux of the problem is that in .NET (core) the application is separate from the launcher (Launcher.exe).

To work around this problem i plan to add the following logic into my application:

  • at every startup/shutdown check if the user has a *.lnk file to my application in the %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar folder
  • if they do, it means they created the "wrong" link to my app, because that link points to the local copy of the application
  • copy my app's proper link file from %appdata%\Microsoft\Windows\Start Menu\Programs...*.appref-ms into the %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar folder and remove the useless *.lnk file

I'd be quite surprised if that worked. Pinning something to the taskbar is intentionally difficult to prevent abuse.

When you pin a .NET Framework ClickOnce application to the taskbar, the apprefms is pinned rather than the executable because ClickOnce somehow sets the same explicit AppUserModelID on the process that it starts (the .NET Framework in the target is probably cooperating). With .NET 5+, this isn't getting done because ClickOnce is starting the launcher rather than your application. You can test this by retrieving the AUMID of the current install of some ClickOnce application (IIRC it changes on each install or upgrade) and making a totally separate non-ClickOnce application that calls SetCurrentProcessExplicitAppUserModelID with that value. If you pin the test application, the pin will start the ClickOnce application instead of the test application.

I'm not sure how you can retrieve the correct AUMID at runtime from within your application. The most straightforward way to workaround the various ClickOnce issues is probably to use a custom launcher. It can call GetCurrentProcessExplicitAppUserModelID and pass it along to your application.

billybednar avatar Jan 21 '22 23:01 billybednar

I'd be quite surprised if that worked. Pinning something to the taskbar is intentionally difficult to prevent abuse.

You're right, simply moving the files around doesn't work, as designed by the system itself to prevent abuse.

I still found a workaround though. Currently the system creates a .lnk file when the user pins the clickonce application to the taskbar. Although i cannot (easily) programmatically pin/unpin the .appref-ms file, i can change the target of the .lnk file to point to the .appref-ms file. Just tested it manually, seems to work, can't see why it wouldn't work programmatically, but will test it next week.

@NikolaMilosavljevic - i tried with <CreateDesktopShortcut>True</CreateDesktopShortcut>. With that option my deployment created a shortcut for my application on the desktop. When i right-click on the desktop shortcut and select Pin to taskbar it works as expected, however it doesn't solve my original problem - users more often than not right-click on the running application in the task bar and pin right there, instead of finding the icon on the desktop/start menu. In this latter case pinning doesn't work, and i need to revert to the only ugly hack i could find so far described above.

e-master avatar Jan 22 '22 04:01 e-master

@billybednar

I'm not sure how you can retrieve the correct AUMID at runtime from within your application. The most straightforward way to workaround the various ClickOnce issues is probably to use a custom launcher. It can call GetCurrentProcessExplicitAppUserModelID and pass it along to your application.

Thanks for the suggestions. I will have to create a custom launcher anyways because of this bug https://github.com/dotnet/deployment-tools/issues/53, so i might as well try your suggestion.

e-master avatar Jan 22 '22 04:01 e-master

@billybednar - thanks a lot for the suggestions, it looks like it works.

To wrap up:

  • i created a custom launcher.exe where i call GetCurrentProcessExplicitAppUserModelID and pass the app user model id to my application as a process scoped environment variable (e.g.: CLICKONCE_APPUSERMODELID).
  • in my application if i can read the CLICKONCE_APPUSERMODELID, i set my app's app user model id to the same value using SetCurrentProcessExplicitAppUserModelID

Preliminary testing shows that it works perfectly. Finally the pinned icon is pointing to the .appref-ms, and it even works after application updates.

@NikolaMilosavljevic, I'd be happy to submit a PR, but so far there's no 'official' way of passing information from the launcher to the application (last time i tried to use process scoped environment variables to do that my PR #135 was rejected).

e-master avatar Jan 24 '22 16:01 e-master

Thanks @billybednar and @e-master - I did plan to experiment with GetCurrentProcessExplicitAppUserModelID and it seems that the model is working, that's great! No hard dates on timeline for updates in official Launcher, but it is certainly coming soon.

NikolaMilosavljevic avatar Jan 24 '22 16:01 NikolaMilosavljevic

Hi all. Is the expectation that this is a .NET 7.0 fix or before then?

SartorialOffense avatar Apr 07 '22 18:04 SartorialOffense

@billybednar, would you be willing to share your fix?

SartorialOffense avatar Apr 27 '22 19:04 SartorialOffense

Hi @NikolaMilosavljevic, is this fix likely to ship with .NET 7.0?

SartorialOffense avatar Aug 11 '22 14:08 SartorialOffense

The fix for this issue is likely localized to dotnet-mage tooling which ships on its own schedule. We do try to align with major .NET releases, i.e. 7.0 GA.

We're still tracking this issue for investigation and fix for 7.0.

NikolaMilosavljevic avatar Aug 11 '22 16:08 NikolaMilosavljevic

Thanks!

SartorialOffense avatar Aug 11 '22 18:08 SartorialOffense

I suppose 7.0.0-preview.2.22317.2 does not solve this issue? When can we expect a release (or preview release) that fixes this problem?

We are currently facing this problem, and we need a fix like... yesterday 😆

znakeeye avatar Sep 22 '22 10:09 znakeeye

I've investigated this issue and feel that the best option is to have Launcher set its own custom AppUserModel ID. Windows generates and assigns an ID to apps, but that value cannot be obtained using GetCurrentProcessExplicitAppUserModelID API.

Furthermore, once we have custom AppUserModel ID for Launcher, we should pass it to child process (.NET app), so it gets automatically assigned and not require any work on the app side.

To enable all this, we'd need to switch from using Process and ProcessStartInfo classes and use CreateProcess API. It's a bigger change than anticipated, but it will bring the best overall experience.

Still on 7.0 release timeline, just not ready for implementation or preview yet.

In the meantime, we'd like to get your opinion on alternative way of pinning apps to Taskbar, from Start Menu. It seems to work, but it does have a small side-effect of new icon (for .NET app) appearing in Taskbar, while the app is running.

NikolaMilosavljevic avatar Sep 30 '22 19:09 NikolaMilosavljevic

@NikolaMilosavljevic Very exciting, it would be great to have it fixed this year.

For the alternative way, do you mean having my users pin the app to the Taskbar from the shortcut on the Start Menu? We try and have them do this now and it does work - we don't see the double icons. Or do you mean something else? I have seen this with Java applications and it is a little confusing.

SartorialOffense avatar Oct 02 '22 23:10 SartorialOffense

@billybednar, would you be willing to share your fix?

See e-master's summary above. Unfortunately I don't have any code handy that I can share, but it only takes a few lines to implement it. The hard part is probably getting the tooling to package up both your application and your launcher in a clean way. I've only done it the quick-and-dirty way as a proof of concept by creating a .NET Framework project as a launcher, pasting the compiled test application into it, adding a few lines of code to start the test application, and publishing the launcher project from within Visual Studio.

I've investigated this issue and feel that the best option is to have Launcher set its own custom AppUserModel ID. Windows generates and assigns an ID to apps, but that value cannot be obtained using GetCurrentProcessExplicitAppUserModelID API.

In my experience, the application started by ClickOnce always uses an explicit ID set by ClickOnce and not the system generated one. I have some .NET Framework WinForms applications that use GetCurrentProcessExplicitAppUserModelID and it returns a value when the application is deployed with ClickOnce and nothing when run standalone. Have you found otherwise?

Edit: According to this (last bullet), ClickOnce does assign explicit IDs:

An example of this situation is the ClickOnce framework, which properly assigns AppUserModelIDs on behalf of the applications that it manages.

billybednar avatar Oct 03 '22 07:10 billybednar

@NikolaMilosavljevic Very exciting, it would be great to have it fixed this year.

For the alternative way, do you mean having my users pin the app to the Taskbar from the shortcut on the Start Menu? We try and have them do this now and it does work - we don't see the double icons. Or do you mean something else? I have seen this with Java applications and it is a little confusing.

Yes, that's the same workaround, which seems to work fine. I was getting a second icon, in my quick test.

NikolaMilosavljevic avatar Oct 03 '22 15:10 NikolaMilosavljevic

In my experience, the application started by ClickOnce always uses an explicit ID set by ClickOnce and not the system generated one. I have some .NET Framework WinForms applications that use GetCurrentProcessExplicitAppUserModelID and it returns a value when the application is deployed with ClickOnce and nothing when run standalone. Have you found otherwise?

Edit: According to this (last bullet), ClickOnce does assign explicit IDs:

An example of this situation is the ClickOnce framework, which properly assigns AppUserModelIDs on behalf of the applications that it manages.

Hmm, that's interesting as it did not work in my tests, on Windows 11. Thank you for sharing the pointer, I will follow up with ClickOnce runtime team if needed.

NikolaMilosavljevic avatar Oct 03 '22 15:10 NikolaMilosavljevic

Hmm, that's interesting as it did not work in my tests, on Windows 11.

That's strange. It has worked for me on Windows 7 and 10, but I've never tried 11.

billybednar avatar Oct 03 '22 17:10 billybednar

Hmm, that's interesting as it did not work in my tests, on Windows 11.

That's strange. It has worked for me on Windows 7 and 10, but I've never tried 11.

Yeah, I just double-checked - it works fine on Windows 11, as well.

NikolaMilosavljevic avatar Oct 17 '22 17:10 NikolaMilosavljevic

Will this be fixed and released along with dotnet mage 7.0?

SwedishBobby avatar Nov 10 '22 08:11 SwedishBobby