637 lines
20 KiB
C++
637 lines
20 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: DXUtil.cpp
|
|
//
|
|
// Desc: Shortcut macros and functions for using DX objects
|
|
//
|
|
//@@BEGIN_MSINTERNAL
|
|
//
|
|
// Hist: 11.16.98 - mwetzel - New for DirectX 7
|
|
// 12.10.98 - mwetzel - Changes to InitLight and axed InitViewport
|
|
// 04.12.99 - mwetzelf - Changed some helper funcs
|
|
// 07.06.99 - mwetzel - Mods for UNICODE support
|
|
// 03.20.00 - mwetzel - Added timer support
|
|
//
|
|
//@@END_MSINTERNAL
|
|
//
|
|
// Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved
|
|
//-----------------------------------------------------------------------------
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "DXUtil.h"
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_GetDXSDKMediaPath()
|
|
// Desc: Returns the DirectX SDK media path
|
|
//-----------------------------------------------------------------------------
|
|
const TCHAR* DXUtil_GetDXSDKMediaPath()
|
|
{
|
|
static TCHAR strNull[2] = _T("");
|
|
static TCHAR strPath[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD dwSize = MAX_PATH;
|
|
HKEY hKey;
|
|
|
|
// Open the appropriate registry key
|
|
LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
_T("Software\\Microsoft\\DirectX"),
|
|
0, KEY_READ, &hKey );
|
|
if( ERROR_SUCCESS != lResult )
|
|
return strNull;
|
|
|
|
lResult = RegQueryValueEx( hKey, _T("DX8SDK Samples Path"), NULL,
|
|
&dwType, (BYTE*)strPath, &dwSize );
|
|
RegCloseKey( hKey );
|
|
|
|
if( ERROR_SUCCESS != lResult )
|
|
return strNull;
|
|
|
|
_tcscat( strPath, _T("\\Media\\") );
|
|
|
|
return strPath;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_FindMediaFile()
|
|
// Desc: Returns a valid path to a DXSDK media file
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT DXUtil_FindMediaFile( TCHAR* strPath, TCHAR* strFilename )
|
|
{
|
|
HANDLE file;
|
|
|
|
if( NULL==strFilename || NULL==strPath )
|
|
return E_INVALIDARG;
|
|
|
|
// Check if the file exists in the current directory
|
|
_tcscpy( strPath, strFilename );
|
|
|
|
file = CreateFile( strPath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, 0, NULL );
|
|
if( INVALID_HANDLE_VALUE != file )
|
|
{
|
|
CloseHandle( file );
|
|
return S_OK;
|
|
}
|
|
|
|
// Check if the file exists in the current directory
|
|
_stprintf( strPath, _T("%s%s"), DXUtil_GetDXSDKMediaPath(), strFilename );
|
|
|
|
file = CreateFile( strPath, 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
|
|
_tcscpy( strPath, strFilename );
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ReadStringRegKey()
|
|
// Desc: Helper function to read a registry key string
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT DXUtil_ReadStringRegKey( HKEY hKey, TCHAR* strRegName, TCHAR* strValue,
|
|
DWORD dwLength, TCHAR* strDefault )
|
|
{
|
|
DWORD dwType;
|
|
|
|
if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType,
|
|
(BYTE*)strValue, &dwLength ) )
|
|
{
|
|
_tcscpy( strValue, strDefault );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_WriteStringRegKey()
|
|
// Desc: Helper function to write a registry key string
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT DXUtil_WriteStringRegKey( HKEY hKey, TCHAR* strRegName,
|
|
TCHAR* strValue )
|
|
{
|
|
if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_SZ,
|
|
(BYTE*)strValue,
|
|
(_tcslen(strValue)+1)*sizeof(TCHAR) ) )
|
|
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* pdwValue,
|
|
DWORD dwDefault )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwLength = sizeof(DWORD);
|
|
|
|
if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType,
|
|
(BYTE*)pdwValue, &dwLength ) )
|
|
{
|
|
*pdwValue = dwDefault;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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* pbValue,
|
|
BOOL bDefault )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwLength = sizeof(BOOL);
|
|
|
|
if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType,
|
|
(BYTE*)pbValue, &dwLength ) )
|
|
{
|
|
*pbValue = bDefault;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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* pGuidValue,
|
|
GUID& guidDefault )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwLength = sizeof(GUID);
|
|
|
|
if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType,
|
|
(LPBYTE) pGuidValue, &dwLength ) )
|
|
{
|
|
*pGuidValue = guidDefault;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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 = timeGetTime() * 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_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_ConvertAnsiStringToWide()
|
|
// Desc: This is a UNICODE conversion utility to convert a CHAR string into a
|
|
// WCHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertAnsiStringToWide( WCHAR* wstrDestination, const CHAR* strSource,
|
|
int cchDestChar )
|
|
{
|
|
if( wstrDestination==NULL || strSource==NULL )
|
|
return;
|
|
|
|
if( cchDestChar == -1 )
|
|
cchDestChar = strlen(strSource)+1;
|
|
|
|
MultiByteToWideChar( CP_ACP, 0, strSource, -1,
|
|
wstrDestination, cchDestChar-1 );
|
|
|
|
wstrDestination[cchDestChar-1] = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ConvertWideStringToAnsi()
|
|
// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
|
|
// CHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertWideStringToAnsi( CHAR* strDestination, const WCHAR* wstrSource,
|
|
int cchDestChar )
|
|
{
|
|
if( strDestination==NULL || wstrSource==NULL )
|
|
return;
|
|
|
|
if( cchDestChar == -1 )
|
|
cchDestChar = wcslen(wstrSource)+1;
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, wstrSource, -1, strDestination,
|
|
cchDestChar-1, NULL, NULL );
|
|
|
|
strDestination[cchDestChar-1] = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ConvertGenericStringToAnsi()
|
|
// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
|
|
// CHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertGenericStringToAnsi( CHAR* strDestination, const TCHAR* tstrSource,
|
|
int cchDestChar )
|
|
{
|
|
if( strDestination==NULL || tstrSource==NULL )
|
|
return;
|
|
|
|
#ifdef _UNICODE
|
|
DXUtil_ConvertWideStringToAnsi( strDestination, tstrSource, cchDestChar );
|
|
#else
|
|
if( cchDestChar == -1 )
|
|
strcpy( strDestination, tstrSource );
|
|
else
|
|
strncpy( strDestination, tstrSource, cchDestChar );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ConvertGenericStringToWide()
|
|
// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
|
|
// WCHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertGenericStringToWide( WCHAR* wstrDestination, const TCHAR* tstrSource,
|
|
int cchDestChar )
|
|
{
|
|
if( wstrDestination==NULL || tstrSource==NULL )
|
|
return;
|
|
|
|
#ifdef _UNICODE
|
|
if( cchDestChar == -1 )
|
|
wcscpy( wstrDestination, tstrSource );
|
|
else
|
|
wcsncpy( wstrDestination, tstrSource, cchDestChar );
|
|
#else
|
|
DXUtil_ConvertAnsiStringToWide( wstrDestination, tstrSource, cchDestChar );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ConvertAnsiStringToGeneric()
|
|
// Desc: This is a UNICODE conversion utility to convert a CHAR string into a
|
|
// TCHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertAnsiStringToGeneric( TCHAR* tstrDestination, const CHAR* strSource,
|
|
int cchDestChar )
|
|
{
|
|
if( tstrDestination==NULL || strSource==NULL )
|
|
return;
|
|
|
|
#ifdef _UNICODE
|
|
DXUtil_ConvertAnsiStringToWide( tstrDestination, strSource, cchDestChar );
|
|
#else
|
|
if( cchDestChar == -1 )
|
|
strcpy( tstrDestination, strSource );
|
|
else
|
|
strncpy( tstrDestination, strSource, cchDestChar );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXUtil_ConvertAnsiStringToGeneric()
|
|
// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
|
|
// TCHAR string. cchDestChar defaults -1 which means it
|
|
// assumes strDest is large enough to store strSource
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXUtil_ConvertWideStringToGeneric( TCHAR* tstrDestination, const WCHAR* wstrSource,
|
|
int cchDestChar )
|
|
{
|
|
if( tstrDestination==NULL || wstrSource==NULL )
|
|
return;
|
|
|
|
#ifdef _UNICODE
|
|
if( cchDestChar == -1 )
|
|
wcscpy( tstrDestination, wstrSource );
|
|
else
|
|
wcsncpy( tstrDestination, wstrSource, cchDestChar );
|
|
#else
|
|
DXUtil_ConvertWideStringToAnsi( tstrDestination, wstrSource, cchDestChar );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: _DbgOut()
|
|
// Desc: Outputs a message to the debug stream
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg )
|
|
{
|
|
TCHAR buffer[256];
|
|
wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine );
|
|
OutputDebugString( buffer );
|
|
OutputDebugString( strMsg );
|
|
|
|
if( hr )
|
|
{
|
|
wsprintf( buffer, _T("(hr=%08lx)\n"), hr );
|
|
OutputDebugString( buffer );
|
|
}
|
|
|
|
OutputDebugString( _T("\n") );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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 );
|
|
#endif
|
|
}
|
|
|
|
|
|
|