CVR Manager 1.0.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
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) { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user