using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; namespace CVRManager.Services; public static class GameWindow { const uint WM_SETICON = 0x0080; const int ICON_SMALL = 0; const int ICON_BIG = 1; const int SM_CXICON = 11; const int SM_CXSMICON = 49; delegate bool EnumProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] static extern bool EnumWindows(EnumProc proc, IntPtr lParam); [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint pid); [DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr hwnd); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetClassName(IntPtr hwnd, StringBuilder name, int max); [DllImport("user32.dll", SetLastError = true)] static extern IntPtr SendMessageTimeout(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, uint flags, uint timeout, out IntPtr result); const uint SMTO_ABORTIFHUNG = 2; [DllImport("user32.dll")] static extern int GetSystemMetrics(int index); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern uint PrivateExtractIcons(string file, int index, int cx, int cy, IntPtr[] icons, uint[] ids, uint count, uint flags); static IntPtr FindUnityWindow(int pid) { var found = IntPtr.Zero; var name = new StringBuilder(64); EnumWindows((hwnd, _) => { GetWindowThreadProcessId(hwnd, out var owner); if (owner != pid || !IsWindowVisible(hwnd)) return true; name.Clear(); GetClassName(hwnd, name, name.Capacity); if (name.ToString() == "UnityWndClass") found = hwnd; return true; }, IntPtr.Zero); return found; } static void SetIcons(IntPtr hwnd, string exe) { foreach (var (kind, size) in new[] { (ICON_SMALL, GetSystemMetrics(SM_CXSMICON)), (ICON_BIG, GetSystemMetrics(SM_CXICON)) }) { var icons = new IntPtr[1]; var ids = new uint[1]; if (PrivateExtractIcons(exe, 0, size, size, icons, ids, 1, 0) > 0 && icons[0] != IntPtr.Zero) SendMessageTimeout(hwnd, WM_SETICON, (IntPtr)kind, icons[0], SMTO_ABORTIFHUNG, 1000, out _); } } public static async Task ApplyIconWhenReadyAsync(Process proc, string exe) { if (!OperatingSystem.IsWindows()) return; try { var hwnd = IntPtr.Zero; for (var i = 0; i < 240 && hwnd == IntPtr.Zero; i++) { if (proc.HasExited) return; hwnd = FindUnityWindow(proc.Id); if (hwnd == IntPtr.Zero) await Task.Delay(250); } if (hwnd == IntPtr.Zero) return; foreach (var wait in new[] { 0, 3000, 7000, 20000 }) { await Task.Delay(wait); if (proc.HasExited) return; var current = FindUnityWindow(proc.Id); if (current != IntPtr.Zero) SetIcons(current, exe); } } catch (InvalidOperationException) { } } }