topical media & game development

talk show tell print

hush-src-multi-GamePlayer-dxutil.cpp / cpp



  //-----------------------------------------------------------------------------
  // File: DXUtil.cpp
  //
  // Desc: Shortcut macros and functions for using DirectX objects
  //
  // Copyright (c) Microsoft Corporation. All rights reserved
  //-----------------------------------------------------------------------------
  
  ifndef STRICT
  define STRICT
  endif // !STRICT
  include <stdafx.h>
  include <windows.h>
  include <mmsystem.h>
  include <tchar.h>
  include <stdio.h> 
  include <stdarg.h>
  include <DXUtil.h>
  
  ifdef UNICODE
      typedef HINSTANCE (WINAPI* LPShellExecute)(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
  else
      typedef HINSTANCE (WINAPI* LPShellExecute)(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd);
  endif
  
  ifndef UNDER_CE
  //-----------------------------------------------------------------------------
  // Name: DXUtil_GetDXSDKMediaPathCch()
  // Desc: Returns the DirectX SDK media path
  //       cchDest is the size in TCHARs of strDest.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds.
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_GetDXSDKMediaPathCch( TCHAR* strDest, int cchDest )
  {
      if( strDest == NULL || cchDest < 1 )
          return E_INVALIDARG;
  
      lstrcpy( strDest, TEXT("") );
  
      // Open the appropriate registry key
      HKEY  hKey;
      LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                                  _T("Software\\Microsoft\\DirectX SDK"),
                                  0, KEY_READ, &hKey );
      if( ERROR_SUCCESS != lResult )
          return E_FAIL;
  
      DWORD dwType;
      DWORD dwSize = cchDest * sizeof(TCHAR);
      lResult = RegQueryValueEx( hKey, _T("DX9J3SDK Samples Path"), NULL,
                                &dwType, (BYTE*)strDest, &dwSize );
      strDest[cchDest-1] = 0; // RegQueryValueEx doesn't NULL term if buffer too small
      RegCloseKey( hKey );
  
      if( ERROR_SUCCESS != lResult )
          return E_FAIL;
  
      const TCHAR* strMedia = _T("\\Media\\");
      if( lstrlen(strDest) + lstrlen(strMedia) < cchDest )
          _tcscat( strDest, strMedia );
      else
          return E_INVALIDARG;
  
      return S_OK;
  }
  endif // !UNDER_CE
  
  ifndef UNDER_CE
  //-----------------------------------------------------------------------------
  // Name: DXUtil_FindMediaFileCch()
  // Desc: Returns a valid path to a DXSDK media file
  //       cchDest is the size in TCHARs of strDestPath.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds.
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_FindMediaFileCch( TCHAR* strDestPath, int cchDest, TCHAR* strFilename )
  {
      HRESULT hr;
      HANDLE file;
      TCHAR* strShortNameTmp = NULL;
      TCHAR strShortName[MAX_PATH];
      int cchPath;
  
      if( NULL==strFilename || NULL==strDestPath || cchDest < 1 )
          return E_INVALIDARG;
  
      lstrcpy( strDestPath, TEXT("") );
      lstrcpy( strShortName, TEXT("") );
  
      // Build full path name from strFileName (strShortName will be just the leaf filename)
      cchPath = GetFullPathName(strFilename, cchDest, strDestPath, &strShortNameTmp);
  
      if ((cchPath == 0) || (cchDest <= cchPath))
          return E_FAIL;
      if( strShortNameTmp )
          lstrcpyn( strShortName, strShortNameTmp, MAX_PATH );
  
      // first try to find the filename given a full path
      file = CreateFile( strDestPath, GENERIC_READ, FILE_SHARE_READ, NULL, 
                         OPEN_EXISTING, 0, NULL );
      if( INVALID_HANDLE_VALUE != file )
      {
          CloseHandle( file );
          return S_OK;
      }
      
      // next try to find the filename in the current working directory (path stripped)
      file = CreateFile( strShortName, GENERIC_READ, FILE_SHARE_READ, NULL, 
                         OPEN_EXISTING, 0, NULL );
      if( INVALID_HANDLE_VALUE != file )
      {
          _tcsncpy( strDestPath, strShortName, cchDest );
          strDestPath[cchDest-1] = 0; // _tcsncpy doesn't NULL term if it runs out of space
          CloseHandle( file );
          return S_OK;
      }
      
      // last, check if the file exists in the media directory
      if( FAILED( hr = DXUtil_GetDXSDKMediaPathCch( strDestPath, cchDest ) ) )
          return hr;
  
      if( lstrlen(strDestPath) + lstrlen(strShortName) < cchDest )
          lstrcat( strDestPath, strShortName );
      else
          return E_INVALIDARG;
  
      file = CreateFile( strDestPath, GENERIC_READ, FILE_SHARE_READ, NULL, 
                         OPEN_EXISTING, 0, NULL );
      if( INVALID_HANDLE_VALUE != file )
      {
          CloseHandle( file );
          return S_OK;
      }
  
      // On failure, just return the file as the path
      _tcsncpy( strDestPath, strFilename, cchDest );
      strDestPath[cchDest-1] = 0; // _tcsncpy doesn't NULL term if it runs out of space
      return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  }
  endif // !UNDER_CE
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ReadStringRegKeyCch()
  // Desc: Helper function to read a registry key string
  //       cchDest is the size in TCHARs of strDest.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds.
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ReadStringRegKeyCch( HKEY hKey, TCHAR* strRegName, TCHAR* strDest, 
                                      DWORD cchDest, TCHAR* strDefault )
  {
      DWORD dwType;
      DWORD cbDest = cchDest * sizeof(TCHAR);
  
      if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
                                            (BYTE*)strDest, &cbDest ) )
      {
          _tcsncpy( strDest, strDefault, cchDest );
          strDest[cchDest-1] = 0;
  
          if( dwType != REG_SZ )
              return E_FAIL;
  
          return S_OK;
      }
  
      return E_FAIL;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_WriteStringRegKey()
  // Desc: Helper function to write a registry key string
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_WriteStringRegKey( HKEY hKey, TCHAR* strRegName,
                                    TCHAR* strValue )
  {
      if( NULL == strValue )
          return E_INVALIDARG;
          
      DWORD cbValue = ((DWORD)_tcslen(strValue)+1) * sizeof(TCHAR);
  
      if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_SZ, 
                                          (BYTE*)strValue, cbValue ) )
          return E_FAIL;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ReadIntRegKey()
  // Desc: Helper function to read a registry key int
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ReadIntRegKey( HKEY hKey, TCHAR* strRegName, DWORD* pdwDest, 
                                DWORD dwDefault )
  {
      DWORD dwType;
      DWORD dwLength = sizeof(DWORD);
  
      if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
                                            (BYTE*)pdwDest, &dwLength ) )
      {
          *pdwDest = dwDefault;
          if( dwType != REG_DWORD )
              return E_FAIL;
  
          return S_OK;
      }
  
      return E_FAIL;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_WriteIntRegKey()
  // Desc: Helper function to write a registry key int
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_WriteIntRegKey( HKEY hKey, TCHAR* strRegName, DWORD dwValue )
  {
      if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_DWORD, 
                                          (BYTE*)&dwValue, sizeof(DWORD) ) )
          return E_FAIL;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ReadBoolRegKey()
  // Desc: Helper function to read a registry key BOOL
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ReadBoolRegKey( HKEY hKey, TCHAR* strRegName, BOOL* pbDest, 
                                BOOL bDefault )
  {
      DWORD dwType;
      DWORD dwLength = sizeof(BOOL);
  
      if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
                                            (BYTE*)pbDest, &dwLength ) )
      {
          *pbDest = bDefault;
          if( dwType != REG_DWORD )
              return E_FAIL;
  
          return S_OK;
      }
  
      return E_FAIL;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_WriteBoolRegKey()
  // Desc: Helper function to write a registry key BOOL
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_WriteBoolRegKey( HKEY hKey, TCHAR* strRegName, BOOL bValue )
  {
      if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_DWORD, 
                                          (BYTE*)&bValue, sizeof(BOOL) ) )
          return E_FAIL;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ReadGuidRegKey()
  // Desc: Helper function to read a registry key guid
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ReadGuidRegKey( HKEY hKey, TCHAR* strRegName, GUID* pGuidDest, 
                                 GUID& guidDefault )
  {
      DWORD dwType;
      DWORD dwLength = sizeof(GUID);
  
      if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
                                            (LPBYTE) pGuidDest, &dwLength ) )
      {
          *pGuidDest = guidDefault;
          if( dwType != REG_BINARY )
              return E_FAIL;
  
          return S_OK;
      }
  
      return E_FAIL;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_WriteGuidRegKey()
  // Desc: Helper function to write a registry key guid
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_WriteGuidRegKey( HKEY hKey, TCHAR* strRegName, GUID guidValue )
  {
      if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_BINARY, 
                                          (BYTE*)&guidValue, sizeof(GUID) ) )
          return E_FAIL;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_Timer()
  // Desc: Performs timer opertations. Use the following commands:
  //          TIMER_RESET           - to reset the timer
  //          TIMER_START           - to start the timer
  //          TIMER_STOP            - to stop (or pause) the timer
  //          TIMER_ADVANCE         - to advance the timer by 0.1 seconds
  //          TIMER_GETABSOLUTETIME - to get the absolute system time
  //          TIMER_GETAPPTIME      - to get the current time
  //          TIMER_GETELAPSEDTIME  - to get the time that elapsed between 
  //                                  TIMER_GETELAPSEDTIME calls
  //-----------------------------------------------------------------------------
  FLOAT __stdcall DXUtil_Timer( TIMER_COMMAND command )
  {
      static BOOL     m_bTimerInitialized = FALSE;
      static BOOL     m_bUsingQPF         = FALSE;
      static BOOL     m_bTimerStopped     = TRUE;
      static LONGLONG m_llQPFTicksPerSec  = 0;
  
      // Initialize the timer
      if( FALSE == m_bTimerInitialized )
      {
          m_bTimerInitialized = TRUE;
  
          // Use QueryPerformanceFrequency() to get frequency of timer.  If QPF is
          // not supported, we will timeGetTime() which returns milliseconds.
          LARGE_INTEGER qwTicksPerSec;
          m_bUsingQPF = QueryPerformanceFrequency( &qwTicksPerSec );
          if( m_bUsingQPF )
              m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
      }
  
      if( m_bUsingQPF )
      {
          static LONGLONG m_llStopTime        = 0;
          static LONGLONG m_llLastElapsedTime = 0;
          static LONGLONG m_llBaseTime        = 0;
          double fTime;
          double fElapsedTime;
          LARGE_INTEGER qwTime;
          
          // Get either the current time or the stop time, depending
          // on whether we're stopped and what command was sent
          if( m_llStopTime != 0 && command != TIMER_START && command != TIMER_GETABSOLUTETIME)
              qwTime.QuadPart = m_llStopTime;
          else
              QueryPerformanceCounter( &qwTime );
  
          // Return the elapsed time
          if( command == TIMER_GETELAPSEDTIME )
          {
              fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
              m_llLastElapsedTime = qwTime.QuadPart;
              return (FLOAT) fElapsedTime;
          }
      
          // Return the current time
          if( command == TIMER_GETAPPTIME )
          {
              double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
              return (FLOAT) fAppTime;
          }
      
          // Reset the timer
          if( command == TIMER_RESET )
          {
              m_llBaseTime        = qwTime.QuadPart;
              m_llLastElapsedTime = qwTime.QuadPart;
              m_llStopTime        = 0;
              m_bTimerStopped     = FALSE;
              return 0.0f;
          }
      
          // Start the timer
          if( command == TIMER_START )
          {
              if( m_bTimerStopped )
                  m_llBaseTime += qwTime.QuadPart - m_llStopTime;
              m_llStopTime = 0;
              m_llLastElapsedTime = qwTime.QuadPart;
              m_bTimerStopped = FALSE;
              return 0.0f;
          }
      
          // Stop the timer
          if( command == TIMER_STOP )
          {
              m_llStopTime = qwTime.QuadPart;
              m_llLastElapsedTime = qwTime.QuadPart;
              m_bTimerStopped = TRUE;
              return 0.0f;
          }
      
          // Advance the timer by 1/10th second
          if( command == TIMER_ADVANCE )
          {
              m_llStopTime += m_llQPFTicksPerSec/10;
              return 0.0f;
          }
  
          if( command == TIMER_GETABSOLUTETIME )
          {
              fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
              return (FLOAT) fTime;
          }
  
          return -1.0f; // Invalid command specified
      }
      else
      {
          // Get the time using timeGetTime()
          static double m_fLastElapsedTime  = 0.0;
          static double m_fBaseTime         = 0.0;
          static double m_fStopTime         = 0.0;
          double fTime;
          double fElapsedTime;
          
          // Get either the current time or the stop time, depending
          // on whether we're stopped and what command was sent
          if( m_fStopTime != 0.0 && command != TIMER_START && command != TIMER_GETABSOLUTETIME)
              fTime = m_fStopTime;
          else
              fTime = GETTIMESTAMP() * 0.001;
      
          // Return the elapsed time
          if( command == TIMER_GETELAPSEDTIME )
          {   
              fElapsedTime = (double) (fTime - m_fLastElapsedTime);
              m_fLastElapsedTime = fTime;
              return (FLOAT) fElapsedTime;
          }
      
          // Return the current time
          if( command == TIMER_GETAPPTIME )
          {
              return (FLOAT) (fTime - m_fBaseTime);
          }
      
          // Reset the timer
          if( command == TIMER_RESET )
          {
              m_fBaseTime         = fTime;
              m_fLastElapsedTime  = fTime;
              m_fStopTime         = 0;
              m_bTimerStopped     = FALSE;
              return 0.0f;
          }
      
          // Start the timer
          if( command == TIMER_START )
          {
              if( m_bTimerStopped )
                  m_fBaseTime += fTime - m_fStopTime;
              m_fStopTime = 0.0f;
              m_fLastElapsedTime  = fTime;
              m_bTimerStopped = FALSE;
              return 0.0f;
          }
      
          // Stop the timer
          if( command == TIMER_STOP )
          {
              m_fStopTime = fTime;
              m_fLastElapsedTime  = fTime;
              m_bTimerStopped = TRUE;
              return 0.0f;
          }
      
          // Advance the timer by 1/10th second
          if( command == TIMER_ADVANCE )
          {
              m_fStopTime += 0.1f;
              return 0.0f;
          }
  
          if( command == TIMER_GETABSOLUTETIME )
          {
              return (FLOAT) fTime;
          }
  
          return -1.0f; // Invalid command specified
      }
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertAnsiStringToWideCch()
  // Desc: This is a UNICODE conversion utility to convert a CHAR string into a
  //       WCHAR string. 
  //       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to 
  //       pass in sizeof(strDest) 
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertAnsiStringToWideCch( WCHAR* wstrDestination, const CHAR* strSource, 
                                       int cchDestChar )
  {
      if( wstrDestination==NULL || strSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
  
      int nResult = MultiByteToWideChar( CP_ACP, 0, strSource, -1, 
                                         wstrDestination, cchDestChar );
      wstrDestination[cchDestChar-1] = 0;
      
      if( nResult == 0 )
          return E_FAIL;
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertWideStringToAnsi()
  // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
  //       CHAR string. 
  //       cchDestChar is the size in TCHARs of strDestination
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertWideStringToAnsiCch( CHAR* strDestination, const WCHAR* wstrSource, 
                                       int cchDestChar )
  {
      if( strDestination==NULL || wstrSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
  
      int nResult = WideCharToMultiByte( CP_ACP, 0, wstrSource, -1, strDestination, 
                                         cchDestChar*sizeof(CHAR), NULL, NULL );
      strDestination[cchDestChar-1] = 0;
      
      if( nResult == 0 )
          return E_FAIL;
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertGenericStringToAnsi()
  // Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
  //       CHAR string. 
  //       cchDestChar is the size in TCHARs of strDestination
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertGenericStringToAnsiCch( CHAR* strDestination, const TCHAR* tstrSource, 
                                             int cchDestChar )
  {
      if( strDestination==NULL || tstrSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
  
  ifdef _UNICODE
      return DXUtil_ConvertWideStringToAnsiCch( strDestination, tstrSource, cchDestChar );
  else
      strncpy( strDestination, tstrSource, cchDestChar );
      strDestination[cchDestChar-1] = '\0';
      return S_OK;
  endif   
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertGenericStringToWide()
  // Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
  //       WCHAR string. 
  //       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to 
  //       pass in sizeof(strDest) 
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertGenericStringToWideCch( WCHAR* wstrDestination, const TCHAR* tstrSource, 
                                             int cchDestChar )
  {
      if( wstrDestination==NULL || tstrSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
  
  ifdef _UNICODE
      wcsncpy( wstrDestination, tstrSource, cchDestChar );
      wstrDestination[cchDestChar-1] = L'\0';
      return S_OK;
  else
      return DXUtil_ConvertAnsiStringToWideCch( wstrDestination, tstrSource, cchDestChar );
  endif    
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertAnsiStringToGeneric()
  // Desc: This is a UNICODE conversion utility to convert a CHAR string into a
  //       TCHAR string. 
  //       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertAnsiStringToGenericCch( TCHAR* tstrDestination, const CHAR* strSource, 
                                             int cchDestChar )
  {
      if( tstrDestination==NULL || strSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
          
  ifdef _UNICODE
      return DXUtil_ConvertAnsiStringToWideCch( tstrDestination, strSource, cchDestChar );
  else
      strncpy( tstrDestination, strSource, cchDestChar );
      tstrDestination[cchDestChar-1] = '\0';
      return S_OK;
  endif    
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertAnsiStringToGeneric()
  // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
  //       TCHAR string. 
  //       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertWideStringToGenericCch( TCHAR* tstrDestination, const WCHAR* wstrSource, 
                                             int cchDestChar )
  {
      if( tstrDestination==NULL || wstrSource==NULL || cchDestChar < 1 )
          return E_INVALIDARG;
  
  ifdef _UNICODE
      wcsncpy( tstrDestination, wstrSource, cchDestChar );
      tstrDestination[cchDestChar-1] = L'\0';    
      return S_OK;
  else
      return DXUtil_ConvertWideStringToAnsiCch( tstrDestination, wstrSource, cchDestChar );
  endif
  }
  
  ifndef UNDER_CE
  //-----------------------------------------------------------------------------
  // Name: DXUtil_LaunchReadme()
  // Desc: Finds and opens the readme.txt for this sample
  //-----------------------------------------------------------------------------
  VOID DXUtil_LaunchReadme( HWND hWnd )
  {
      bool bSuccess = false;
      bool bFound = false;
      TCHAR strReadmePath[1024];
      TCHAR strExeName[MAX_PATH];
      TCHAR strExePath[MAX_PATH];
      TCHAR* strLastSlash = NULL;
  
      lstrcpy( strReadmePath, TEXT("") );
      lstrcpy( strExePath, TEXT("") );
      lstrcpy( strExeName, TEXT("") );
  
      // Get the exe name, and exe path
      GetModuleFileName( NULL, strExePath, MAX_PATH );
      strExePath[MAX_PATH-1]=0;
  
      strLastSlash = _tcsrchr( strExePath, TEXT('\\') );
      if( strLastSlash )
      {
          lstrcpyn( strExeName, &strLastSlash[1], MAX_PATH );
          strExeName[MAX_PATH-1]=0;
  
          // Chop the exe name from the exe path
          *strLastSlash = 0;
  
          // Chop the .exe from the exe name
          strLastSlash = _tcsrchr( strExeName, TEXT('.') );
          if( strLastSlash )
              *strLastSlash = 0;
      }
  
      if( !bFound )
      {
          // Search in "\%EXE_DIR%\..%EXE_NAME%".  This matchs the DirectX SDK layout
          _tcscpy( strReadmePath, strExePath );
  
          strLastSlash = _tcsrchr( strReadmePath, TEXT('\\') );
          if( strLastSlash )
              *strLastSlash = 0;
          lstrcat( strReadmePath, TEXT("\\") );
          lstrcat( strReadmePath, strExeName );
          lstrcat( strReadmePath, TEXT("\\readme.txt") );
          if( GetFileAttributes( strReadmePath ) != 0xFFFFFFFF )
              bFound = TRUE;
      }
  
      if( !bFound )
      {
          // Search in "\%EXE_DIR%\"
          _tcscpy( strReadmePath, strExePath );
          lstrcat( strReadmePath, TEXT("\\readme.txt") );
          if( GetFileAttributes( strReadmePath ) != 0xFFFFFFFF )
              bFound = TRUE;
      }
  
      if( !bFound )
      {
          // Search in "\%EXE_DIR%\.."
          _tcscpy( strReadmePath, strExePath );
          strLastSlash = _tcsrchr( strReadmePath, TEXT('\\') );
          if( strLastSlash )
              *strLastSlash = 0;
          lstrcat( strReadmePath, TEXT("\\readme.txt") );
          if( GetFileAttributes( strReadmePath ) != 0xFFFFFFFF )
              bFound = TRUE;
      }
  
      if( !bFound )
      {
          // Search in "\%EXE_DIR%\..\.."
          _tcscpy( strReadmePath, strExePath );
          strLastSlash = _tcsrchr( strReadmePath, TEXT('\\') );
          if( strLastSlash )
              *strLastSlash = 0;
          strLastSlash = _tcsrchr( strReadmePath, TEXT('\\') );
          if( strLastSlash )
              *strLastSlash = 0;
          lstrcat( strReadmePath, TEXT("\\readme.txt") );
          if( GetFileAttributes( strReadmePath ) != 0xFFFFFFFF )
              bFound = TRUE;
      }
  
      if( bFound )
      {
          // GetProcAddress for ShellExecute, so we don't have to include shell32.lib 
          // in every project that uses dxutil.cpp
          LPShellExecute pShellExecute = NULL;
          HINSTANCE hInstShell32 = LoadLibrary(TEXT(<shell32.dll>));
          if (hInstShell32 != NULL)
          {
  ifdef UNICODE
              pShellExecute = (LPShellExecute)GetProcAddress(hInstShell32, _TWINCE("ShellExecuteW"));
  else
              pShellExecute = (LPShellExecute)GetProcAddress(hInstShell32, _TWINCE("ShellExecuteA"));
  endif
              if( pShellExecute != NULL )
              {
                  if( pShellExecute( hWnd, TEXT("open"), strReadmePath, NULL, NULL, SW_SHOW ) > (HINSTANCE) 32 )
                      bSuccess = true;
              }
  
              FreeLibrary(hInstShell32);
          }
      }
  
      if( !bSuccess )
      {
          // Tell the user that the readme couldn't be opened
          MessageBox( hWnd, TEXT("Could not find readme.txt"), 
                      TEXT("DirectX SDK Sample"), MB_ICONWARNING | MB_OK );
      }
  }
  endif // !UNDER_CE
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_Trace()
  // Desc: Outputs to the debug stream a formatted string with a variable-
  //       argument list.
  //-----------------------------------------------------------------------------
  VOID DXUtil_Trace( TCHAR* strMsg, ... )
  {
  if defined(DEBUG) | defined(_DEBUG)
      TCHAR strBuffer[512];
      
      va_list args;
      va_start(args, strMsg);
      _vsntprintf( strBuffer, 512, strMsg, args );
      va_end(args);
  
      OutputDebugString( strBuffer );
  else
      UNREFERENCED_PARAMETER(strMsg);
  endif
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertStringToGUID()
  // Desc: Converts a string to a GUID
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertStringToGUID( const TCHAR* strSrc, GUID* pGuidDest )
  {
      UINT aiTmp[10];
  
      if( _stscanf( strSrc, TEXT("{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}"),
                      &pGuidDest->Data1, 
                      &aiTmp[0], &aiTmp[1], 
                      &aiTmp[2], &aiTmp[3],
                      &aiTmp[4], &aiTmp[5],
                      &aiTmp[6], &aiTmp[7],
                      &aiTmp[8], &aiTmp[9] ) != 11 )
      {
          ZeroMemory( pGuidDest, sizeof(GUID) );
          return E_FAIL;
      }
      else
      {
          pGuidDest->Data2       = (USHORT) aiTmp[0];
          pGuidDest->Data3       = (USHORT) aiTmp[1];
          pGuidDest->Data4[0]    = (BYTE) aiTmp[2];
          pGuidDest->Data4[1]    = (BYTE) aiTmp[3];
          pGuidDest->Data4[2]    = (BYTE) aiTmp[4];
          pGuidDest->Data4[3]    = (BYTE) aiTmp[5];
          pGuidDest->Data4[4]    = (BYTE) aiTmp[6];
          pGuidDest->Data4[5]    = (BYTE) aiTmp[7];
          pGuidDest->Data4[6]    = (BYTE) aiTmp[8];
          pGuidDest->Data4[7]    = (BYTE) aiTmp[9];
          return S_OK;
      }
  }
  
  //-----------------------------------------------------------------------------
  // Name: DXUtil_ConvertGUIDToStringCch()
  // Desc: Converts a GUID to a string 
  //       cchDestChar is the size in TCHARs of strDest.  Be careful not to 
  //       pass in sizeof(strDest) on UNICODE builds
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertGUIDToStringCch( const GUID* pGuidSrc, TCHAR* strDest, int cchDestChar )
  {
      int nResult = _sntprintf( strDest, cchDestChar, TEXT("{%0.8X-%0.4X-%0.4X-%0.2X%0.2X-%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X}"),
                 pGuidSrc->Data1, pGuidSrc->Data2, pGuidSrc->Data3,
                 pGuidSrc->Data4[0], pGuidSrc->Data4[1],
                 pGuidSrc->Data4[2], pGuidSrc->Data4[3],
                 pGuidSrc->Data4[4], pGuidSrc->Data4[5],
                 pGuidSrc->Data4[6], pGuidSrc->Data4[7] );
  
      if( nResult < 0 )
          return E_FAIL;
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList constructor
  // Desc: 
  //-----------------------------------------------------------------------------
  CArrayList::CArrayList( ArrayListType Type, UINT BytesPerEntry )
  {
      if( Type == AL_REFERENCE )
          BytesPerEntry = sizeof(void*);
      m_ArrayListType = Type;
      m_pData = NULL;
      m_BytesPerEntry = BytesPerEntry;
      m_NumEntries = 0;
      m_NumEntriesAllocated = 0;
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList destructor
  // Desc: 
  //-----------------------------------------------------------------------------
  CArrayList::~CArrayList( void )
  {
      if( m_pData != NULL )
          delete[] m_pData;
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList::Add
  // Desc: Adds pEntry to the list.
  //-----------------------------------------------------------------------------
  HRESULT CArrayList::Add( void* pEntry )
  {
      if( m_BytesPerEntry == 0 )
          return E_FAIL;
      if( m_pData == NULL || m_NumEntries + 1 > m_NumEntriesAllocated )
      {
          void* pDataNew;
          UINT NumEntriesAllocatedNew;
          if( m_NumEntriesAllocated == 0 )
              NumEntriesAllocatedNew = 16;
          else
              NumEntriesAllocatedNew = m_NumEntriesAllocated * 2;
          pDataNew = new BYTE[NumEntriesAllocatedNew * m_BytesPerEntry];
          if( pDataNew == NULL )
              return E_OUTOFMEMORY;
          if( m_pData != NULL )
          {
              CopyMemory( pDataNew, m_pData, m_NumEntries * m_BytesPerEntry );
              delete[] m_pData;
          }
          m_pData = pDataNew;
          m_NumEntriesAllocated = NumEntriesAllocatedNew;
      }
  
      if( m_ArrayListType == AL_VALUE )
          CopyMemory( (BYTE*)m_pData + (m_NumEntries * m_BytesPerEntry), pEntry, m_BytesPerEntry );
      else
          *(((void**)m_pData) + m_NumEntries) = pEntry;
      m_NumEntries++;
  
      return S_OK;
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList::Remove
  // Desc: Remove the item at Entry in the list, and collapse the array. 
  //-----------------------------------------------------------------------------
  void CArrayList::Remove( UINT Entry )
  {
      // Decrement count
      m_NumEntries--;
  
      // Find the entry address
      BYTE* pData = (BYTE*)m_pData + (Entry * m_BytesPerEntry);
  
      // Collapse the array
      MoveMemory( pData, pData + m_BytesPerEntry, ( m_NumEntries - Entry ) * m_BytesPerEntry );
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList::GetPtr
  // Desc: Returns a pointer to the Entry'th entry in the list.
  //-----------------------------------------------------------------------------
  void* CArrayList::GetPtr( UINT Entry )
  {
      if( m_ArrayListType == AL_VALUE )
          return (BYTE*)m_pData + (Entry * m_BytesPerEntry);
      else
          return *(((void**)m_pData) + Entry);
  }
  
  //-----------------------------------------------------------------------------
  // Name: CArrayList::Contains
  // Desc: Returns whether the list contains an entry identical to the 
  //       specified entry data.
  //-----------------------------------------------------------------------------
  bool CArrayList::Contains( void* pEntryData )
  {
      for( UINT iEntry = 0; iEntry < m_NumEntries; iEntry++ )
      {
          if( m_ArrayListType == AL_VALUE )
          {
              if( memcmp( GetPtr(iEntry), pEntryData, m_BytesPerEntry ) == 0 )
                  return true;
          }
          else
          {
              if( GetPtr(iEntry) == pEntryData )
                  return true;
          }
      }
      return false;
  }
  
  //-----------------------------------------------------------------------------
  // Name: BYTE helper functions
  // Desc: cchDestChar is the size in BYTEs of strDest.  Be careful not to 
  //       pass use sizeof() if the strDest is a string pointer.  
  //       eg.
  //       TCHAR* sz = new TCHAR[100]; // sizeof(sz)  == 4
  //       TCHAR sz2[100];             // sizeof(sz2) == 200
  //-----------------------------------------------------------------------------
  HRESULT DXUtil_ConvertAnsiStringToWideCb( WCHAR* wstrDestination, const CHAR* strSource, int cbDestChar )
  {
      return DXUtil_ConvertAnsiStringToWideCch( wstrDestination, strSource, cbDestChar / sizeof(WCHAR) );
  }
  
  HRESULT DXUtil_ConvertWideStringToAnsiCb( CHAR* strDestination, const WCHAR* wstrSource, int cbDestChar )
  {
      return DXUtil_ConvertWideStringToAnsiCch( strDestination, wstrSource, cbDestChar / sizeof(CHAR) );
  }
  
  HRESULT DXUtil_ConvertGenericStringToAnsiCb( CHAR* strDestination, const TCHAR* tstrSource, int cbDestChar )
  {
      return DXUtil_ConvertGenericStringToAnsiCch( strDestination, tstrSource, cbDestChar / sizeof(CHAR) );
  }
  
  HRESULT DXUtil_ConvertGenericStringToWideCb( WCHAR* wstrDestination, const TCHAR* tstrSource, int cbDestChar )
  {
      return DXUtil_ConvertGenericStringToWideCch( wstrDestination, tstrSource, cbDestChar / sizeof(WCHAR) );
  }
  
  HRESULT DXUtil_ConvertAnsiStringToGenericCb( TCHAR* tstrDestination, const CHAR* strSource, int cbDestChar )
  {
      return DXUtil_ConvertAnsiStringToGenericCch( tstrDestination, strSource, cbDestChar / sizeof(TCHAR) );
  }
  
  HRESULT DXUtil_ConvertWideStringToGenericCb( TCHAR* tstrDestination, const WCHAR* wstrSource, int cbDestChar )
  {
      return DXUtil_ConvertWideStringToGenericCch( tstrDestination, wstrSource, cbDestChar / sizeof(TCHAR) );
  }
  
  HRESULT DXUtil_ReadStringRegKeyCb( HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault )
  {
      return DXUtil_ReadStringRegKeyCch( hKey, strRegName, strDest, cbDest / sizeof(TCHAR), strDefault );
  }
  
  HRESULT DXUtil_ConvertGUIDToStringCb( const GUID* pGuidSrc, TCHAR* strDest, int cbDestChar )
  {
      return DXUtil_ConvertGUIDToStringCch( pGuidSrc, strDest, cbDestChar / sizeof(TCHAR) );
  }
  
  ifndef UNDER_CE
  HRESULT DXUtil_GetDXSDKMediaPathCb( TCHAR* szDest, int cbDest )
  {
      return DXUtil_GetDXSDKMediaPathCch( szDest, cbDest / sizeof(TCHAR) );
  }
  
  HRESULT DXUtil_FindMediaFileCb( TCHAR* szDestPath, int cbDest, TCHAR* strFilename )
  {
      return DXUtil_FindMediaFileCch( szDestPath, cbDest / sizeof(TCHAR), strFilename );
  }
  endif // !UNDER_CE
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.