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

CATDirectSoundIntercept.cpp

Go to the documentation of this file.
00001 /// \file  CATDirectSoundIntercept.cpp
00002 /// \brief DirectSound 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-14 02:13:38 -0600 (Mon, 14 Jan 2008) $
00010 // $Revision:   $
00011 // $NoKeywords: $
00012 
00013 #include "CATDirectSoundIntercept.h"
00014 #ifdef CAT_CONFIG_WIN32
00015 
00016 #define DIRECTSOUND_VERSION 0x0900  /* Version 9.0 */
00017 #define INITGUID
00018 #include <dsound.h>
00019 #undef INITGUID
00020 #include <dmusicc.h>
00021 #include <dmusici.h>
00022 #include <cguid.h>
00023 
00024 /// This table contains all of the functions we wish to intercept
00025 /// from IDirectSoundBuffer and the targets for those functions.
00026 CATINTERCEPT_COM_TABLE_ENTRY kBufferInterceptTable[] =
00027 {
00028     // VTableIndex  HookFunction                                 StubLength
00029     {  12,          CATDirectSoundIntercept::OnPlayBuffer,       5},  
00030 //    {  11,          CATDirectSoundIntercept::OnLockBuffer,       5},
00031 //    {  19,          CATDirectSoundIntercept::OnUnlockBuffer,     5},
00032 
00033     // End marker
00034     {(CATUInt32)-1,0,-1}
00035 };
00036 
00037 /// This table contains all of the functions we wish to intercept
00038 /// from IDirectSoundBuffer and the targets for those functions.
00039 CATINTERCEPT_COM_TABLE_ENTRY kEAXBufferInterceptTable[] =
00040 {
00041     // VTableIndex  HookFunction                                 StubLength
00042     {  12,          CATDirectSoundIntercept::OnPlayBufferEAX,       5},  
00043 //    {  11,          CATDirectSoundIntercept::OnLockBufferEAX,       5},
00044 //    {  19,          CATDirectSoundIntercept::OnUnlockBufferEAX,     5},
00045 
00046     // End marker
00047     {(CATUInt32)-1,0,-1}
00048 };
00049 
00050 CATINTERCEPT_COM_TABLE_ENTRY kPerformanceInterceptTable[] =
00051 {
00052     // VTableIndex  HookFunction                                 StubLength
00053     {  4,          CATDirectSoundIntercept::OnPlaySegment,       5},  
00054     {  46,         CATDirectSoundIntercept::OnPlaySegmentEx,     5},
00055     // End marker
00056     {(CATUInt32)-1,0,-1}
00057 };
00058 
00059 CATDirectSoundIntercept::CATDirectSoundIntercept()
00060 {
00061     CoInitializeEx(0,0);
00062     fDSoundDLL   = ::LoadLibrary(L"dsound.dll");
00063     fDSound3DDLL = ::LoadLibrary(L"dsound3d.dll");
00064     fDSound3DEaxDLL = ::LoadLibrary(L"eax.dll");
00065 }
00066 
00067 CATDirectSoundIntercept::~CATDirectSoundIntercept()
00068 {
00069     // Unhook before base class, since we're possibly unloading the DLLs
00070     RestoreAll();
00071 
00072     // Now unload the DLLs and free our count on COM
00073     if (fDSound3DDLL)
00074         FreeLibrary(fDSound3DDLL);
00075 
00076     if (fDSoundDLL)
00077         FreeLibrary(fDSoundDLL);
00078 
00079     if (fDSound3DEaxDLL)
00080         FreeLibrary(fDSound3DEaxDLL);
00081 
00082     CoUninitialize();
00083 }
00084 
00085 CATResult CATDirectSoundIntercept::HookFunctions()
00086 {
00087     // Here we snag all the pointers to the DirectSound objects we're interested in
00088     // for the default audio device.  The objects themselves may be released afterwards -
00089     // we just need the addresses of their vtables to play with.
00090     DSoundCreate8Func           tmpDSoundCreate8   = 0;
00091     IDirectSound8*              tmpDS8             = 0;
00092 
00093     if (!fDSoundDLL)
00094         return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);
00095 
00096     tmpDSoundCreate8 = (DSoundCreate8Func)::GetProcAddress(fDSoundDLL,"DirectSoundCreate8");
00097     if (!tmpDSoundCreate8)
00098         return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);
00099 
00100     tmpDSoundCreate8(0,(void**)&tmpDS8, 0);
00101     if (tmpDS8 == 0)
00102         return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);    
00103 
00104     tmpDS8->SetCooperativeLevel(::GetDesktopWindow(),DSSCL_PRIORITY);
00105 
00106     ::OutputDebugString(L"Hooking DirectSound8...\n");
00107     CATResult result = HookDSound(tmpDS8,&kBufferInterceptTable[0]);
00108     if (CATFAILED(result))
00109         ::OutputDebugString(L"Failed hooking DirectSound8.\n");
00110 
00111     if (tmpDS8)
00112         tmpDS8->Release();
00113 
00114     if (fDSound3DEaxDLL)
00115     {
00116         // Now do the same for EAX.
00117         tmpDSoundCreate8 = (DSoundCreate8Func)::GetProcAddress(fDSound3DEaxDLL,"EAXDirectSoundCreate8");
00118         if (tmpDSoundCreate8)
00119         {
00120             tmpDSoundCreate8(0,(void**)&tmpDS8, 0);
00121             if (tmpDS8)
00122             {
00123                 tmpDS8->SetCooperativeLevel(::GetDesktopWindow(),DSSCL_PRIORITY);
00124                 ::OutputDebugString(L"Hooking EAX DirectSound...\n");
00125                 result = HookDSound(tmpDS8,&kEAXBufferInterceptTable[0]);
00126                 if (CATFAILED(result))
00127                     ::OutputDebugString(L"Failed hooking EAX DirectSound.\n");
00128                 tmpDS8->Release();
00129             }
00130         }
00131     }
00132 
00133 
00134     // Next.... hit the DirectMusic stuff, not sure how commonly used it is, but it appears to be used in some 
00135     // cases.
00136 
00137     IDirectMusicPerformance8*   tmpPerformance = 0;
00138     
00139     CoCreateInstance(CLSID_DirectMusicPerformance, 
00140                      NULL, 
00141                      CLSCTX_INPROC,
00142                      IID_IDirectMusicPerformance8, 
00143                      (void**)&tmpPerformance );
00144 
00145     if (tmpPerformance)
00146     {
00147         result = InterceptCOMObject(tmpPerformance,&kPerformanceInterceptTable[0],0);
00148         
00149         tmpPerformance->Release();
00150     }
00151     
00152     return result;
00153 }
00154 
00155 CATResult CATDirectSoundIntercept::HookDSound(IDirectSound8* tmpDS8,CATINTERCEPT_COM_TABLE_ENTRY* interceptTable)
00156 {    
00157     IDirectSoundBuffer*         tmpDSPrimaryBuffer = 0;
00158     IDirectSoundBuffer*         tmpDSBuffer        = 0;
00159     IDirectSoundBuffer8*        tmpDSBuffer8       = 0;
00160     IDirectSound3DBuffer*       tmpDSBuffer3D      = 0;
00161     IDirectSound3DListener*     tmpDSListener3D    = 0;
00162     // Get the primary buffer
00163     DSBUFFERDESC bufferDesc; 
00164     memset(&bufferDesc, 0, sizeof(DSBUFFERDESC)); 
00165     bufferDesc.dwSize        = sizeof(DSBUFFERDESC); 
00166     bufferDesc.dwFlags       = DSBCAPS_CTRL3D |  DSBCAPS_PRIMARYBUFFER;
00167     
00168     HRESULT hr = S_OK;
00169     // Create primary DirectSound buffer
00170     if (SUCCEEDED(hr = tmpDS8->CreateSoundBuffer(&bufferDesc, &tmpDSPrimaryBuffer, NULL)))
00171     { 
00172         // Set the wave format for primary
00173         WAVEFORMATEX waveFormat; 
00174         memset(&waveFormat, 0, sizeof(WAVEFORMATEX)); 
00175         waveFormat.wFormatTag       = WAVE_FORMAT_PCM; 
00176         waveFormat.nChannels        = 2; 
00177         waveFormat.nSamplesPerSec   = 22050; 
00178         waveFormat.nBlockAlign      = 4; 
00179         waveFormat.wBitsPerSample   = 16; 
00180         waveFormat.nAvgBytesPerSec  = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 
00181         hr = tmpDSPrimaryBuffer->SetFormat(&waveFormat);
00182 
00183         // Get the listener object from the primary buffer
00184         hr = tmpDSPrimaryBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID*)&tmpDSListener3D);           
00185 
00186         // Now create a buffer... single channel on this one so it can be 3D.
00187         waveFormat.nChannels   = 1;
00188         waveFormat.nBlockAlign = 2;
00189         waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 
00190 
00191         bufferDesc.dwFlags          = DSBCAPS_CTRL3D;
00192         bufferDesc.lpwfxFormat      = &waveFormat;
00193         bufferDesc.guid3DAlgorithm  = DS3DALG_NO_VIRTUALIZATION;
00194         bufferDesc.dwBufferBytes    = waveFormat.nAvgBytesPerSec;
00195         hr = tmpDS8->CreateSoundBuffer(&bufferDesc,&tmpDSBuffer,0);
00196         if (tmpDSBuffer)
00197         {
00198             // Get a pointer to the DirectSound8 interface if available
00199             hr = tmpDSBuffer->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&tmpDSBuffer8);
00200 
00201             // Get the 3D buffer interface
00202             hr = tmpDSBuffer->QueryInterface(IID_IDirectSound3DBuffer,   (LPVOID*)&tmpDSBuffer3D);
00203         }
00204     } 
00205 
00206     // Got all the interfaces now... find the functions we're interested in...
00207     CATResult result;
00208     result = InterceptCOMObject(tmpDSBuffer,interceptTable,0);
00209 
00210 
00211     // Clean up
00212     if (tmpDSBuffer)
00213         tmpDSBuffer->Release();
00214 
00215     if (tmpDSBuffer3D)
00216         tmpDSBuffer3D->Release();
00217 
00218     if (tmpDSListener3D)
00219         tmpDSListener3D->Release();
00220     
00221     if (tmpDSBuffer8)
00222         tmpDSBuffer8->Release();
00223 
00224     if (tmpDSPrimaryBuffer)
00225         tmpDSPrimaryBuffer->Release();
00226 
00227     return result;
00228 }
00229 
00230 
00231 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnPlayBuffer(CATHOOK*      hookInst,
00232                                                           IDirectSound* dsound,
00233                                                           DWORD         dwReserved1,
00234                                                           DWORD         dwPriority,
00235                                                           DWORD         dwFlags)
00236 {
00237     CATHOOK_PROLOGUE(4);
00238     ::OutputDebugString(L"ds:Play\n");
00239     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 4);
00240     CATHOOK_EPILOGUE_WINAPI(4);
00241 }
00242 
00243 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnPlayBufferEAX(CATHOOK*      hookInst,
00244                                                           IDirectSound* dsound,
00245                                                           DWORD         dwReserved1,
00246                                                           DWORD         dwPriority,
00247                                                           DWORD         dwFlags)
00248 {
00249     CATHOOK_PROLOGUE(4);
00250     ::OutputDebugString(L"eax:Play\n");
00251     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 4);
00252     CATHOOK_EPILOGUE_WINAPI(4);
00253 }
00254 
00255 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnLockBuffer(CATHOOK*        hookInst,
00256                                                           IDirectSound*   dsound,
00257                                                           DWORD           dwOffset,
00258                                                           DWORD           dwBytes,
00259                                                           LPVOID*         ppvAudioPtr1,
00260                                                           LPDWORD         pdwAudioBytes1,
00261                                                           LPVOID*         ppvAudioPtr2,
00262                                                           LPDWORD         pdwAudioBytes2,
00263                                                           DWORD           dwFlags)
00264 {
00265     CATHOOK_PROLOGUE(8);
00266     //::OutputDebugString(L"ds:Lock\n");
00267     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 8);
00268 
00269 
00270     CATHOOK_EPILOGUE_WINAPI(8);
00271 }
00272         
00273 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnUnlockBuffer(  CATHOOK*        hookInst,
00274                                                               IDirectSound*   dsound,
00275                                                               LPVOID          pvAudioPtr1,
00276                                                               DWORD           dwAudioBytes1,
00277                                                               LPVOID          pvAudioPtr2,
00278                                                               DWORD           dwAudioBytes2)
00279 {
00280     CATHOOK_PROLOGUE(5);
00281     //::OutputDebugString(L"ds:Unlock\n");
00282     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 5);
00283 
00284 
00285     CATHOOK_EPILOGUE_WINAPI(5);
00286 }
00287 
00288 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnPlaySegment(  CATHOOK*                    hookInst, 
00289                                                              IDirectMusicPerformance*    performance,
00290                                                              IDirectMusicSegment*        pSegment,
00291                                                              DWORD                       dwFlags,
00292                                                              DWORD                       startTimeLow,
00293                                                              DWORD                       startTimeHigh,                                         
00294                                                              IDirectMusicSegmentState**  ppSegmentState)
00295 {
00296     CATHOOK_PROLOGUE(6);
00297     ::OutputDebugString(L"ds:PlaySegment\n");
00298     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 6);
00299 
00300 
00301     CATHOOK_EPILOGUE_WINAPI(6);
00302 }
00303 
00304 CATHOOKFUNC HRESULT CATDirectSoundIntercept::OnPlaySegmentEx( CATHOOK*                    hookInst, 
00305                                                               IDirectMusicPerformance*    performance,
00306                                                               IUnknown*                   pSource,
00307                                                               WCHAR*                      pwzSegmentName,
00308                                                               IUnknown*                   pTransition,
00309                                                               DWORD                       dwFlags,
00310                                                               DWORD                       startTimeLow,
00311                                                               DWORD                       startTimeHigh,                                         
00312                                                               IDirectMusicSegmentState**  ppSegmentState,
00313                                                               IUnknown*                   pFrom, 
00314                                                               IUnknown*                   pAudioPath)
00315 {
00316     CATHOOK_PROLOGUE(10);
00317     ::OutputDebugString(L"ds:PlaySegmentEx\n");
00318     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 10);
00319 
00320 
00321     CATHOOK_EPILOGUE_WINAPI(10);
00322 }
00323 
00324 #endif // CAT_CONFIG_WIN32

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