I did this test on Windows 10 with a Button and a ListView, based on one of my old codes to enumerate windows, then with help from IA (Copilot, ChatGPT) to parse UWP Manifest to get icon (.png) :
To be improved/simplified...
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;
using Windows.Management.Deployment;
// Change Windows SDLK version and/or Windows Kits path...
// Add reference to "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd
namespace WPf_EnumDesktopWindows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public enum HRESULT : int
{
S_OK = 0,
S_FALSE = 1,
E_NOINTERFACE = unchecked((int)0x80004002),
E_NOTIMPL = unchecked((int)0x80004001),
E_FAIL = unchecked((int)0x80004005),
E_UNEXPECTED = unchecked((int)0x8000FFFF),
E_OUTOFMEMORY = unchecked((int)0x8007000E),
E_INVALIDARG = unchecked((int)0x80070057)
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool IsWindowEnabled(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpEnumFunc, ref IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
public const int GW_OWNER = 4;
public static long GetWindowLong(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 4)
{
return GetWindowLong32(hWnd, nIndex);
}
return GetWindowLongPtr64(hWnd, nIndex);
}
[DllImport("User32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Unicode)]
public static extern long GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("User32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Unicode)]
public static extern long GetWindowLongPtr64(IntPtr hWnd, int nIndex);
public const int GWL_STYLE = (-16);
public const int GWL_EXSTYLE = (-20);
public const int WS_OVERLAPPED = 0x00000000;
public const int WS_POPUP = unchecked((int)0x80000000L);
public const int WS_CHILD = 0x40000000;
public const int WS_MINIMIZE = 0x20000000;
public const int WS_VISIBLE = 0x10000000;
public const int WS_DISABLED = 0x08000000;
public const int WS_CLIPSIBLINGS = 0x04000000;
public const int WS_CLIPCHILDREN = 0x02000000;
public const int WS_MAXIMIZE = 0x01000000;
public const int WS_CAPTION = 0x00C00000; /* WS_BORDER | WS_DLGFRAME */
public const int WS_BORDER = 0x00800000;
public const int WS_DLGFRAME = 0x00400000;
public const int WS_VSCROLL = 0x00200000;
public const int WS_HSCROLL = 0x00100000;
public const int WS_SYSMENU = 0x00080000;
public const int WS_THICKFRAME = 0x00040000;
public const int WS_GROUP = 0x00020000;
public const int WS_TABSTOP = 0x00010000;
public const int WS_MINIMIZEBOX = 0x00020000;
public const int WS_MAXIMIZEBOX = 0x00010000;
public const int WS_TILED = WS_OVERLAPPED;
public const int WS_ICONIC = WS_MINIMIZE;
public const int WS_SIZEBOX = WS_THICKFRAME;
public const int WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW;
public const int WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
public const int WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU);
public const int WS_CHILDWINDOW = (WS_CHILD);
public const int WS_EX_DLGMODALFRAME = 0x00000001;
public const int WS_EX_NOPARENTNOTIFY = 0x00000004;
public const int WS_EX_TOPMOST = 0x00000008;
public const int WS_EX_ACCEPTFILES = 0x00000010;
public const int WS_EX_TRANSPARENT = 0x00000020;
public const int WS_EX_MDICHILD = 0x00000040;
public const int WS_EX_TOOLWINDOW = 0x00000080;
public const int WS_EX_WINDOWEDGE = 0x00000100;
public const int WS_EX_CLIENTEDGE = 0x00000200;
public const int WS_EX_CONTEXTHELP = 0x00000400;
public const int WS_EX_RIGHT = 0x00001000;
public const int WS_EX_LEFT = 0x00000000;
public const int WS_EX_RTLREADING = 0x00002000;
public const int WS_EX_LTRREADING = 0x00000000;
public const int WS_EX_LEFTSCROLLBAR = 0x00004000;
public const int WS_EX_RIGHTSCROLLBAR = 0x00000000;
public const int WS_EX_CONTROLPARENT = 0x00010000;
public const int WS_EX_STATICEDGE = 0x00020000;
public const int WS_EX_APPWINDOW = 0x00040000;
public const int WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
public const int WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
public const int WS_EX_LAYERED = 0x00080000;
public const int WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritence of mirroring by children
public const int WS_EX_NOREDIRECTIONBITMAP = 0x00200000;
public const int WS_EX_LAYOUTRTL = 0x00400000; // Right to left mirroring
public const int WS_EX_COMPOSITED = 0x02000000;
public const int WS_EX_NOACTIVATE = 0x08000000;
[DllImport("Dwmapi.dll", SetLastError = true)]
public static extern HRESULT DwmGetWindowAttribute(IntPtr hwnd, int dwAttributeToGet, ref int pvAttributeValue, int cbAttribute);
public enum DWMWINDOWATTRIBUTE
{
DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
DWMWA_CAPTION_BUTTON_BOUNDS,
DWMWA_NONCLIENT_RTL_LAYOUT,
DWMWA_FORCE_ICONIC_REPRESENTATION,
DWMWA_FLIP3D_POLICY,
DWMWA_EXTENDED_FRAME_BOUNDS,
DWMWA_HAS_ICONIC_BITMAP,
DWMWA_DISALLOW_PEEK,
DWMWA_EXCLUDED_FROM_PEEK,
DWMWA_CLOAK,
DWMWA_CLOAKED,
DWMWA_FREEZE_REPRESENTATION,
DWMWA_LAST
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "GetClassLong", CharSet = CharSet.Unicode)]
private static extern uint GetClassLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "GetClassLongPtr", CharSet = CharSet.Unicode)]
private static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex);
private static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
{
return GetClassLongPtr64(hWnd, nIndex);
}
else
{
return new IntPtr(unchecked(GetClassLong32(hWnd, nIndex)));
}
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern HRESULT SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid, [Out(), MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
[ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStore
{
HRESULT GetCount([Out] out uint propertyCount);
HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
HRESULT Commit();
}
public static PROPERTYKEY PKEY_AppUserModel_ID = new PROPERTYKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
public struct PROPERTYKEY
{
public PROPERTYKEY(Guid InputId, UInt32 InputPid)
{
fmtid = InputId;
pid = InputPid;
}
Guid fmtid;
uint pid;
};
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct PROPARRAY
{
public UInt32 cElems;
public IntPtr pElems;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct PROPVARIANT
{
[FieldOffset(0)]
public ushort varType;
[FieldOffset(2)]
public ushort wReserved1;
[FieldOffset(4)]
public ushort wReserved2;
[FieldOffset(6)]
public ushort wReserved3;
[FieldOffset(8)]
public byte bVal;
[FieldOffset(8)]
public sbyte cVal;
[FieldOffset(8)]
public ushort uiVal;
[FieldOffset(8)]
public short iVal;
[FieldOffset(8)]
public UInt32 uintVal;
[FieldOffset(8)]
public Int32 intVal;
[FieldOffset(8)]
public UInt64 ulVal;
[FieldOffset(8)]
public Int64 lVal;
[FieldOffset(8)]
public float fltVal;
[FieldOffset(8)]
public double dblVal;
[FieldOffset(8)]
public short boolVal;
[FieldOffset(8)]
public IntPtr pclsidVal; // GUID ID pointer
[FieldOffset(8)]
public IntPtr pszVal; // Ansi string pointer
[FieldOffset(8)]
public IntPtr pwszVal; // Unicode string pointer
[FieldOffset(8)]
public IntPtr punkVal; // punkVal (interface pointer)
[FieldOffset(8)]
public PROPARRAY ca;
[FieldOffset(8)]
public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool DestroyIcon(IntPtr handle);
[DllImport("Gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool DeleteObject(IntPtr hObject);
public const int WM_GETICON = 0x007F;
public const int ICON_SMALL2 = 2;
public const int ICON_SMALL = 0;
public const int ICON_BIG = 1;
public const int GCL_HICON = -14;
ImageSource GetWindowIcon(IntPtr hWnd)
{
IntPtr hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL2, IntPtr.Zero);
if (hIcon == IntPtr.Zero)
hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
if (hIcon == IntPtr.Zero)
hIcon = GetClassLongPtr(hWnd, GCL_HICON);
if (hIcon != IntPtr.Zero)
{
try
{
return Imaging.CreateBitmapSourceFromHIcon(
hIcon,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DestroyIcon(hIcon); // Or not, depending on how it's obtained
}
}
return null;
}
IntPtr m_hWnd = IntPtr.Zero;
public MainWindow()
{
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
}
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
m_hWnd = new WindowInteropHelper(this).Handle;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
lvWindows.Items.Clear();
EnumWindowsProc Callback = new EnumWindowsProc(ListWindows);
IntPtr plParam = IntPtr.Zero;
EnumDesktopWindows(IntPtr.Zero, Callback, ref plParam);
}
public class WindowItem
{
public ImageSource Icon { get; set; }
public string Title { get; set; }
}
public bool ListWindows(IntPtr hWnd, ref IntPtr lParam)
{
bool bOK = false;
long nStyle = GetWindowLong(hWnd, GWL_STYLE);
long nExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
if (
((nStyle & WS_CHILDWINDOW) != 0 || (nStyle & WS_VISIBLE) == 0)
||
((nStyle & WS_POPUP) != 0 && (nStyle & WS_CAPTION) == 0)
)
bOK = false;
else
{
if ((nExStyle & WS_EX_APPWINDOW) != 0)
bOK = true;
else if ((nExStyle & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE)) != 0)
// Windows with style WS_EX_TOOLWINDOW or WS_EX_NOACTIVATE never appear in the task list
bOK = false;
else
{
IntPtr hWndOwner = GetWindow(hWnd, GW_OWNER);
if (hWndOwner != IntPtr.Zero)
{
// Owned windows are typically not in taskbar unless they explicitly request it
bOK = (nExStyle & WS_EX_APPWINDOW) != 0;
}
else
{
bOK = true;
}
}
int nResult = 0;
HRESULT hr = DwmGetWindowAttribute(hWnd, (int)DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, ref nResult, Marshal.SizeOf(typeof(int)));
if (nResult != 0)
bOK = false;
}
if (bOK)
{
int nTextLength = GetWindowTextLength(hWnd);
if (nTextLength++ > 0)
{
StringBuilder sbText = new StringBuilder(nTextLength);
GetWindowText(hWnd, sbText, nTextLength);
if (hWnd != m_hWnd)
{
ImageSource icon = GetWindowIcon(hWnd);
if (icon is null)
{
IPropertyStore pPropertyStore;
Guid guid = new Guid("{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}");
HRESULT hr = SHGetPropertyStoreForWindow(hWnd, ref guid, out pPropertyStore);
string sAUMID = null;
if (hr == HRESULT.S_OK)
{
PROPVARIANT propVar = new PROPVARIANT();
hr = pPropertyStore.GetValue(ref PKEY_AppUserModel_ID, out propVar);
// Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
sAUMID = Marshal.PtrToStringUni(propVar.pwszVal);
if (sAUMID != "" && sAUMID != null)
{
string[] sParts = sAUMID.Split('!');
if (sParts.Length == 2)
{
string sFamilyName = sParts[0];
string sAppId = sParts[1];
var pm = new PackageManager();
var package = pm.FindPackagesForUser("", sFamilyName).FirstOrDefault();
if (package != null)
{
string manifestPath = System.IO.Path.Combine(package.InstalledLocation.Path, "AppxManifest.xml");
if (System.IO.File.Exists(manifestPath))
{
XDocument manifest = XDocument.Load(manifestPath);
XNamespace ns = "http://schemas.microsoft.com/appx/manifest/uap/windows10";
var appElem = manifest.Root.Descendants()
.FirstOrDefault(e => e.Name.LocalName == "Application" &&
(string)e.Attribute("Id") == sAppId);
if (appElem != null)
{
var visual = appElem.Descendants(ns + "VisualElements").FirstOrDefault();
if (visual != null)
{
// "Assets\\CalculatorAppList.png"
string sIconPath = (string)visual.Attribute("Square44x44Logo");
// "C:\\Program Files\\WindowsApps\\Microsoft.WindowsCalculator_11.2502.2.0_x64__8wekyb3d8bbwe"
string sPackagePath = package.InstalledLocation.Path;
// Get directory and base filename
string sIconDir = System.IO.Path.Combine(sPackagePath, System.IO.Path.GetDirectoryName(sIconPath));
string sIconBase = System.IO.Path.GetFileNameWithoutExtension(sIconPath);
// List candidate PNGs
var sFiles = Directory.GetFiles(sIconDir, $"{sIconBase}*.png");
// Try to pick the best match (scale-200 preferred, fallback to others)
string[] sPreferred = { "scale-200", "targetsize-32", "targetsize-48", "scale-100" };
string sPicked = sFiles
.FirstOrDefault(f => sPreferred.Any(p => f.Contains(p)))
?? sFiles.FirstOrDefault(); // fallback to any found
if (sPicked != null)
{
// Open the file as a stream
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(sPicked, UriKind.Absolute);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze(); // Optional: for cross-thread use
icon = bitmap;
}
}
}
}
}
}
}
Marshal.ReleaseComObject(pPropertyStore);
}
}
var sTitle = sbText.ToString();
Application.Current.Dispatcher.Invoke(() =>
{
lvWindows.Items.Add(new WindowItem
{
Icon = icon,
Title = sTitle
});
});
}
}
}
return true;
}
}
}
Basic MainWindow.xaml for Button + ListView :
<Window x:Class="WPf_EnumDesktopWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPf_EnumDesktopWindows"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<!--<RowDefinition Height="Auto"></RowDefinition>-->
<!--<RowDefinition Height="*"></RowDefinition>-->
</Grid.RowDefinitions>
<Button Content="Button" Grid.Row="0" HorizontalAlignment="Left" Height="35" Margin="51,39,0,0" VerticalAlignment="Top" Width="102" Click="Button_Click"/>
<ListView x:Name="lvWindows" Grid.Row="1" Height="300" Margin="10">
<ListView.View>
<GridView>
<GridViewColumn Header="Icon" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Width="32" Height="32" Source="{Binding Icon}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" Width="300" DisplayMemberBinding="{Binding Title}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>