Add Jumplist 'Run as Administrator' to Taskbar on Windows#6913
Add Jumplist 'Run as Administrator' to Taskbar on Windows#6913TravisEz13 merged 13 commits intoPowerShell:masterfrom
Conversation
|
|
| <DefineConstants>$(DefineConstants);CORECLR</DefineConstants> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup Condition=" '$(Configuration)' == 'Linux' "> |
There was a problem hiding this comment.
Configuration Linux has been removed. See Common Props for how to conditionally remove for Non-Windows.
There was a problem hiding this comment.
Thanks, I addressed that.
TravisEz13
left a comment
There was a problem hiding this comment.
I reviewed, but since this a WIP... I'm just marking my place.
|
@TravisEz13 Thanks for having a quick look and the helpful comments. I finished the last cleanup items and it is now not WIP any more. I manually tested it already on a clean VM with one of the early AppVeyor build artifacts. |
|
@bergmeister Would performance be better if you checked if we already are registered and don't register? Also, I need to run compliance tools due to some changes you made. I'm going to mark this as WIP again until the compliance tools say this change is good. |
|
@TravisEz13 By 'registered', do you mean if the jumplist has already been populated? As far as I am aware the Windows APIs for the jumplist, do not have 'Get' methods to check their current state (but I might be wrong). Any pointers are welcome. |
|
@bergmeister No compliance issue with your new code
That answered my question. |
|
restarted macOS due to #6915 |
| { | ||
| if (hResult < 0) | ||
| { | ||
| throw new Exception($"HResult from COM call was negative, which indicates a failure. Was: '{hResult}'"); |
There was a problem hiding this comment.
We use explicit formating in our code and never use the operator $().
Is the message is user-faced? If so we should move it in resource file.
There was a problem hiding this comment.
Good point. I was thinking about this more after I opened the PR. Initially I wrote it as a check to make sure all COM calls were successful at each stage during development. Looking at it again now, it is probably better to not throw but instead make the function return/stop prematurely (which should not be a problem because we haven't commited the transaction)
| private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned) | ||
| { | ||
| Dbg.Assert(null != cpp, "CommandLine parameter parser cannot be null."); | ||
| Dbg.Assert(cpp != null, "CommandLine parameter parser cannot be null."); |
There was a problem hiding this comment.
Should we replace the assert with throw?
There was a problem hiding this comment.
No strong opinion on this one, this line was only changed because the code style checker flagged it up that null was on the left hand side (which is only necessary in C/C++ but not C#)
|
@TravisEz13 I had a more detailed look and the WPF implementation seems to have a 'get' method: https://msdn.microsoft.com/en-us/library/system.windows.shell.jumplist.getjumplist(v=vs.110).aspx In general I should also note that I managed to port a subset of the WindowsApiPack to .Net Core and also have a prototype to populate an elevated jumplist with that, which has slightly more advanced techniques (synclock, UI permission checks, etc.) but it would also require bringing in 100 times more code, hence why this PR aims only for a minimal port of the existing Windows PowerShell code, which should be at least better performance wise. |
…instead of throwing an exception. Since this now not a user facing string any more, I do not think it is worth having the StringUtil.Format wrapper for it
|
Does that slow down the PowerShell Core start? |
|
I have not measured it but I could not feel a difference. It also only affects pwsh on Windows when it is being opened in an actual window. |
|
I guess we get this easily with .Net Core 3.0 - right? |
|
Maybe but even now I think WPF does not offer the APIs needed for elevation. .Net Core 3 development has only just started and realistically speaking, the chance that they will be delayed is high and they are probably going to deliver a MVP first. But it is not a reason against this PR because one can just delete the folder that I added, so there is no deep integration that would make it difficult to take out in the future |
|
.Net Framework has System.Windows.Shell.JumpList (STA only) |
|
Yes, but the classes in full .net do not support elevated JumpList entries. |
|
@SteveL-MSFT Do we want to measure perf before accepting this? |
|
I could give you a measurement using the Stopwatch class when being compiled in Release and CrossGen'd to give you a rough number. Hardware would be either a 7th Gen i7 Notebook processor or an Azure VM size of your choice. |
|
The code remove one extra mouse click in GUI. This seems to be a very expensive solution, given that there are many non-interactive scenarios. |
|
Expensive in terms of what? In non-interactive scenarios, the only overhead is one call to get the startupinfo and then the algorithm will not proceed. |
Over 600 code lines to add one menu item. |
|
The main code is just the 90 lines in the TaskbarJumpList file, which was a port of the existing Windows PowerShell C++ code in the referenced MainEntry.cpp |
|
@bergmeister I'm trying to understand the need for this change, the difficulty in supporting and the negative impact on the start. So far I can take it but I don't see much benefits. |
|
The benefit of this feature is that it halves the time/clicks to open an elevated pwsh shell, brings consistency with Windows PowerShell in terms of user experience and having one less click to do reduces muscle strain in the long term. This issue got opened by a community member in the first place and other people are getting excited about this as well: https://twitter.com/CBergmeister/status/996873883268648960?s=19 The difficulty in writing/supporting this feature is the lack of support for this scenario from the Windows/.Net side: I have not measured the exact performance impact yet but I think it is minimal and negligible. |
…o JumpListStartAsAdmin_COM
|
@TravisEz13 @iSazonov @SteveL-MSFT I measured the performance impact using the Is this OK performance wise since the performance impact only happens when a JumpList can be provided? Otherwise we would have to do something like kicking the work off in a background thread. I am not an expert on COM/Interop performance but I think there is not much potential for optimisation. When the PowerShell host moves back to STA I would expect a performance increase though.
|
…ow (and exit even earlier when being in a non-interactive thread) This reduces the overhead to less than 1ms when the shell is not owning the current window
| GetStartupInfo(out StartUpInfo startupInfo); | ||
| var STARTF_TITLEISLINKNAME = 0x00000800; | ||
| if (startupInfo.lpTitle == null || (startupInfo.dwFlags & STARTF_TITLEISLINKNAME) != STARTF_TITLEISLINKNAME) | ||
| if (Environment.UserInteractive) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Lol. I will remove it then. The idea behind this was to not even have a single COM call in non-interactive mode (but it will should stop after the call to getstartupinfo then)
There was a problem hiding this comment.
I think it should be PowerShell internal flag - whether it interacts with an user.
…urns true). In non-interactive mode the algorithm will stop after the call to getstartupinfo then
|
@bergmeister Thanks for your contribution! I am delighted that you have found this solution. |



PR Summary
travisez13: marking as WIP while I run compliance tools to make sure this doesn't break any compliance rules. Don't remove WIP until I've signed off on compliance issuesCloses #6649
This is a port of existing C++ Windows PowerShell code from MainEntry.cpp
Some of the code has been copied and minified from the WindowsApiPack.
The code is not compiled for
Linux(not sure also another condition is needed for Windows on ARM?).The code checks if the PowerShell process has a window handle by checking the startupinfo and only then tries to populate the list (and also checks if there is a slot available in the jumplist).
Tested on Windows 10 1803, jumpLists have been supported in Windows since Windows 7, which matches what PowerShell Core supports.
This is how it looks like:
Note that I found that on WinServer 2012 R2, the icon does not recognised and is empty instead, I tried using the
SetIconLocationmethod to point it to the ico file instead (which works on Win10) but it did not work on WinServer2012R2, therefore I suspect I have either an odd VM or it is an OS bug. Since this is only a minor optical and non-functional detail on a less common OS, I think this is OK.PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.[feature]if the change is significant or affects feature tests