using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using IPClab1.Models;
using Microsoft.UI.Xaml.Media.Imaging;
using Windows.Graphics.Imaging;
namespace IPClab1.Services;
public partial class WindowListService
{
#region Win32 P/Invoke Declarations
private const uint WM_GETICON = 0x007F;
private const IntPtr ICON_SMALL = 0;
private const IntPtr ICON_BIG = 1;
private const IntPtr ICON_SMALL2 = 2;
private const int GCLP_HICON = -14;
private const int GCLP_HICONSM = -34;
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool IsWindowVisible(IntPtr hWnd);
[LibraryImport("user32.dll", EntryPoint = "GetWindowTextW", SetLastError = true)]
private static partial int GetWindowText(IntPtr hWnd, [Out] char[] lpString, int nMaxCount);
[LibraryImport("user32.dll", EntryPoint = "GetWindowTextLengthW", SetLastError = true)]
private static partial int GetWindowTextLength(IntPtr hWnd);
[LibraryImport("user32.dll", EntryPoint = "SendMessageW")]
private static partial IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[LibraryImport("user32.dll", EntryPoint = "GetClassLongPtrW")]
private static partial IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex);
[LibraryImport("user32.dll", EntryPoint = "GetClassLongW")]
private static partial uint GetClassLong32(IntPtr hWnd, int nIndex);
[LibraryImport("user32.dll", SetLastError = true)]
private static partial uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[LibraryImport("shell32.dll", EntryPoint = "ExtractIconW", StringMarshalling = StringMarshalling.Utf16)]
private static partial IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
private IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex)
{
return IntPtr.Size == 8 ? GetClassLongPtr64(hWnd, nIndex) : new IntPtr(GetClassLong32(hWnd, nIndex));
}
#endregion
///
/// Retrieves a list of structs representing all visible top-level windows with titles and native WinUI 3 icons.
///
public async Task> GetVisibleWindowsAsync(bool onlyVisible)
{
var windowList = new List();
var handles = new List();
// 1. Gather all raw visible window handles that actually contain titles
EnumWindows((hWnd, lParam) =>
{
if ((IsWindowVisible(hWnd) || !onlyVisible) && GetWindowTextLength(hWnd) > 0)
{
handles.Add(hWnd);
}
return true;
}, IntPtr.Zero);
// 2. Iterate and async decode titles, process info, and UI image references
foreach (var hWnd in handles)
{
// Fetch window text title cleanly
var length = GetWindowTextLength(hWnd);
var titleBuffer = new char[length + 1];
var actualLength = GetWindowText(hWnd, titleBuffer, titleBuffer.Length);
var title = actualLength > 0 ? new string(titleBuffer, 0, actualLength) : string.Empty;
// Fetch numeric process identifier
GetWindowThreadProcessId(hWnd, out var processId);
// Fetch and map the icon image synchronously/asynchronously into WinUI structures
SoftwareBitmapSource iconSource = await GetWinUi3IconAsync(hWnd);
windowList.Add(new WindowInfo
{
Hwnd = hWnd,
ProcessId = processId,
WindowTitle = title,
IconSource = iconSource
});
}
return windowList;
}
private Icon GetIconFromHwnd(IntPtr hWnd)
{
var hIcon = SendMessage(hWnd, WM_GETICON, ICON_BIG, IntPtr.Zero);
if (hIcon == IntPtr.Zero)
hIcon = SendMessage(hWnd, WM_GETICON, ICON_SMALL2, IntPtr.Zero);
if (hIcon == IntPtr.Zero)
hIcon = GetClassLongPtr(hWnd, GCLP_HICON);
if (hIcon == IntPtr.Zero)
hIcon = GetClassLongPtr(hWnd, GCLP_HICONSM);
if (hIcon != IntPtr.Zero)
{
try
{
using var rawIcon = Icon.FromHandle(hIcon);
return (Icon)rawIcon.Clone();
}
catch { /* Proceed to alternate extraction fallback */ }
}
try
{
GetWindowThreadProcessId(hWnd, out uint processId);
if (processId != 0)
{
using var proc = Process.GetProcessById((int)processId);
string exePath = proc.MainModule?.FileName;
if (!string.IsNullOrEmpty(exePath) && File.Exists(exePath))
{
IntPtr hExtracted = ExtractIcon(IntPtr.Zero, exePath, 0);
if (hExtracted != IntPtr.Zero && hExtracted != new IntPtr(1))
{
using var rawIcon = Icon.FromHandle(hExtracted);
return (Icon)rawIcon.Clone();
}
}
}
}
catch { /* Protection fallback */ }
return null;
}
private async Task GetWinUi3IconAsync(IntPtr hWnd)
{
using Icon icon = GetIconFromHwnd(hWnd);
if (icon == null) return null;
try
{
using Bitmap bitmap = icon.ToBitmap();
using var stream = new MemoryStream();
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
var decoder = await BitmapDecoder.CreateAsync(stream.AsRandomAccessStream());
var softwareBitmap = await decoder.GetSoftwareBitmapAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied);
var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(softwareBitmap);
return source;
}
catch
{
return null;
}
}
}