diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
index 4dde9d4f..acc8021a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
@@ -37,7 +37,7 @@ internal static class Must
{
if (!condition)
{
- throw new ArgumentOutOfRangeException(message, parameterName);
+ throw new ArgumentOutOfRangeException(parameterName, message);
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs
index d60ecd8f..6172a5cf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs
@@ -13,6 +13,7 @@ namespace Snap.Hutao.Service.Game.Unlocker;
///
/// 游戏帧率解锁器
+/// Credit to https://github.com/34736384/genshin-fps-unlock
///
[HighQuality]
internal sealed class GameFpsUnlocker : IGameFpsUnlocker
@@ -58,10 +59,10 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker
await LoopAdjustFpsAsync(adjustFpsDelay).ConfigureAwait(false);
}
- private static unsafe bool UnsafeReadModuleMemory(Process process, MODULEENTRY32 entry, out Span image)
+ private static unsafe bool UnsafeReadModuleMemory(Process process, MODULEENTRY32 entry, out Span memory)
{
- image = new byte[entry.modBaseSize];
- fixed (byte* lpBuffer = image)
+ memory = new byte[entry.modBaseSize];
+ fixed (byte* lpBuffer = memory)
{
return ReadProcessMemory(process.SafeHandle, entry.modBaseAddr, lpBuffer, entry.modBaseSize, null);
}
@@ -81,22 +82,15 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker
{
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
- MODULEENTRY32 entry = StructMarshal.MODULEENTRY32();
- bool found = false;
-
- bool loop = Module32First(snapshot, &entry);
- while (loop)
+ foreach (MODULEENTRY32 entry in StructMarshal.EnumerateModuleEntry32(snapshot))
{
- if (entry.th32ProcessID == processId && entry.szModule.AsNullTerminatedReadOnlySpan() == moduleName)
+ if (entry.th32ProcessID == processId && entry.szModule.AsNullTerminatedReadOnlySpan().SequenceEqual(moduleName))
{
- found = true;
- break;
+ return entry;
}
-
- loop = Module32Next(snapshot, &entry);
}
- return found ? entry : default;
+ return default;
}
finally
{
@@ -148,22 +142,22 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker
private unsafe void UnsafeTryReadModuleMemoryFindFpsAddress(MODULEENTRY32 unityPlayer)
{
- bool readOk = UnsafeReadModuleMemory(gameProcess, unityPlayer, out Span image);
+ bool readOk = UnsafeReadModuleMemory(gameProcess, unityPlayer, out Span memory);
Verify.Operation(readOk, "读取内存失败");
// Find FPS offset
// 7F 0F jg 0x11
// 8B 05 ? ? ? ? mov eax, dword ptr[rip+?]
- int adr = image.IndexOf(new byte[] { 0x7F, 0x0F, 0x8B, 0x05 });
+ int adr = memory.IndexOf(new byte[] { 0x7F, 0x0F, 0x8B, 0x05 });
- Must.Range(adr >= 0, "未匹配到FPS字节");
+ Must.Range(adr >= 0, $"未匹配到FPS字节");
- fixed (byte* pSpan = image)
+ fixed (byte* pSpan = memory)
{
int rip = adr + 2;
int rel = *(int*)(pSpan + rip + 2); // Unsafe.ReadUnaligned(ref image[rip + 2]);
int ofs = rip + rel + 6;
- fpsAddress = (nuint)((long)unityPlayer.modBaseAddr + ofs);
+ fpsAddress = (nuint)(unityPlayer.modBaseAddr + ofs);
}
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/LaunchGameResourceExpander.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/LaunchGameResourceExpander.xaml
index e9b55b27..4947b339 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Control/LaunchGameResourceExpander.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/LaunchGameResourceExpander.xaml
@@ -9,7 +9,7 @@
IsExpanded="True"
mc:Ignorable="d">
-
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml
index 99575c1f..8d2cc224 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml
@@ -40,7 +40,7 @@
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml
index b4932573..fb5ce6fc 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml
@@ -52,7 +52,7 @@
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
index b96c7420..3d2416fe 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml
@@ -24,7 +24,7 @@
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
index c7da4086..cefdbc66 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
@@ -27,7 +27,7 @@
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
index 920257f3..4b6f4cfa 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
@@ -11,6 +11,7 @@ namespace Snap.Hutao.Web.Hoyolab;
internal sealed partial class Cookie
{
public const string LOGIN_TICKET = "login_ticket";
+ public const string LOGIN_UID = "login_uid";
public const string ACCOUNT_ID = "account_id";
public const string COOKIE_TOKEN = "cookie_token";
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
index ba3aaa1e..18774c57 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Auth/AuthClient.cs
@@ -62,8 +62,8 @@ internal sealed class AuthClient
/// 包含token的字典
public async Task>> GetMultiTokenByLoginTicketAsync(Cookie cookie, CancellationToken token)
{
- string loginTicket = cookie["login_ticket"];
- string loginUid = cookie["login_uid"];
+ string loginTicket = cookie[Cookie.LOGIN_TICKET];
+ string loginUid = cookie[Cookie.LOGIN_UID];
Response>? resp = await httpClient
.TryCatchGetFromJsonAsync>>(ApiEndpoints.AuthMultiToken(loginTicket, loginUid), options, logger, token)
diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs b/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
index fa1c2c1f..b6668902 100644
--- a/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
@@ -4,9 +4,12 @@
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Windows.Graphics;
+using Windows.Win32.Foundation;
using Windows.Win32.System.Diagnostics.ToolHelp;
using Windows.Win32.UI.WindowsAndMessaging;
+using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Win32;
@@ -22,7 +25,7 @@ internal static class StructMarshal
/// 新的实例
public static unsafe MODULEENTRY32 MODULEENTRY32()
{
- return new() { dwSize = (uint)sizeof(MODULEENTRY32) };
+ return new() { dwSize = unchecked((uint)sizeof(MODULEENTRY32)) };
}
///
@@ -31,7 +34,7 @@ internal static class StructMarshal
/// 新的实例
public static unsafe WINDOWPLACEMENT WINDOWPLACEMENT()
{
- return new() { length = (uint)sizeof(WINDOWPLACEMENT) };
+ return new() { length = unchecked((uint)sizeof(WINDOWPLACEMENT)) };
}
///
@@ -78,6 +81,27 @@ internal static class StructMarshal
return new(point.X, point.Y, size.Width, size.Height);
}
+ ///
+ /// 枚举快照的模块
+ ///
+ /// 快照
+ /// 模块枚举
+ public static IEnumerable EnumerateModuleEntry32(HANDLE snapshot)
+ {
+ MODULEENTRY32 entry = MODULEENTRY32();
+
+ if (!UnsafeModule32First(snapshot, ref entry))
+ {
+ yield break;
+ }
+
+ do
+ {
+ yield return entry;
+ }
+ while (UnsafeModule32Next(snapshot, ref entry));
+ }
+
///
/// 判断结构实例是否为默认结构
///
@@ -87,4 +111,20 @@ internal static class StructMarshal
{
return moduleEntry32.dwSize == 0;
}
+
+ private static unsafe BOOL UnsafeModule32First(HANDLE snapshot, ref MODULEENTRY32 lpme)
+ {
+ fixed (MODULEENTRY32* lpmeLocal = &lpme)
+ {
+ return Module32First(snapshot, lpmeLocal);
+ }
+ }
+
+ private static unsafe BOOL UnsafeModule32Next(HANDLE snapshot, ref MODULEENTRY32 lpme)
+ {
+ fixed (MODULEENTRY32* lpmeLocal = &lpme)
+ {
+ return Module32Next(snapshot, lpmeLocal);
+ }
+ }
}
\ No newline at end of file