home *** CD-ROM | disk | FTP | other *** search
/ Game Programming in C++ - Start to Finish / GameProgrammingS.iso / developer_install / ReplicaNetFreewareV5_4.exe / data1.cab / Program_Executable_Files / Common3DApp / Src / dxutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-10-30  |  19.7 KB  |  627 lines

  1. //-----------------------------------------------------------------------------
  2. // File: DXUtil.cpp
  3. //
  4. // Desc: Shortcut macros and functions for using DX objects
  5. //
  6. //
  7. // Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <mmsystem.h>
  12. #include <tchar.h>
  13. #include <stdio.h> 
  14. #include <stdarg.h>
  15. #include "DXUtil.h"
  16.  
  17.  
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Name: DXUtil_GetDXSDKMediaPath()
  22. // Desc: Returns the DirectX SDK media path
  23. //-----------------------------------------------------------------------------
  24. const TCHAR* DXUtil_GetDXSDKMediaPath()
  25. {
  26.     static TCHAR strNull[2] = _T("");
  27.     static TCHAR strPath[MAX_PATH];
  28.     DWORD dwType;
  29.     DWORD dwSize = MAX_PATH;
  30.     HKEY  hKey;
  31.  
  32.     // Open the appropriate registry key
  33.     LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  34.                                 _T("Software\\Microsoft\\DirectX"),
  35.                                 0, KEY_READ, &hKey );
  36.     if( ERROR_SUCCESS != lResult )
  37.         return strNull;
  38.  
  39.     lResult = RegQueryValueEx( hKey, _T("DX8SDK Samples Path"), NULL,
  40.                               &dwType, (BYTE*)strPath, &dwSize );
  41.     RegCloseKey( hKey );
  42.  
  43.     if( ERROR_SUCCESS != lResult )
  44.         return strNull;
  45.  
  46.     _tcscat( strPath, _T("\\Media\\") );
  47.  
  48.     return strPath;
  49. }
  50.  
  51.  
  52.  
  53.  
  54. //-----------------------------------------------------------------------------
  55. // Name: DXUtil_FindMediaFile()
  56. // Desc: Returns a valid path to a DXSDK media file
  57. //-----------------------------------------------------------------------------
  58. HRESULT DXUtil_FindMediaFile( TCHAR* strPath, TCHAR* strFilename )
  59. {
  60.     HANDLE file;
  61.  
  62. #ifdef _DEBUG
  63.     char buffer[512];
  64.     sprintf(buffer,"Looking for %s\n",strFilename);
  65.     OutputDebugString(buffer);
  66. #endif
  67.  
  68.     if( NULL==strFilename || NULL==strPath )
  69.         return E_INVALIDARG;
  70.  
  71.     // Check if the file exists in the current directory
  72.     _tcscpy( strPath, strFilename );
  73.  
  74.     file = CreateFile( strPath, GENERIC_READ, FILE_SHARE_READ, NULL, 
  75.                        OPEN_EXISTING, 0, NULL );
  76.     if( INVALID_HANDLE_VALUE != file )
  77.     {
  78.         CloseHandle( file );
  79.         return S_OK;
  80.     }
  81.     
  82.     // Check if the file exists in the DX media directory
  83.     _stprintf( strPath, _T("%s%s"), DXUtil_GetDXSDKMediaPath(), strFilename );
  84.  
  85.     file = CreateFile( strPath, GENERIC_READ, FILE_SHARE_READ, NULL, 
  86.                        OPEN_EXISTING, 0, NULL );
  87.     if( INVALID_HANDLE_VALUE != file )
  88.     {
  89. #ifdef _DEBUG
  90.         sprintf(buffer,"    Found it in %s\n",strPath);
  91.         OutputDebugString(buffer);
  92. #endif
  93.         CloseHandle( file );
  94.         return S_OK;
  95.     }
  96.  
  97.     // On failure, just return the file as the path
  98.     _tcscpy( strPath, strFilename );
  99.     return E_FAIL;
  100. }
  101.  
  102.  
  103.  
  104.  
  105. //-----------------------------------------------------------------------------
  106. // Name: DXUtil_ReadStringRegKey()
  107. // Desc: Helper function to read a registry key string
  108. //-----------------------------------------------------------------------------
  109. HRESULT DXUtil_ReadStringRegKey( HKEY hKey, TCHAR* strRegName, TCHAR* strValue, 
  110.                                  DWORD dwLength, TCHAR* strDefault )
  111. {
  112.     DWORD dwType;
  113.  
  114.     if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
  115.                                           (BYTE*)strValue, &dwLength ) )
  116.     {
  117.         _tcscpy( strValue, strDefault );
  118.     }
  119.  
  120.     return S_OK;
  121. }
  122.  
  123.  
  124.  
  125.  
  126. //-----------------------------------------------------------------------------
  127. // Name: DXUtil_WriteStringRegKey()
  128. // Desc: Helper function to write a registry key string
  129. //-----------------------------------------------------------------------------
  130. HRESULT DXUtil_WriteStringRegKey( HKEY hKey, TCHAR* strRegName,
  131.                                   TCHAR* strValue )
  132. {
  133.     if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_SZ, 
  134.                                         (BYTE*)strValue, 
  135.                                         (_tcslen(strValue)+1)*sizeof(TCHAR) ) )
  136.         return E_FAIL;
  137.  
  138.     return S_OK;
  139. }
  140.  
  141.  
  142.  
  143.  
  144. //-----------------------------------------------------------------------------
  145. // Name: DXUtil_ReadIntRegKey()
  146. // Desc: Helper function to read a registry key int
  147. //-----------------------------------------------------------------------------
  148. HRESULT DXUtil_ReadIntRegKey( HKEY hKey, TCHAR* strRegName, DWORD* pdwValue, 
  149.                               DWORD dwDefault )
  150. {
  151.     DWORD dwType;
  152.     DWORD dwLength = sizeof(DWORD);
  153.  
  154.     if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
  155.                                           (BYTE*)pdwValue, &dwLength ) )
  156.     {
  157.         *pdwValue = dwDefault;
  158.     }
  159.  
  160.     return S_OK;
  161. }
  162.  
  163.  
  164.  
  165.  
  166. //-----------------------------------------------------------------------------
  167. // Name: DXUtil_WriteIntRegKey()
  168. // Desc: Helper function to write a registry key int
  169. //-----------------------------------------------------------------------------
  170. HRESULT DXUtil_WriteIntRegKey( HKEY hKey, TCHAR* strRegName, DWORD dwValue )
  171. {
  172.     if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_DWORD, 
  173.                                         (BYTE*)&dwValue, sizeof(DWORD) ) )
  174.         return E_FAIL;
  175.  
  176.     return S_OK;
  177. }
  178.  
  179.  
  180.  
  181.  
  182. //-----------------------------------------------------------------------------
  183. // Name: DXUtil_ReadBoolRegKey()
  184. // Desc: Helper function to read a registry key BOOL
  185. //-----------------------------------------------------------------------------
  186. HRESULT DXUtil_ReadBoolRegKey( HKEY hKey, TCHAR* strRegName, BOOL* pbValue, 
  187.                               BOOL bDefault )
  188. {
  189.     DWORD dwType;
  190.     DWORD dwLength = sizeof(BOOL);
  191.  
  192.     if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
  193.                                           (BYTE*)pbValue, &dwLength ) )
  194.     {
  195.         *pbValue = bDefault;
  196.     }
  197.  
  198.     return S_OK;
  199. }
  200.  
  201.  
  202.  
  203.  
  204. //-----------------------------------------------------------------------------
  205. // Name: DXUtil_WriteBoolRegKey()
  206. // Desc: Helper function to write a registry key BOOL
  207. //-----------------------------------------------------------------------------
  208. HRESULT DXUtil_WriteBoolRegKey( HKEY hKey, TCHAR* strRegName, BOOL bValue )
  209. {
  210.     if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_DWORD, 
  211.                                         (BYTE*)&bValue, sizeof(BOOL) ) )
  212.         return E_FAIL;
  213.  
  214.     return S_OK;
  215. }
  216.  
  217.  
  218.  
  219.  
  220. //-----------------------------------------------------------------------------
  221. // Name: DXUtil_ReadGuidRegKey()
  222. // Desc: Helper function to read a registry key guid
  223. //-----------------------------------------------------------------------------
  224. HRESULT DXUtil_ReadGuidRegKey( HKEY hKey, TCHAR* strRegName, GUID* pGuidValue, 
  225.                                GUID& guidDefault )
  226. {
  227.     DWORD dwType;
  228.     DWORD dwLength = sizeof(GUID);
  229.  
  230.     if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, 
  231.                                           (LPBYTE) pGuidValue, &dwLength ) )
  232.     {
  233.         *pGuidValue = guidDefault;
  234.     }
  235.  
  236.     return S_OK;
  237. }
  238.  
  239.  
  240.  
  241.  
  242. //-----------------------------------------------------------------------------
  243. // Name: DXUtil_WriteGuidRegKey()
  244. // Desc: Helper function to write a registry key guid
  245. //-----------------------------------------------------------------------------
  246. HRESULT DXUtil_WriteGuidRegKey( HKEY hKey, TCHAR* strRegName, GUID guidValue )
  247. {
  248.     if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_BINARY, 
  249.                                         (BYTE*)&guidValue, sizeof(GUID) ) )
  250.         return E_FAIL;
  251.  
  252.     return S_OK;
  253. }
  254.  
  255.  
  256.  
  257.  
  258. //-----------------------------------------------------------------------------
  259. // Name: DXUtil_Timer()
  260. // Desc: Performs timer opertations. Use the following commands:
  261. //          TIMER_RESET           - to reset the timer
  262. //          TIMER_START           - to start the timer
  263. //          TIMER_STOP            - to stop (or pause) the timer
  264. //          TIMER_ADVANCE         - to advance the timer by 0.1 seconds
  265. //          TIMER_GETABSOLUTETIME - to get the absolute system time
  266. //          TIMER_GETAPPTIME      - to get the current time
  267. //          TIMER_GETELAPSEDTIME  - to get the time that elapsed between 
  268. //                                  TIMER_GETELAPSEDTIME calls
  269. //-----------------------------------------------------------------------------
  270. FLOAT __stdcall DXUtil_Timer( TIMER_COMMAND command )
  271. {
  272.     static BOOL     m_bTimerInitialized = FALSE;
  273.     static BOOL     m_bUsingQPF         = FALSE;
  274.     static LONGLONG m_llQPFTicksPerSec  = 0;
  275.  
  276.     // Initialize the timer
  277.     if( FALSE == m_bTimerInitialized )
  278.     {
  279.         m_bTimerInitialized = TRUE;
  280.  
  281.         // Use QueryPerformanceFrequency() to get frequency of timer.  If QPF is
  282.         // not supported, we will timeGetTime() which returns milliseconds.
  283.         LARGE_INTEGER qwTicksPerSec;
  284.         m_bUsingQPF = QueryPerformanceFrequency( &qwTicksPerSec );
  285.         if( m_bUsingQPF )
  286.             m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
  287.     }
  288.  
  289.     if( m_bUsingQPF )
  290.     {
  291.         static LONGLONG m_llStopTime        = 0;
  292.         static LONGLONG m_llLastElapsedTime = 0;
  293.         static LONGLONG m_llBaseTime        = 0;
  294.         double fTime;
  295.         double fElapsedTime;
  296.         LARGE_INTEGER qwTime;
  297.         
  298.         // Get either the current time or the stop time, depending
  299.         // on whether we're stopped and what command was sent
  300.         if( m_llStopTime != 0 && command != TIMER_START && command != TIMER_GETABSOLUTETIME)
  301.             qwTime.QuadPart = m_llStopTime;
  302.         else
  303.             QueryPerformanceCounter( &qwTime );
  304.  
  305.         // Return the elapsed time
  306.         if( command == TIMER_GETELAPSEDTIME )
  307.         {
  308.             fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
  309.             m_llLastElapsedTime = qwTime.QuadPart;
  310.             return (FLOAT) fElapsedTime;
  311.         }
  312.     
  313.         // Return the current time
  314.         if( command == TIMER_GETAPPTIME )
  315.         {
  316.             double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
  317.             return (FLOAT) fAppTime;
  318.         }
  319.     
  320.         // Reset the timer
  321.         if( command == TIMER_RESET )
  322.         {
  323.             m_llBaseTime        = qwTime.QuadPart;
  324.             m_llLastElapsedTime = qwTime.QuadPart;
  325.             return 0.0f;
  326.         }
  327.     
  328.         // Start the timer
  329.         if( command == TIMER_START )
  330.         {
  331.             m_llBaseTime += qwTime.QuadPart - m_llStopTime;
  332.             m_llStopTime = 0;
  333.             m_llLastElapsedTime = qwTime.QuadPart;
  334.             return 0.0f;
  335.         }
  336.     
  337.         // Stop the timer
  338.         if( command == TIMER_STOP )
  339.         {
  340.             m_llStopTime = qwTime.QuadPart;
  341.             m_llLastElapsedTime = qwTime.QuadPart;
  342.             return 0.0f;
  343.         }
  344.     
  345.         // Advance the timer by 1/10th second
  346.         if( command == TIMER_ADVANCE )
  347.         {
  348.             m_llStopTime += m_llQPFTicksPerSec/10;
  349.             return 0.0f;
  350.         }
  351.  
  352.         if( command == TIMER_GETABSOLUTETIME )
  353.         {
  354.             fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
  355.             return (FLOAT) fTime;
  356.         }
  357.  
  358.         return -1.0f; // Invalid command specified
  359.     }
  360.     else
  361.     {
  362.         // Get the time using timeGetTime()
  363.         static double m_fLastElapsedTime  = 0.0;
  364.         static double m_fBaseTime         = 0.0;
  365.         static double m_fStopTime         = 0.0;
  366.         double fTime;
  367.         double fElapsedTime;
  368.         
  369.         // Get either the current time or the stop time, depending
  370.         // on whether we're stopped and what command was sent
  371.         if( m_fStopTime != 0.0 && command != TIMER_START && command != TIMER_GETABSOLUTETIME)
  372.             fTime = m_fStopTime;
  373.         else
  374.             fTime = timeGetTime() * 0.001;
  375.     
  376.         // Return the elapsed time
  377.         if( command == TIMER_GETELAPSEDTIME )
  378.         {   
  379.             fElapsedTime = (double) (fTime - m_fLastElapsedTime);
  380.             m_fLastElapsedTime = fTime;
  381.             return (FLOAT) fElapsedTime;
  382.         }
  383.     
  384.         // Return the current time
  385.         if( command == TIMER_GETAPPTIME )
  386.         {
  387.             return (FLOAT) (fTime - m_fBaseTime);
  388.         }
  389.     
  390.         // Reset the timer
  391.         if( command == TIMER_RESET )
  392.         {
  393.             m_fBaseTime         = fTime;
  394.             m_fLastElapsedTime  = fTime;
  395.             return 0.0f;
  396.         }
  397.     
  398.         // Start the timer
  399.         if( command == TIMER_START )
  400.         {
  401.             m_fBaseTime += fTime - m_fStopTime;
  402.             m_fStopTime = 0.0f;
  403.             m_fLastElapsedTime  = fTime;
  404.             return 0.0f;
  405.         }
  406.     
  407.         // Stop the timer
  408.         if( command == TIMER_STOP )
  409.         {
  410.             m_fStopTime = fTime;
  411.             return 0.0f;
  412.         }
  413.     
  414.         // Advance the timer by 1/10th second
  415.         if( command == TIMER_ADVANCE )
  416.         {
  417.             m_fStopTime += 0.1f;
  418.             return 0.0f;
  419.         }
  420.  
  421.         if( command == TIMER_GETABSOLUTETIME )
  422.         {
  423.             return (FLOAT) fTime;
  424.         }
  425.  
  426.         return -1.0f; // Invalid command specified
  427.     }
  428. }
  429.  
  430.  
  431.  
  432.  
  433. //-----------------------------------------------------------------------------
  434. // Name: DXUtil_ConvertAnsiStringToWide()
  435. // Desc: This is a UNICODE conversion utility to convert a CHAR string into a
  436. //       WCHAR string. cchDestChar defaults -1 which means it 
  437. //       assumes strDest is large enough to store strSource
  438. //-----------------------------------------------------------------------------
  439. VOID DXUtil_ConvertAnsiStringToWide( WCHAR* wstrDestination, const CHAR* strSource, 
  440.                                      int cchDestChar )
  441. {
  442.     if( wstrDestination==NULL || strSource==NULL )
  443.         return;
  444.  
  445.     if( cchDestChar == -1 )
  446.         cchDestChar = strlen(strSource)+1;
  447.  
  448.     MultiByteToWideChar( CP_ACP, 0, strSource, -1, 
  449.                          wstrDestination, cchDestChar-1 );
  450.  
  451.     wstrDestination[cchDestChar-1] = 0;
  452. }
  453.  
  454.  
  455.  
  456.  
  457. //-----------------------------------------------------------------------------
  458. // Name: DXUtil_ConvertWideStringToAnsi()
  459. // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
  460. //       CHAR string. cchDestChar defaults -1 which means it 
  461. //       assumes strDest is large enough to store strSource
  462. //-----------------------------------------------------------------------------
  463. VOID DXUtil_ConvertWideStringToAnsi( CHAR* strDestination, const WCHAR* wstrSource, 
  464.                                      int cchDestChar )
  465. {
  466.     if( strDestination==NULL || wstrSource==NULL )
  467.         return;
  468.  
  469.     if( cchDestChar == -1 )
  470.         cchDestChar = wcslen(wstrSource)+1;
  471.  
  472.     WideCharToMultiByte( CP_ACP, 0, wstrSource, -1, strDestination, 
  473.                          cchDestChar-1, NULL, NULL );
  474.  
  475.     strDestination[cchDestChar-1] = 0;
  476. }
  477.  
  478.  
  479.  
  480.  
  481. //-----------------------------------------------------------------------------
  482. // Name: DXUtil_ConvertGenericStringToAnsi()
  483. // Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
  484. //       CHAR string. cchDestChar defaults -1 which means it 
  485. //       assumes strDest is large enough to store strSource
  486. //-----------------------------------------------------------------------------
  487. VOID DXUtil_ConvertGenericStringToAnsi( CHAR* strDestination, const TCHAR* tstrSource, 
  488.                                         int cchDestChar )
  489. {
  490.     if( strDestination==NULL || tstrSource==NULL )
  491.         return;
  492.  
  493. #ifdef _UNICODE
  494.     DXUtil_ConvertWideStringToAnsi( strDestination, tstrSource, cchDestChar );
  495. #else
  496.     if( cchDestChar == -1 )
  497.         strcpy( strDestination, tstrSource );
  498.     else
  499.         strncpy( strDestination, tstrSource, cchDestChar );
  500. #endif
  501. }
  502.  
  503.  
  504.  
  505.  
  506. //-----------------------------------------------------------------------------
  507. // Name: DXUtil_ConvertGenericStringToWide()
  508. // Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
  509. //       WCHAR string. cchDestChar defaults -1 which means it 
  510. //       assumes strDest is large enough to store strSource
  511. //-----------------------------------------------------------------------------
  512. VOID DXUtil_ConvertGenericStringToWide( WCHAR* wstrDestination, const TCHAR* tstrSource, 
  513.                                         int cchDestChar )
  514. {
  515.     if( wstrDestination==NULL || tstrSource==NULL )
  516.         return;
  517.  
  518. #ifdef _UNICODE
  519.     if( cchDestChar == -1 )
  520.         wcscpy( wstrDestination, tstrSource );
  521.     else
  522.         wcsncpy( wstrDestination, tstrSource, cchDestChar );
  523. #else
  524.     DXUtil_ConvertAnsiStringToWide( wstrDestination, tstrSource, cchDestChar );
  525. #endif
  526. }
  527.  
  528.  
  529.  
  530.  
  531. //-----------------------------------------------------------------------------
  532. // Name: DXUtil_ConvertAnsiStringToGeneric()
  533. // Desc: This is a UNICODE conversion utility to convert a CHAR string into a
  534. //       TCHAR string. cchDestChar defaults -1 which means it 
  535. //       assumes strDest is large enough to store strSource
  536. //-----------------------------------------------------------------------------
  537. VOID DXUtil_ConvertAnsiStringToGeneric( TCHAR* tstrDestination, const CHAR* strSource, 
  538.                                         int cchDestChar )
  539. {
  540.     if( tstrDestination==NULL || strSource==NULL )
  541.         return;
  542.         
  543. #ifdef _UNICODE
  544.     DXUtil_ConvertAnsiStringToWide( tstrDestination, strSource, cchDestChar );
  545. #else
  546.     if( cchDestChar == -1 )
  547.         strcpy( tstrDestination, strSource );
  548.     else
  549.         strncpy( tstrDestination, strSource, cchDestChar );
  550. #endif
  551. }
  552.  
  553.  
  554.  
  555.  
  556. //-----------------------------------------------------------------------------
  557. // Name: DXUtil_ConvertAnsiStringToGeneric()
  558. // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
  559. //       TCHAR string. cchDestChar defaults -1 which means it 
  560. //       assumes strDest is large enough to store strSource
  561. //-----------------------------------------------------------------------------
  562. VOID DXUtil_ConvertWideStringToGeneric( TCHAR* tstrDestination, const WCHAR* wstrSource, 
  563.                                         int cchDestChar )
  564. {
  565.     if( tstrDestination==NULL || wstrSource==NULL )
  566.         return;
  567.  
  568. #ifdef _UNICODE
  569.     if( cchDestChar == -1 )
  570.         wcscpy( tstrDestination, wstrSource );
  571.     else
  572.         wcsncpy( tstrDestination, wstrSource, cchDestChar );
  573. #else
  574.     DXUtil_ConvertWideStringToAnsi( tstrDestination, wstrSource, cchDestChar );
  575. #endif
  576. }
  577.  
  578.  
  579.  
  580.  
  581. //-----------------------------------------------------------------------------
  582. // Name: _DbgOut()
  583. // Desc: Outputs a message to the debug stream
  584. //-----------------------------------------------------------------------------
  585. HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg )
  586. {
  587.     TCHAR buffer[256];
  588.     wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine );
  589.     OutputDebugString( buffer );
  590.     OutputDebugString( strMsg );
  591.  
  592.     if( hr )
  593.     {
  594.         wsprintf( buffer, _T("(hr=%08lx)\n"), hr );
  595.         OutputDebugString( buffer );
  596.     }
  597.  
  598.     OutputDebugString( _T("\n") );
  599.  
  600.     return hr;
  601. }
  602.  
  603.  
  604.  
  605.  
  606. //-----------------------------------------------------------------------------
  607. // Name: DXUtil_Trace()
  608. // Desc: Outputs to the debug stream a formatted string with a variable-
  609. //       argument list.
  610. //-----------------------------------------------------------------------------
  611. VOID DXUtil_Trace( TCHAR* strMsg, ... )
  612. {
  613. #if defined(DEBUG) | defined(_DEBUG)
  614.     TCHAR strBuffer[512];
  615.     
  616.     va_list args;
  617.     va_start(args, strMsg);
  618.     _vsntprintf( strBuffer, 512, strMsg, args );
  619.     va_end(args);
  620.  
  621.     OutputDebugString( strBuffer );
  622. #endif
  623. }
  624.  
  625.  
  626.  
  627.