22// SPDX-License-Identifier: GPL-3.0-or-later
33
44using System . Diagnostics ;
5+ using System . Runtime . InteropServices ;
56using System . Windows ;
67using System . Windows . Media ;
78using System . Windows . Media . Imaging ;
@@ -96,7 +97,20 @@ public static (string, ImageSource?) GetAndCacheMediaPlayerData(string mediaPlay
9697 } )
9798 . FirstOrDefault ( data => data != null ) ; // use first result
9899
99- if ( processData == null ) return ( mediaTitle , mediaIcon ) ;
100+ if ( processData == null )
101+ {
102+ var ( shellTitle , shellIcon ) = ResolveViaAppsFolder ( mediaPlayerId ) ;
103+ if ( shellTitle == null ) return ( mediaTitle , mediaIcon ) ;
104+
105+ mediaPlayerCache [ mediaPlayerId ] = new CachedMediaPlayerInfo
106+ {
107+ Title = shellTitle ,
108+ Icon = shellIcon ,
109+ ProcessId = - 1 // no process match, -1 avoids colliding with real PIDs
110+ } ;
111+
112+ return ( shellTitle , shellIcon ) ;
113+ }
100114
101115 mediaTitle = ! string . IsNullOrWhiteSpace ( processData . Title ) ? processData . Title : mediaPlayerId ;
102116
@@ -183,4 +197,38 @@ public static (string, ImageSource?) GetAndCacheMediaPlayerData(string mediaPlay
183197 return null ;
184198 }
185199 }
200+
201+ /// <summary>
202+ /// Resolves an AppUserModelId through the shell Apps folder ("shell:AppsFolder"),
203+ /// the same way the native media flyout does. Handles apps whose session id
204+ /// doesn't match their process path, e.g. Firefox-based browsers (#949).
205+ /// </summary>
206+ private static ( string ? Title , ImageSource ? Icon ) ResolveViaAppsFolder ( string appUserModelId )
207+ {
208+ try
209+ {
210+ var shellType = Type . GetTypeFromProgID ( "Shell.Application" ) ;
211+ if ( shellType == null ) return ( null , null ) ;
212+
213+ dynamic shell = Activator . CreateInstance ( shellType ) ! ;
214+ dynamic ? item = shell . NameSpace ( "shell:AppsFolder" ) ? . ParseName ( appUserModelId ) ;
215+ if ( item == null ) return ( null , null ) ;
216+
217+ string name = item . Name ;
218+ if ( string . IsNullOrWhiteSpace ( name ) ) return ( null , null ) ;
219+
220+ // desktop apps expose their start menu shortcut target, so the icon can
221+ // be extracted the same way as everywhere else; packaged apps don't
222+ // have one and keep a null icon
223+ var targetPath = item . ExtendedProperty ( "System.Link.TargetParsingPath" ) as string ;
224+ ImageSource ? icon = targetPath != null ? GetIconFromPath ( targetPath ) : null ;
225+
226+ return ( name , icon ) ;
227+ }
228+ catch
229+ {
230+ // id is not registered in the apps folder, nothing we can do
231+ return ( null , null ) ;
232+ }
233+ }
186234}
0 commit comments