1- /*
1+ /*
22 * OpenSpeedy - Open Source Game Speed Controller
33 * Copyright (C) 2025 Game1024
44 *
1919 * <https://www.gnu.org/licenses/>.
2020 */
2121#include < windows.h>
22+ #include < winternl.h>
2223#include " Minhook.h"
2324#include " speedpatch.h"
2425#include < atomic>
@@ -37,18 +38,22 @@ static HANDLE hShare;
3738static bool * pEnable;
3839
3940typedef VOID (WINAPI* SLEEP) (DWORD);
40- typedef UINT_PTR (WINAPI* SETTIMER) (HWND,
41- UINT_PTR,
42- UINT,
43- TIMERPROC
44- );
41+ typedef DWORD (WINAPI* SLEEPEX) (DWORD, BOOL);
42+
43+ typedef UINT_PTR (WINAPI* SETTIMER) (
44+ HWND,
45+ UINT_PTR,
46+ UINT,
47+ TIMERPROC
48+ );
4549typedef DWORD (WINAPI* TIMEGETTIME) (VOID);
46- typedef MMRESULT (WINAPI* TIMESETEVENT) (UINT,
47- UINT,
48- LPTIMECALLBACK,
49- DWORD_PTR,
50- UINT
51- );
50+ typedef MMRESULT (WINAPI* TIMESETEVENT) (
51+ UINT,
52+ UINT,
53+ LPTIMECALLBACK,
54+ DWORD_PTR,
55+ UINT
56+ );
5257
5358typedef LONG (WINAPI* GETMESSAGETIME) (VOID);
5459typedef DWORD (WINAPI* GETTICKCOUNT) (VOID);
@@ -60,11 +65,23 @@ typedef BOOL (WINAPI* QUERYPERFORMANCEFREQUENCY) (LARGE_INTEGER*);
6065typedef VOID (WINAPI* GETSYSTEMTIMEASFILETIME) (LPFILETIME);
6166typedef VOID (WINAPI* GETSYSTEMTIMEPRECISEASFILETIME) (LPFILETIME);
6267
68+ typedef BOOL (WINAPI* SETWAITABLETIMEREX) (
69+ HANDLE,
70+ const LARGE_INTEGER*,
71+ LONG,
72+ PTIMERAPCROUTINE,
73+ LPVOID,
74+ PREASON_CONTEXT,
75+ ULONG);
76+
6377inline VOID shouldUpdateAll ();
6478
6579static SLEEP pfnKernelSleep = NULL ;
6680static SLEEP pfnDetourSleep = NULL ;
6781
82+ static SLEEPEX pfnKernelSleepEx = NULL ;
83+ static SLEEPEX pfnDetourSleepEx = NULL ;
84+
6885static SETTIMER pfnKernelSetTimer = NULL ;
6986static SETTIMER pfnDetourSetTimer = NULL ;
7087
@@ -95,6 +112,9 @@ static GETSYSTEMTIMEASFILETIME pfnDetourGetSystemTimeAsFileTime = NULL;
95112static GETSYSTEMTIMEPRECISEASFILETIME pfnKernelGetSystemTimePreciseAsFileTime = NULL ;
96113static GETSYSTEMTIMEPRECISEASFILETIME pfnDetourGetSystemTimePreciseAsFileTime = NULL ;
97114
115+ static SETWAITABLETIMEREX pfnKernelSetWaitableTimerEx = NULL ;
116+ static SETWAITABLETIMEREX pfnDetourSetWaitableTimerEx = NULL ;
117+
98118SPEEDPATCH_API void ChangeSpeed (double factor_)
99119{
100120 factor.store (factor_);
@@ -199,6 +219,12 @@ VOID WINAPI DetourSleep(DWORD dwMilliseconds)
199219 pfnKernelSleep (dwMilliseconds / SpeedFactor ());
200220}
201221
222+ DWORD WINAPI DetourSleepEx (DWORD dwMilliseconds, BOOL bAlertable)
223+ {
224+ std::shared_lock<std::shared_mutex> lock (mutex);
225+ return pfnKernelSleepEx (dwMilliseconds / SpeedFactor (), bAlertable);
226+ }
227+
202228UINT_PTR WINAPI DetourSetTimer (HWND hWnd,
203229 UINT_PTR nIDEvent,
204230 UINT uElapse,
@@ -484,6 +510,27 @@ DetourGetSystemTimePreciseAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
484510 (*lpSystemTimeAsFileTime) = { ulRtn.LowPart , ulRtn.HighPart };
485511}
486512
513+ BOOL WINAPI DetourSetWaitableTimerEx (
514+ HANDLE hTimer,
515+ const LARGE_INTEGER* lpDueTime,
516+ LONG lPeriod,
517+ PTIMERAPCROUTINE pfnCompletionRoutine,
518+ LPVOID lpArgToCompletionRoutine,
519+ PREASON_CONTEXT WakeContext,
520+ ULONG TolerableDelay
521+ )
522+ {
523+ LARGE_INTEGER dueTime = {0 };
524+ dueTime.QuadPart = lpDueTime->QuadPart / SpeedFactor ();
525+ return pfnKernelSetWaitableTimerEx (hTimer,
526+ &dueTime,
527+ lPeriod,
528+ pfnCompletionRoutine,
529+ lpArgToCompletionRoutine,
530+ WakeContext,
531+ TolerableDelay);
532+ }
533+
487534inline VOID shouldUpdateAll ()
488535{
489536 shouldUpdateTimeGetTime = true ;
@@ -498,10 +545,18 @@ inline VOID shouldUpdateAll()
498545template <typename S, typename T>
499546inline VOID MH_HOOK (S* pTarget, S* pDetour, T** ppOriginal)
500547{
501- MH_CreateHook (reinterpret_cast <LPVOID> (pTarget),
502- reinterpret_cast <LPVOID> (pDetour),
503- reinterpret_cast <LPVOID*> (ppOriginal));
504- MH_EnableHook (reinterpret_cast <LPVOID> (pTarget));
548+
549+ if (MH_CreateHook (reinterpret_cast <LPVOID> (pTarget),
550+ reinterpret_cast <LPVOID> (pDetour),
551+ reinterpret_cast <LPVOID*> (ppOriginal)) != MH_OK)
552+ {
553+ MessageBoxW (NULL , L" MH装载失败" , L" DLL" , MB_OK);
554+ }
555+
556+ if (MH_EnableHook (reinterpret_cast <LPVOID> (pTarget)) != MH_OK)
557+ {
558+ MessageBoxW (NULL , L" MH装载失败" , L" DLL" , MB_OK);
559+ }
505560}
506561
507562template <typename T>
@@ -533,9 +588,13 @@ BOOL APIENTRY DllMain(HMODULE hModule,
533588 LPVOID lpReserved)
534589{
535590 FILETIME now = { 0 };
591+ HMODULE hKernel32;
592+ SETWAITABLETIMEREX pSetWaitableTimerEx;
536593 switch (ul_reason_for_call)
537594 {
538595 case DLL_PROCESS_ATTACH:
596+ hKernel32 = GetModuleHandleW (L" kernel32.dll" );
597+
539598 if (MH_Initialize () != MH_OK)
540599 {
541600 MessageBoxW (NULL , L" MH装载失败" , L" DLL" , MB_OK);
@@ -587,8 +646,17 @@ BOOL APIENTRY DllMain(HMODULE hModule,
587646 baselineDetourGetSystemTimePreciseAsFileTime.store (now);
588647 prevcallDetourGetSystemTimePreciseAsFileTime.store (now);
589648
590- MH_HOOK (
591- &Sleep, &DetourSleep, reinterpret_cast <LPVOID*> (&pfnKernelSleep));
649+ MH_HOOK (&Sleep,
650+ &DetourSleep,
651+ reinterpret_cast <LPVOID*> (&pfnKernelSleep));
652+ MH_HOOK (&SleepEx,
653+ &DetourSleepEx,
654+ reinterpret_cast <LPVOID*>(&pfnKernelSleepEx));
655+
656+ pSetWaitableTimerEx = (SETWAITABLETIMEREX)GetProcAddress (hKernel32, " SetWaitableTimerEx" );
657+ MH_HOOK (pSetWaitableTimerEx,
658+ &DetourSetWaitableTimerEx,
659+ reinterpret_cast <LPVOID*>(&pfnKernelSetWaitableTimerEx));
592660 MH_HOOK (&SetTimer,
593661 &DetourSetTimer,
594662 reinterpret_cast <LPVOID*> (&pfnKernelSetTimer));
@@ -617,6 +685,8 @@ BOOL APIENTRY DllMain(HMODULE hModule,
617685 &DetourGetSystemTimePreciseAsFileTime,
618686 reinterpret_cast <LPVOID*> (
619687 &pfnKernelGetSystemTimePreciseAsFileTime));
688+
689+
620690 break ;
621691 case DLL_THREAD_ATTACH:
622692 break ;
@@ -633,6 +703,7 @@ BOOL APIENTRY DllMain(HMODULE hModule,
633703 MH_UNHOOK (pfnKernelSleep);
634704 MH_UNHOOK (pfnKernelSetTimer);
635705 MH_UNHOOK (pfnKernelTimeGetTime);
706+ MH_UNHOOK (pfnKernelTimeSetEvent);
636707 MH_UNHOOK (pfnKernelGetTickCount);
637708 MH_UNHOOK (pfnKernelGetTickCount64);
638709 MH_UNHOOK (pfnKernelQueryPerformanceCounter);
0 commit comments