I want to get a list of applications that are installed and executable on Windows 10 -- i.e. executables of applications a user can launch (UWP and non-UWP). For UWP apps, I want to get its AppUserModelId. For non-UWP apps, I want to get the executable's file location.
So far, I have tried:
1) Going through the registry and iterate through the installed applications. However, this method goes through all installed applications, the returned list would include things like microsoft asp.net core 2.1.8 shared framework (x64)
, which I want to eliminate.
2) I found that I can access what I wanted through the special Appsfolder
, by typing shell:Appsfolder
into either the explorer window or Run. So far I was able to get access to this folder, and iterate through the items and list the names of the files. But I am not sure how to collect information on AppUserModelId (for UWP apps) and filepath (for WPF apps).
Relevant code I used to enumerate Appsfolder files:
namespace AppsFolder
{
...
public static class AppsFolder
{
...
// GUID for shell:Appsfolder
public static readonly Guid KnownFolderID = new Guid("1e87508d-89c2-42f0-8a7e-645a0f50ca58");
public static IEnumerable<string> GetItemNames(ESHGDN gdn)
{
IShellFolder appsFolder = GetAppsFolder();
try
{
IntPtr enumIDListInterfacePointer;
appsFolder.EnumObjects(IntPtr.Zero,
ESHCONTF.SHCONTF_NONFOLDERS | ESHCONTF.SHCONTF_FOLDERS,
out enumIDListInterfacePointer);
using (var enumIDList = new
EnumIDListWrapper(enumIDListInterfacePointer))
{
var names = new List<string>();
foreach (var pidl in enumIDList)
{
STRRET name;
recycleBin.GetDisplayNameOf(
pidl.DangerousGetHandle(),
gdn,
out name);
names.Add(STRRETToString(ref name, pidl));
if (name.uType != (int)STRRETType.Offset)
Marshal.FreeCoTaskMem(name.data.pOleStr);
}
return names;
}
}
finally
{
Marshal.FinalReleaseComObject(recycleBin);
}
}
private static IShellFolder GetAppsFolder()
{
IShellFolder desktop;
NativeMethod.SHGetDesktopFolder(out desktop);
try
{
Guid shellFolderInterfaceId = typeof(IShellFolder).GUID;
IntPtr recycleBinShellFolderInterfacePointer;
desktop.BindToObject(
GetItemIDList().DangerousGetHandle(),
IntPtr.Zero,
ref shellFolderInterfaceId,
out recycleBinShellFolderInterfacePointer);
return (IShellFolder)Marshal.GetObjectForIUnknown(
recycleBinShellFolderInterfacePointer);
}
finally
{
Marshal.FinalReleaseComObject(desktop);
}
}
public static SafeCoTaskMemHandleZeroIsInvalid GetItemIDList()
{
SafeCoTaskMemHandleZeroIsInvalid pidl;
Guid guid = KnownFolderID;
NativeMethod.SHGetKnownFolderIDList(
ref guid, 0, IntPtr.Zero, out pidl);
return pidl;
}
}
}
Executed as:
string[] names = AppsFolder.GetItemNames(AppsFolder.ESHGDN.SHGDN_INFOLDER).ToArray();
for (int i=0; i<names.Length; i++)
{
Console.WriteLine(names[i]);
}
The ILaunchSourceAppUserModelID
interface provides a method to get the AppUserModelID, but I'm not sure how to get access to this interface through my IShellFolder interface. Also, how do I get the actual file location within the AppsFolder virtual folder to actual exe's filepath?