diff --git a/dll/appcompat/shims/genral/CMakeLists.txt b/dll/appcompat/shims/genral/CMakeLists.txt index bc2c1d083f4..d2732a1905b 100644 --- a/dll/appcompat/shims/genral/CMakeLists.txt +++ b/dll/appcompat/shims/genral/CMakeLists.txt @@ -9,6 +9,7 @@ list(APPEND SOURCE main.c shimtest.c themes.c + timeapi.c genral.spec) add_library(acgenral MODULE diff --git a/dll/appcompat/shims/genral/timeapi.c b/dll/appcompat/shims/genral/timeapi.c index 80eb3fdd02b..35c11fb48c6 100644 --- a/dll/appcompat/shims/genral/timeapi.c +++ b/dll/appcompat/shims/genral/timeapi.c @@ -12,27 +12,63 @@ #include #include #include -#include +#include - -#define SHIM_NS TimeAPI Resolution +#define SHIM_NS DefaultTimerResolution1ms #include -#define SHIM_NUM_HOOKS 0 +typedef DWORD (WINAPI* TIMEGETTIMEPROC)(void); +typedef MMRESULT(WINAPI* TIMEBEGINPERIODPROC)(_In_ UINT); +typedef MMRESULT(WINAPI* TIMEENDPERIODPROC)(_In_ UINT); + +/* Only adjust timer resolution if timeGetTime() is called before timeBeginPeriod() */ +static LONG isResolutionSet; + #define SHIM_NOTIFY_FN SHIM_OBJ_NAME(Notify) BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason, PVOID ptr) { - if (fdwReason == SHIM_REASON_INIT) + HMODULE hWinMM; + TIMEENDPERIODPROC ftimeEndPeriod; + + if (fdwReason == SHIM_REASON_DEINIT) { - timeBeginPeriod(1); + hWinMM = GetModuleHandleW(L"WINMM"); + if (hWinMM != NULL) + { + ftimeEndPeriod = (TIMEENDPERIODPROC)GetProcAddress(hWinMM, "timeEndPeriod"); + if (ftimeEndPeriod != NULL && InterlockedAnd(&isResolutionSet, TRUE)) + ftimeEndPeriod(1); + } } - else if (fdwReason == SHIM_REASON_DEINIT) - { - timeEndPeriod(1); - } return TRUE; } +DWORD WINAPI SHIM_OBJ_NAME(APIHook_timeGetTime)(void) +{ + if (InterlockedExchange(&isResolutionSet, TRUE) == FALSE) + { + HMODULE hWinMM = GetModuleHandleW(L"WINMM"); + TIMEBEGINPERIODPROC ftimeBeginPeriod = (TIMEBEGINPERIODPROC)GetProcAddress(hWinMM, "timeBeginPeriod"); + + /* Windows 95/98/ME timeGetTime has a default resolution of 1 ms and on */ + /* Windows NT/2000/XP this same function has a resolution of 10 ms. */ + ftimeBeginPeriod(1); + } + + return CALL_SHIM(0, TIMEGETTIMEPROC)(); +} + +MMRESULT WINAPI SHIM_OBJ_NAME(APIHook_timeBeginPeriod)(_In_ UINT uPeriod) +{ + InterlockedExchange(&isResolutionSet, TRUE); + return CALL_SHIM(0, TIMEBEGINPERIODPROC)(uPeriod); +} + +#define SHIM_NUM_HOOKS 1 +#define SHIM_SETUP_HOOKS \ + SHIM_HOOK(0, "WINMM.DLL", "timeGetTime", SHIM_OBJ_NAME(APIHook_timeGetTime)) \ + SHIM_HOOK(1, "WINMM.DLL", "timeBeginPeriod", SHIM_OBJ_NAME(APIHook_timeBeginPeriod)) + #include diff --git a/media/sdb/sysmain.xml b/media/sdb/sysmain.xml index c105abadab2..0e78e722e46 100644 --- a/media/sdb/sysmain.xml +++ b/media/sdb/sysmain.xml @@ -270,6 +270,10 @@ 8 + + acgenral.dll + Windows 95/98/ME timeGetTime has a default resolution of 1 ms and on Windows NT/2000/XP this same function has a resolution of 10 ms + @@ -283,12 +287,14 @@ + + @@ -442,6 +448,9 @@ + + +