Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CAT/CATTimeWarp.cpp Source File

CATTimeWarp.cpp

Go to the documentation of this file.
00001 /// \file  CATTimeWarp.cpp
00002 /// \brief Time function interception
00003 /// \ingroup CAT
00004 ///
00005 /// Copyright (c) 2007-2008 by Michael Ellison.
00006 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00007 ///
00008 // $Author: mikeellison $
00009 // $Date: 2008-01-27 21:01:45 -0600 (Sun, 27 Jan 2008) $
00010 // $Revision:   $
00011 // $NoKeywords: $
00012 
00013 #include "CATTimeWarp.h"
00014 #include "CATString.h"
00015 
00016 #ifdef CAT_CONFIG_WIN32
00017 
00018 // WinMM intercepts for time warp
00019 CATINTERCEPT_DLL_TABLE_ENTRY CATTimeWarp::kWinMMFuncs[] =
00020 {
00021     {"timeGetTime",  CATTimeWarp::OnTimeGetTime,  7},
00022     { 0, 0, 0}
00023 };
00024 
00025 // Kernel32 intercepts for time warp
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     // Unhook before base class, since we're possibly unloading the DLLs
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     // Get starting values
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     // Adjust time based on speed.
00125     __asm
00126     {
00127         mov  eax,ebp    // Ptr to return value (push as time argument for fixup)
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     // No assembler needed since it's a passed argument ;)
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     // Adjust time based on speed
00158     _asm
00159     {
00160         mov  eax,ebp    // Ptr to return value (push as time argument for fixup)
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 //    LARGE_INTEGER perf;
00175 //    QueryPerformanceCounter(&perf);
00176 //    timeGetTime();
00177 //    GetTickCount();
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         // Scale interval between last call and now and add to result of last call for each
00200         // requested (Non-NULL) timer.
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

Generated on Mon Feb 11 04:09:49 2008 for Game Accessibility Suite by doxygen 1.5.4