00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "CATTimeWarp.h"
00014 #include "CATString.h"
00015
00016 #ifdef CAT_CONFIG_WIN32
00017
00018
00019 CATINTERCEPT_DLL_TABLE_ENTRY CATTimeWarp::kWinMMFuncs[] =
00020 {
00021 {"timeGetTime", CATTimeWarp::OnTimeGetTime, 7},
00022 { 0, 0, 0}
00023 };
00024
00025
00026 CATINTERCEPT_DLL_TABLE_ENTRY CATTimeWarp::kKernel32Funcs[] =
00027 {
00028 {"QueryPerformanceCounter", CATTimeWarp::OnQueryPerformanceCounter, 5},
00029 {"GetTickCount", CATTimeWarp::OnGetTickCount, 5},
00030 { 0, 0, 0}
00031 };
00032
00033 CATTimeWarp::CATTimeWarp()
00034 {
00035 fSpeed = 1.0f;
00036 fWinmmDLL = ::LoadLibrary(L"winmm.dll");
00037 fKernelDLL = ::LoadLibrary(L"kernel32.dll");
00038
00039 fLastTickCount = 0;
00040 fLastTimeGetTime = 0;
00041 fLastPerfCounter.QuadPart = 0;
00042
00043 fLastRealTickCount = 0;
00044 fLastRealTimeGetTime = 0;
00045 fLastRealPerfCounter.QuadPart = 0;
00046 }
00047
00048 CATTimeWarp::~CATTimeWarp()
00049 {
00050
00051 RestoreAll();
00052
00053 if (fWinmmDLL)
00054 FreeLibrary(fWinmmDLL);
00055 if (fKernelDLL)
00056 FreeLibrary(fKernelDLL);
00057 }
00058
00059 CATResult CATTimeWarp::HookFunctions()
00060 {
00061 CATResult result = CAT_SUCCESS;
00062
00063 fLock.Wait();
00064
00065
00066 fLastTickCount = GetTickCount();
00067 fLastTimeGetTime = timeGetTime();
00068 QueryPerformanceCounter(&fLastPerfCounter);
00069
00070 fLastRealTickCount = fLastTickCount;
00071 fLastRealTimeGetTime = fLastTimeGetTime;
00072 fLastRealPerfCounter = fLastPerfCounter;
00073
00074
00075 if (this->fWinmmDLL)
00076 {
00077 ::OutputDebugString(L"Hooking WinMM time functions...\n");
00078 result = InterceptDLL(fWinmmDLL,&kWinMMFuncs[0],0);
00079 if (CATFAILED(result))
00080 ::OutputDebugString(L"Failed hooking WinMM.\n");
00081 }
00082 else
00083 ::OutputDebugString(L"Failed to load WinMM.\n");
00084
00085 if (this->fKernelDLL)
00086 {
00087 ::OutputDebugString(L"Hooking Kernel32 performance counter...\n");
00088 result = InterceptDLL(fKernelDLL,&kKernel32Funcs[0],0);
00089 if (CATFAILED(result))
00090 ::OutputDebugString(L"Failed hooking Kernel32.\n");
00091 }
00092
00093 SetSpeed(1.0f);
00094 fLock.Release();
00095
00096 return result;
00097 }
00098
00099
00100 void CATTimeWarp::FixupQPC(CATHOOK* hookInst, LARGE_INTEGER* lpCount)
00101 {
00102 CATTimeWarp* timeWarp = ((CATTimeWarp*)hookInst->InterceptObj);
00103 timeWarp->AdjustSaveTime(lpCount, 0,0);
00104 }
00105
00106 void CATTimeWarp::FixupTime(CATHOOK* hookInst, DWORD* timePtr)
00107 {
00108 CATTimeWarp* timeWarp = ((CATTimeWarp*)hookInst->InterceptObj);
00109 timeWarp->AdjustSaveTime(0,0,timePtr);
00110 }
00111
00112 void CATTimeWarp::FixupTick(CATHOOK* hookInst, DWORD* tickPtr)
00113 {
00114 CATTimeWarp* timeWarp = ((CATTimeWarp*)hookInst->InterceptObj);
00115 timeWarp->AdjustSaveTime(0,tickPtr,0);
00116 }
00117
00118 CATHOOKFUNC void CATTimeWarp::OnTimeGetTime( CATHOOK* hookInst)
00119 {
00120 CATHOOK_PROLOGUE(0);
00121
00122 CATHOOK_CALLORIGINAL_WINAPI(hookInst, 0);
00123
00124
00125 __asm
00126 {
00127 mov eax,ebp
00128 sub eax,4
00129 push eax
00130 push hookInst
00131 call FixupTime
00132 add esp,8
00133 }
00134
00135 CATHOOK_EPILOGUE_WINAPI(0);
00136 }
00137
00138 CATHOOKFUNC void CATTimeWarp::OnQueryPerformanceCounter( CATHOOK* hookInst,
00139 LARGE_INTEGER* lpCount)
00140 {
00141 CATHOOK_PROLOGUE(1);
00142 CATHOOK_CALLORIGINAL_WINAPI(hookInst, 1);
00143
00144
00145 FixupQPC(hookInst,lpCount);
00146
00147 CATHOOK_EPILOGUE_WINAPI(1);
00148 }
00149
00150
00151 CATHOOKFUNC void CATTimeWarp::OnGetTickCount( CATHOOK* hookInst)
00152 {
00153 CATHOOK_PROLOGUE(0);
00154
00155 CATHOOK_CALLORIGINAL_WINAPI(hookInst, 0);
00156
00157
00158 _asm
00159 {
00160 mov eax,ebp
00161 sub eax,4
00162 push eax
00163 push hookInst
00164 call FixupTick
00165 add esp,8
00166 }
00167 CATHOOK_EPILOGUE_WINAPI(0);
00168 }
00169
00170 CATResult CATTimeWarp::SetSpeed(CATFloat32 speed)
00171 {
00172 fLock.Wait();
00173
00174
00175
00176
00177
00178
00179 fSpeed = speed;
00180
00181
00182 fLock.Release();
00183
00184 return CAT_SUCCESS;
00185 }
00186
00187 CATFloat32 CATTimeWarp::GetSpeed()
00188 {
00189 fLock.Wait();
00190 CATFloat32 speed = fSpeed;
00191 fLock.Release();
00192 return speed;
00193 }
00194
00195 void CATTimeWarp::AdjustSaveTime(LARGE_INTEGER* lastPerf, DWORD* lastTick, DWORD* lastTime)
00196 {
00197 fLock.Wait();
00198 {
00199
00200
00201
00202 if (lastPerf)
00203 {
00204 LARGE_INTEGER nextPerf;
00205 nextPerf.QuadPart = (LONGLONG)((lastPerf->QuadPart - fLastRealPerfCounter.QuadPart)*fSpeed
00206 + fLastPerfCounter.QuadPart);
00207
00208
00209 fLastRealPerfCounter.QuadPart = lastPerf->QuadPart;
00210 fLastPerfCounter.QuadPart = nextPerf.QuadPart;
00211 lastPerf->QuadPart = nextPerf.QuadPart;
00212 }
00213
00214 if (lastTick)
00215 {
00216 DWORD nextTick = (DWORD)(((*lastTick) - fLastRealTickCount)*fSpeed + fLastTickCount);
00217
00218
00219 fLastRealTickCount = (*lastTick);
00220 fLastTickCount = nextTick;
00221 *lastTick = nextTick;
00222 }
00223
00224 if (lastTime)
00225 {
00226 DWORD nextTime = (DWORD)(((*lastTime) - fLastRealTimeGetTime)*fSpeed + fLastTimeGetTime);
00227
00228
00229 fLastRealTimeGetTime = (*lastTime);
00230 fLastTimeGetTime = nextTime;
00231 *lastTime = nextTime;
00232 }
00233 }
00234
00235 fLock.Release();
00236 }
00237
00238 #endif // CAT_CONFIG_WIN32