diff --git a/App.config b/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/App.cs b/App.cs new file mode 100644 index 0000000..478c567 --- /dev/null +++ b/App.cs @@ -0,0 +1,263 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; +using System.Management; +using System.ComponentModel; +using System.Net.Http; +using System.Threading.Tasks; +using System.Text; + +namespace fix_lcu_window_bin +{ + internal class App + { + [DllImport("User32.dll", EntryPoint = "FindWindow")] + public extern static IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("User32.dll", EntryPoint = "FindWindowEx")] + public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int Width, int Height, int flags); + + [DllImport("user32.dll")] + private static extern uint GetDpiForWindow([In] IntPtr hmonitor); + + // 取commandline + private static string GetCommandLineByProcessId(int processId) + { + try + { + return GetCommandLineArgsCore(); + } + catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005) + { + return string.Empty; + } + catch (InvalidOperationException) + { + return string.Empty; + } + + string GetCommandLineArgsCore() + { + using (var searcher = new ManagementObjectSearcher( + "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + processId)) + using (var objects = searcher.Get()) + { + var @object = objects.Cast().SingleOrDefault(); + return @object?["CommandLine"]?.ToString() ?? ""; + } + } + } + + private static int GetProcessId(String processName) + { + Process[] processes = Process.GetProcesses(); + int iProcessId = 0; + + foreach (Process p in processes) + { + if (p.ProcessName == processName) + { + iProcessId = p.Id; + break; + } + } + + return iProcessId; + } + + private static (bool Available, int Port, string Token, string Protocol) CommandLineParser(string command) + { + Regex installAuthToken = new Regex(@"""--remoting-auth-token=(.*?)"""); + Regex installAppPort = new Regex(@"""--app-port=(.*?)"""); + + var portMatch = installAppPort.Match(command); + var tokenMatch = installAuthToken.Match(command); + + if (portMatch.Success && tokenMatch.Success) + { + return (true, int.Parse(portMatch.Groups[1].Value), tokenMatch.Groups[1].Value, "https"); + } + + return (false, 0, null, null); + } + + private static async Task GetLeagueClientZoom(int Port, String Token) + { + + String address = "https://127.0.0.1:" + Port + "/riotclient/zoom-scale"; + + WebRequestHandler handler = new WebRequestHandler(); + HttpClient client = new HttpClient(handler); + + handler.ServerCertificateValidationCallback = delegate { return true; }; + client.DefaultRequestHeaders.Add("Accept", "*/*"); + client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("riot:" + Token))); + try + { + HttpResponseMessage response = await client.GetAsync(address); + response.EnsureSuccessStatusCode(); + + return double.Parse(await response.Content.ReadAsStringAsync()); + } + catch + { + return -1; + } + } + + private static async Task RestartClientUx(int Port, String Token) + { + + string address = "https://127.0.0.1:" + Port + "/riotclient/kill-and-restart-ux"; + + WebRequestHandler handler = new WebRequestHandler(); + HttpClient client = new HttpClient(handler); + + handler.ServerCertificateValidationCallback = delegate { return true; }; + client.DefaultRequestHeaders.Add("Accept", "*/*"); + client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("riot:" + Token))); + try + { + HttpResponseMessage response = await client.PostAsync(address, new StringContent("")); + response.EnsureSuccessStatusCode(); + + return true; + } + catch + { + return false; + } + } + + private static void emitExit() + { + Console.WriteLine("按任意键退出..."); + Console.ReadKey(); + } + + private static async Task MethodPlanA() + { + var LeagueClientUxCommandLine = GetCommandLineByProcessId(GetProcessId("LeagueClientUx")); + var LeagueClientUxArgs = CommandLineParser(LeagueClientUxCommandLine); + + if (!LeagueClientUxArgs.Available) + { + Console.WriteLine("Can't find LeagueClientUx process."); + emitExit(); + return; + } + + IntPtr pLeagueClientWindowHWnd = FindWindow("RCLIENT", "League of Legends"); + IntPtr pLeagueClientWindowCefHWnd = FindWindowEx(pLeagueClientWindowHWnd, IntPtr.Zero, "CefBrowserWindow", null); + + if (pLeagueClientWindowHWnd == IntPtr.Zero || pLeagueClientWindowCefHWnd == IntPtr.Zero) + { + Console.WriteLine("Can't find LeagueClient window."); + emitExit(); + return; + } + + double fLeagueClientZoom = await GetLeagueClientZoom(LeagueClientUxArgs.Port, LeagueClientUxArgs.Token); + double fScreenDpi = GetDpiForWindow(pLeagueClientWindowHWnd) / 96.0; + int iScreenWidth = Screen.PrimaryScreen.Bounds.Width; + int iScreenHeight = Screen.PrimaryScreen.Bounds.Height; + + if (fLeagueClientZoom == -1) + { + Console.WriteLine("Can't get original zoom of LeagueClientUx"); + emitExit(); + return; + } + + int iTargetWindowWidth = (int)(1280 * fLeagueClientZoom); + int iTargetWindowHeight = (int)(720 * fLeagueClientZoom); + + Console.WriteLine("LeagueClientPort: " + LeagueClientUxArgs.Port); + Console.WriteLine("LeagueClientAuthtoken: " + LeagueClientUxArgs.Token); + Console.WriteLine("LeagueClientOriginZoom: " + fLeagueClientZoom); + Console.WriteLine("LeagueClientWindowHWnd: " + pLeagueClientWindowHWnd); + Console.WriteLine("LeagueClientWindowCefHWnd: " + pLeagueClientWindowCefHWnd); + Console.WriteLine("ScreenWidth: " + iScreenWidth * fScreenDpi); + Console.WriteLine("ScreenHeight: " + iScreenHeight * fScreenDpi); + Console.WriteLine("ScreenDpi: " + fScreenDpi); + Console.WriteLine("TargetWindowWidth: " + iTargetWindowWidth); + Console.WriteLine("TargetWindowHeight: " + iTargetWindowHeight); + + Console.WriteLine("-----------------------------"); + Console.WriteLine("客户端修复成功!"); + Console.WriteLine("-----------------------------"); + + SetWindowPos(pLeagueClientWindowHWnd, 0, (iScreenWidth - iTargetWindowWidth) / 2, (iScreenHeight - iTargetWindowHeight) / 2, iTargetWindowWidth, iTargetWindowHeight, 0x0040); + SetWindowPos(pLeagueClientWindowCefHWnd, 0, 0, 0, iTargetWindowWidth, iTargetWindowHeight, 0x0040); + } + + private static async Task MethodPlanB() + { + var LeagueClientUxCommandLine = GetCommandLineByProcessId(GetProcessId("LeagueClientUx")); + var LeagueClientUxArgs = CommandLineParser(LeagueClientUxCommandLine); + + if (!LeagueClientUxArgs.Available) + { + Console.WriteLine("Can't find LeagueClientUx process."); + emitExit(); + return; + } + + if (!await RestartClientUx(LeagueClientUxArgs.Port, LeagueClientUxArgs.Token)) + { + Console.WriteLine("Failed to reload LeagueClientUx."); + emitExit(); + return; + } + + Console.WriteLine("LeagueClientPort: " + LeagueClientUxArgs.Port); + Console.WriteLine("LeagueClientAuthtoken: " + LeagueClientUxArgs.Token); + + Console.WriteLine("-----------------------------"); + Console.WriteLine("客户端修复成功!"); + Console.WriteLine("-----------------------------"); + } + + static void Main(string[] args) + { + Console.WriteLine("-----------------------------"); + Console.WriteLine("Bilibili: Butter_Cookies"); + Console.WriteLine("Github: https://github.com/LeagueTavern/fix-lcu-window"); + Console.WriteLine("Code by LeagueTavern"); + Console.WriteLine("-----------------------------"); + Console.WriteLine("选择修复模式:"); + Console.WriteLine("[1]: 通过 窗口句柄 修复客户端"); + Console.WriteLine("[2]: 通过 LCUAPI 热重载客户端"); + Console.WriteLine("-----------------------------"); + Console.WriteLine("输入您想选择的修复模式 [1]:"); + + String strUserInput = Console.ReadLine(); + int iUserChoice; + + Console.WriteLine("-----------------------------"); + + + if (String.IsNullOrWhiteSpace(strUserInput) || !int.TryParse(strUserInput, out iUserChoice)) + { + iUserChoice = 1; + } + + switch (iUserChoice) + { + case 1: + MethodPlanA().Wait(); + break; + case 2: + MethodPlanB().Wait(); + break; + } + emitExit(); + } + } +} \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..88b4dbc --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +[assembly: AssemblyTitle("Fix-LCU-Window")] +[assembly: AssemblyDescription("Fix League of Legends client window.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("LeagueTavern")] +[assembly: AssemblyProduct("fix-lcu-window")] +[assembly: AssemblyCopyright("Copyright © LeagueTavern 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] +[assembly: Guid("3787836b-68c8-4026-bc2d-833e1752e7f6")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/app.manifest b/app.manifest new file mode 100644 index 0000000..75867c2 --- /dev/null +++ b/app.manifest @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fix-lcu-window-bin.csproj b/fix-lcu-window-bin.csproj new file mode 100644 index 0000000..22b429d --- /dev/null +++ b/fix-lcu-window-bin.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {3787836B-68C8-4026-BC2D-833E1752E7F6} + Exe + fix_lcu_window_bin + fix-lcu-window-bin + v4.8 + 512 + true + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + app.manifest + + + + + + + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.8 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + \ No newline at end of file diff --git a/fix-lcu-window-bin.sln b/fix-lcu-window-bin.sln new file mode 100644 index 0000000..03b1efc --- /dev/null +++ b/fix-lcu-window-bin.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fix-lcu-window-bin", "fix-lcu-window-bin.csproj", "{3787836B-68C8-4026-BC2D-833E1752E7F6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3787836B-68C8-4026-BC2D-833E1752E7F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3787836B-68C8-4026-BC2D-833E1752E7F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3787836B-68C8-4026-BC2D-833E1752E7F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3787836B-68C8-4026-BC2D-833E1752E7F6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D844A625-55BC-4BAD-96BD-39B9B33DA694} + EndGlobalSection +EndGlobal diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..4c12410 --- /dev/null +++ b/readme.md @@ -0,0 +1,2 @@ +# Fix-League-Client-Update-Window +本项目适用于修复《英雄联盟》客户端因不明原因导致的尺寸异常问题。 \ No newline at end of file