Initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using IPClab1.Enums;
|
||||
|
||||
namespace IPClab1.Services;
|
||||
|
||||
public class WindowInteractionService
|
||||
{
|
||||
private const uint WM_MOUSEMOVE = 0x0200;
|
||||
private const uint WM_LBUTTONDOWN = 0x0201;
|
||||
private const uint WM_LBUTTONUP = 0x0202;
|
||||
private const uint WM_SETTEXT = 0x000C;
|
||||
private const uint WM_CLOSE = 0x0010;
|
||||
private const uint WM_SYSCOMMAND = 0x0112;
|
||||
|
||||
private const int SC_MINIMIZE = 0xF020;
|
||||
private const int SC_MAXIMIZE = 0xF030;
|
||||
private const int SC_RESTORE = 0xF120;
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
// 1. Get Class Name
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
|
||||
// 2. Get Geometry
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
||||
|
||||
// 3. Get Parent
|
||||
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr GetParent(IntPtr hWnd);
|
||||
|
||||
public void SimulateClick(IntPtr hwnd, int x, int y)
|
||||
{
|
||||
IntPtr lParam = (IntPtr)((y << 16) | (x & 0xFFFF));
|
||||
PostMessage(hwnd, WM_MOUSEMOVE, IntPtr.Zero, lParam);
|
||||
PostMessage(hwnd, WM_LBUTTONDOWN, (IntPtr)1, lParam);
|
||||
PostMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, lParam);
|
||||
}
|
||||
|
||||
public void SetText(IntPtr hwnd, string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return;
|
||||
SendMessage(hwnd, WM_SETTEXT, IntPtr.Zero, text);
|
||||
}
|
||||
|
||||
public void SetWindowState(IntPtr hwnd, WindowState state)
|
||||
{
|
||||
IntPtr wParam = state switch
|
||||
{
|
||||
WindowState.Minimize => (IntPtr)SC_MINIMIZE,
|
||||
WindowState.Maximize => (IntPtr)SC_MAXIMIZE,
|
||||
WindowState.Restore => (IntPtr)SC_RESTORE,
|
||||
_ => IntPtr.Zero
|
||||
};
|
||||
|
||||
if (wParam != IntPtr.Zero)
|
||||
{
|
||||
PostMessage(hwnd, WM_SYSCOMMAND, wParam, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseWindow(IntPtr hwnd)
|
||||
{
|
||||
PostMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public (int, int) GetWindowSize(IntPtr hwnd)
|
||||
{
|
||||
GetWindowRect(hwnd, out RECT rect);
|
||||
return (rect.Width, rect.Height);
|
||||
}
|
||||
|
||||
public string GetWindowDetails(IntPtr hwnd)
|
||||
{
|
||||
StringBuilder classNameBuffer = new StringBuilder(256);
|
||||
GetClassName(hwnd, classNameBuffer, classNameBuffer.Capacity);
|
||||
string className = classNameBuffer.ToString();
|
||||
|
||||
GetWindowRect(hwnd, out RECT rect);
|
||||
|
||||
IntPtr parentHWnd = GetParent(hwnd);
|
||||
bool isChild = (parentHWnd != IntPtr.Zero);
|
||||
|
||||
return @$"Класс окна: {className}
|
||||
Положение: (x, y) = ({rect.Left}, {rect.Top})
|
||||
Размер: (w, h) = ({rect.Width}, {rect.Height})
|
||||
Является дочерним: {(isChild ? "да" : "нет")}{(isChild ? $"\nРодительское окно: 0x{parentHWnd.ToInt64():X}" : "")}";
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
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 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);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool IsWindowVisible(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetClassLongPtr", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetClassLong", CharSet = CharSet.Auto)]
|
||||
private static extern uint GetClassLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern 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
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of structs representing all visible top-level windows with titles and native WinUI 3 icons.
|
||||
/// </summary>
|
||||
public async Task<List<WindowInfo>> GetVisibleWindowsAsync(bool onlyVisible)
|
||||
{
|
||||
var windowList = new List<WindowInfo>();
|
||||
var handles = new List<IntPtr>();
|
||||
|
||||
// 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
|
||||
int length = GetWindowTextLength(hWnd);
|
||||
var builder = new StringBuilder(length + 1);
|
||||
GetWindowText(hWnd, builder, builder.Capacity);
|
||||
string title = builder.ToString();
|
||||
|
||||
// Fetch numeric process identifier
|
||||
GetWindowThreadProcessId(hWnd, out uint 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)
|
||||
{
|
||||
IntPtr 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<SoftwareBitmapSource> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user