Table of Contents

Target Platform(s):

include/AK/Tools/Win32/AkPlatformFuncs.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
00003 released in source code form as part of the SDK installer package.
00004 
00005 Commercial License Usage
00006 
00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
00008 may use this file in accordance with the end user license agreement provided 
00009 with the software or, alternatively, in accordance with the terms contained in a
00010 written agreement between you and Audiokinetic Inc.
00011 
00012 Apache License Usage
00013 
00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the 
00015 "Apache License"); you may not use this file except in compliance with the 
00016 Apache License. You may obtain a copy of the Apache License at 
00017 http://www.apache.org/licenses/LICENSE-2.0.
00018 
00019 Unless required by applicable law or agreed to in writing, software distributed
00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
00022 the specific language governing permissions and limitations under the License.
00023 
00024   Version: <VERSION>  Build: <BUILDNUMBER>
00025   Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc.
00026 *******************************************************************************/
00027 
00028 #ifndef _AK_PLATFORM_FUNCS_H_
00029 #define _AK_PLATFORM_FUNCS_H_
00030 
00031 #include "malloc.h"
00032 #include <AK/Tools/Common/AkAssert.h>
00033 #include <AK/SoundEngine/Common/AkTypes.h>
00034 #include <windows.h>
00035 //#define AK_ENABLE_PERF_RECORDING
00036 #if defined(AK_ENABLE_PERF_RECORDING)
00037 #include <stdio.h>
00038 #endif
00039 
00040 #if defined(_WIN64)
00041 // on 64 bit, removes warning C4985: 'ceil': attributes not present on previous declaration.
00042 // see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=294649
00043 #include <math.h>
00044 #endif // _WIN64
00045 #include <intrin.h>
00046 
00047 //-----------------------------------------------------------------------------
00048 // Platform-specific thread properties definition.
00049 //-----------------------------------------------------------------------------
00050 struct AkThreadProperties
00051 {
00052     int                 nPriority;      ///< Thread priority
00053 #ifdef AK_WIN_UNIVERSAL_APP
00054     PROCESSOR_NUMBER    processorNumber;///< Ideal processor (passed to SetThreadIdealProcessorEx)
00055 #else
00056     AkUInt32            dwAffinityMask; ///< Affinity mask
00057 #endif
00058     AkUInt32            uStackSize;     ///< Thread stack size.
00059 };
00060 
00061 //-----------------------------------------------------------------------------
00062 // External variables.
00063 //-----------------------------------------------------------------------------
00064 // g_fFreqRatio is used by time helpers to return time values in milliseconds.
00065 // It is declared and updated by the sound engine.
00066 namespace AK
00067 {
00068     extern AkReal32 g_fFreqRatio;
00069 }
00070 
00071 //-----------------------------------------------------------------------------
00072 // Defines for Win32.
00073 //-----------------------------------------------------------------------------
00074 #define AK_DECLARE_THREAD_ROUTINE( FuncName )   DWORD WINAPI FuncName(LPVOID lpParameter)
00075 #define AK_THREAD_RETURN( _param_ )             return (_param_);
00076 #define AK_THREAD_ROUTINE_PARAMETER             lpParameter
00077 #define AK_GET_THREAD_ROUTINE_PARAMETER_PTR(type) reinterpret_cast<type*>( AK_THREAD_ROUTINE_PARAMETER )
00078 #define AK_RETURN_THREAD_OK                     0x00000000
00079 #define AK_RETURN_THREAD_ERROR                  0x00000001
00080 #define AK_DEFAULT_STACK_SIZE                   (128*1024)
00081 #define AK_THREAD_PRIORITY_NORMAL               THREAD_PRIORITY_NORMAL
00082 #define AK_THREAD_PRIORITY_ABOVE_NORMAL         THREAD_PRIORITY_ABOVE_NORMAL
00083 #define AK_THREAD_PRIORITY_TIME_CRITICAL        THREAD_PRIORITY_TIME_CRITICAL
00084 #define AK_THREAD_MODE_BACKGROUND_BEGIN         THREAD_MODE_BACKGROUND_BEGIN
00085 
00086 // NULL objects
00087 #define AK_NULL_THREAD                          NULL
00088 
00089 #define AK_INFINITE                             INFINITE
00090 
00091 #define AkMax(x1, x2)   (((x1) > (x2))? (x1): (x2))
00092 #define AkMin(x1, x2)   (((x1) < (x2))? (x1): (x2))
00093 #define AkClamp(x, min, max)  ((x) < (min)) ? (min) : (((x) > (max) ? (max) : (x)))
00094 
00095 namespace AKPLATFORM
00096 {
00097     // Simple automatic event API
00098     // ------------------------------------------------------------------
00099     
00100     /// Platform Independent Helper
00101     inline void AkClearEvent( AkEvent & out_event )
00102     {
00103         out_event = NULL;
00104     }
00105 
00106     /// Platform Independent Helper
00107     inline AKRESULT AkCreateEvent( AkEvent & out_event )
00108     {
00109 #ifdef AK_USE_UWP_API
00110         out_event = CreateEventEx(nullptr, nullptr, 0, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE);
00111 #else
00112         out_event = ::CreateEvent( NULL,                    // No security attributes
00113                                     false,                  // Reset type: automatic
00114                                     false,                  // Initial signaled state: not signaled
00115                                     NULL                    // No name
00116                                    );
00117 #endif
00118         return ( out_event ) ? AK_Success : AK_Fail;
00119     }
00120 
00121     /// Platform Independent Helper
00122     inline void AkDestroyEvent( AkEvent & io_event )
00123     {
00124         if ( io_event )
00125             ::CloseHandle( io_event );
00126         io_event = NULL;
00127     }
00128 
00129     /// Platform Independent Helper
00130     inline void AkWaitForEvent( AkEvent & in_event )
00131     {
00132 #ifdef AK_USE_UWP_API
00133 #ifdef AK_ENABLE_ASSERTS
00134         DWORD dwWaitResult = 
00135 #endif // AK_ENABLE_ASSERTS
00136             ::WaitForSingleObjectEx( in_event, INFINITE, FALSE );
00137         AKASSERT( dwWaitResult == WAIT_OBJECT_0 );
00138 #else
00139         AKVERIFY( ::WaitForSingleObject( in_event, INFINITE ) == WAIT_OBJECT_0 );
00140 #endif
00141     }
00142 
00143     /// Platform Independent Helper
00144     inline void AkSignalEvent( const AkEvent & in_event )
00145     {
00146         AKVERIFY( ::SetEvent( in_event ) );
00147     }
00148 
00149     
00150     // Atomic Operations
00151     // ------------------------------------------------------------------
00152 
00153     /// Platform Independent Helper
00154     inline AkInt32 AkInterlockedIncrement(AkAtomic32 * pValue)
00155     {
00156         return InterlockedIncrement( pValue );
00157     }
00158 
00159     /// Platform Independent Helper
00160     inline AkInt32 AkInterlockedDecrement(AkAtomic32 * pValue)
00161     {
00162         return InterlockedDecrement( pValue );
00163     }
00164 
00165 #if defined AK_POINTER_64
00166     inline bool AkInterlockedCompareExchange( volatile AkAtomic64* io_pDest, AkInt64 in_newValue, AkInt64 in_expectedOldVal )
00167     {
00168         return _InterlockedCompareExchange64(io_pDest, in_newValue, in_expectedOldVal) == in_expectedOldVal;
00169     }
00170 #endif
00171 
00172     inline bool AkInterlockedCompareExchange(volatile AkAtomic32* io_pDest, AkInt32 in_newValue, AkInt32 in_expectedOldVal)
00173     {
00174         return InterlockedCompareExchange(io_pDest, in_newValue, in_expectedOldVal) == in_expectedOldVal;
00175     }
00176 
00177 #if !defined AK_POINTER_64
00178     inline bool AkInterlockedCompareExchange(volatile AkAtomicPtr* io_pDest, AkIntPtr in_newValue, AkIntPtr in_expectedOldVal)
00179     {
00180         return InterlockedCompareExchange((volatile LONG_PTR*)io_pDest, (LONG_PTR)in_newValue, (LONG_PTR)in_expectedOldVal) == in_expectedOldVal;
00181     }
00182 #endif      
00183 
00184     //Ensure that all write operations are complete.  Necessary only on platforms that don't garentee the order of writes.
00185     inline void AkMemoryBarrier() 
00186     {
00187         _ReadWriteBarrier();
00188     }
00189 
00190     // Threads
00191     // ------------------------------------------------------------------
00192 
00193     /// Platform Independent Helper
00194     inline bool AkIsValidThread( AkThread * in_pThread )
00195     {
00196         return (*in_pThread != AK_NULL_THREAD);
00197     }
00198 
00199     /// Platform Independent Helper
00200     inline void AkClearThread( AkThread * in_pThread )
00201     {
00202         *in_pThread = AK_NULL_THREAD;
00203     }
00204 
00205     /// Platform Independent Helper
00206     inline void AkCloseThread( AkThread * in_pThread )
00207     {
00208         AKASSERT( in_pThread );
00209         AKASSERT( *in_pThread );
00210         AKVERIFY( ::CloseHandle( *in_pThread ) );
00211         AkClearThread( in_pThread );
00212     }
00213 
00214 #define AkExitThread( _result ) return _result;
00215 
00216     /// Platform Independent Helper
00217     inline void AkGetDefaultThreadProperties( AkThreadProperties & out_threadProperties )
00218     {
00219         out_threadProperties.nPriority = AK_THREAD_PRIORITY_NORMAL;
00220         out_threadProperties.uStackSize= AK_DEFAULT_STACK_SIZE;
00221 #ifdef AK_WIN_UNIVERSAL_APP
00222         out_threadProperties.processorNumber.Group = 0;
00223         out_threadProperties.processorNumber.Number = MAXIMUM_PROCESSORS;
00224         out_threadProperties.processorNumber.Reserved = 0;
00225 #else
00226         out_threadProperties.dwAffinityMask = 0;
00227 #endif
00228     }
00229 
00230     /// Set the name of a thread: see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
00231     inline void AkSetThreadName( DWORD in_dwThreadID, LPCSTR in_szThreadName )
00232     {
00233         const DWORD MS_VC_EXCEPTION=0x406D1388;
00234 
00235 #pragma pack(push,8)
00236         typedef struct tagTHREADNAME_INFO
00237         {
00238             DWORD dwType;
00239             LPCSTR szName;
00240             DWORD dwThreadID;
00241             DWORD dwFlags;
00242         } THREADNAME_INFO;
00243 #pragma pack(pop)
00244 
00245         THREADNAME_INFO info;
00246         info.dwType = 0x1000;
00247         info.szName = in_szThreadName;
00248         info.dwThreadID = in_dwThreadID;
00249         info.dwFlags = 0;
00250 
00251         __try
00252         {
00253             RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
00254         }
00255 #pragma warning(suppress: 6312 6322)
00256         __except(EXCEPTION_CONTINUE_EXECUTION)
00257         {
00258         }
00259     }
00260 
00261     /// Platform Independent Helper
00262     inline void AkCreateThread( 
00263         AkThreadRoutine pStartRoutine,                  // Thread routine.
00264         void * pParams,                                 // Routine params.
00265         const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
00266         AkThread * out_pThread,                         // Returned thread handle.
00267         const char * in_szThreadName )                      // Opt thread name.
00268     {
00269         AKASSERT( out_pThread != NULL );
00270         AKASSERT( (in_threadProperties.nPriority >= THREAD_PRIORITY_LOWEST && in_threadProperties.nPriority <= THREAD_PRIORITY_HIGHEST)
00271             || ( in_threadProperties.nPriority == THREAD_PRIORITY_TIME_CRITICAL )
00272             || ( in_threadProperties.nPriority == THREAD_MODE_BACKGROUND_BEGIN ) );
00273 
00274         DWORD dwThreadID;
00275         *out_pThread = ::CreateThread( NULL,                            // No security attributes
00276                                        in_threadProperties.uStackSize,  // StackSize (0 uses system default)
00277                                        pStartRoutine,                   // Thread start routine
00278                                        pParams,                         // Thread function parameter
00279                                        0,                               // Creation flags: create running
00280                                        &dwThreadID );
00281 
00282         // ::CreateThread() return NULL if it fails.
00283         if ( !*out_pThread )
00284         {
00285             AkClearThread( out_pThread );
00286             return;
00287         }
00288 
00289         // Set thread name.
00290         AkSetThreadName( dwThreadID, in_szThreadName );
00291 
00292         // Set properties.
00293         if ( !::SetThreadPriority( *out_pThread, in_threadProperties.nPriority ) &&
00294              in_threadProperties.nPriority != THREAD_MODE_BACKGROUND_BEGIN )
00295         {
00296             AKASSERT( !"Failed setting thread priority" );
00297             AkCloseThread( out_pThread );
00298             return;
00299         }
00300 #ifdef AK_WIN_UNIVERSAL_APP
00301         if ( in_threadProperties.processorNumber.Number != MAXIMUM_PROCESSORS)
00302         {
00303             if ( !SetThreadIdealProcessorEx( *out_pThread, const_cast<PPROCESSOR_NUMBER>(&in_threadProperties.processorNumber), NULL) )
00304             {
00305                 AKASSERT( !"Failed setting thread ideal processor" );
00306                 AkCloseThread( out_pThread );
00307             }
00308         }
00309 #else
00310         if (in_threadProperties.dwAffinityMask)
00311         {
00312             if (!::SetThreadAffinityMask(*out_pThread, in_threadProperties.dwAffinityMask))
00313             {
00314                 AKASSERT(!"Failed setting thread affinity mask");
00315                 AkCloseThread(out_pThread);
00316             }
00317         }
00318 #endif
00319     }
00320 
00321     /// Platform Independent Helper
00322     inline void AkWaitForSingleThread( AkThread * in_pThread )
00323     {
00324         AKASSERT( in_pThread );
00325         AKASSERT( *in_pThread );
00326 #ifdef AK_USE_UWP_API
00327         ::WaitForSingleObjectEx( *in_pThread, INFINITE, FALSE );
00328 #else
00329         ::WaitForSingleObject( *in_pThread, INFINITE );
00330 #endif
00331     }
00332 
00333     /// Returns the calling thread's ID.
00334     inline AkThreadID CurrentThread()
00335     {
00336         return ::GetCurrentThreadId();
00337     }
00338 
00339     /// Platform Independent Helper
00340     inline void AkSleep( AkUInt32 in_ulMilliseconds )
00341     {
00342         ::Sleep( in_ulMilliseconds );
00343     }
00344 
00345     // Optimized memory functions
00346     // --------------------------------------------------------------------
00347 
00348     /// Platform Independent Helper
00349     inline void AkMemCpy( void * pDest, const void * pSrc, AkUInt32 uSize )
00350     {
00351         memcpy( pDest, pSrc, uSize );
00352     }
00353 
00354     /// Platform Independent Helper
00355     inline void AkMemSet( void * pDest, AkInt32 iVal, AkUInt32 uSize )
00356     {
00357         memset( pDest, iVal, uSize );
00358     }
00359 
00360     // Time functions
00361     // ------------------------------------------------------------------
00362 
00363     /// Platform Independent Helper
00364     inline void PerformanceCounter( AkInt64 * out_piLastTime )
00365     {
00366         ::QueryPerformanceCounter( (LARGE_INTEGER*)out_piLastTime );
00367     }
00368 
00369     /// Platform Independent Helper
00370     inline void PerformanceFrequency( AkInt64 * out_piFreq )
00371     {
00372         ::QueryPerformanceFrequency( (LARGE_INTEGER*)out_piFreq );
00373     }
00374 
00375     /// Platform Independent Helper
00376     inline void UpdatePerformanceFrequency()
00377     {
00378         AkInt64 iFreq;
00379         PerformanceFrequency( &iFreq );
00380         AK::g_fFreqRatio = (AkReal32)((AkReal64)iFreq / 1000);
00381     }
00382 
00383     /// Returns a time range in milliseconds, using the sound engine's updated count->milliseconds ratio.
00384     inline AkReal32 Elapsed( const AkInt64 & in_iNow, const AkInt64 & in_iStart )
00385     {
00386         return ( in_iNow - in_iStart ) / AK::g_fFreqRatio;
00387     }
00388 
00389     /// String conversion helper. If io_pszAnsiString is null, the function returns the required size.
00390     inline AkInt32 AkWideCharToChar( const wchar_t* in_pszUnicodeString,
00391                                      AkUInt32   in_uiOutBufferSize,
00392                                      char*  io_pszAnsiString )
00393     {
00394         if(!io_pszAnsiString)
00395             return WideCharToMultiByte(CP_UTF8, 0, in_pszUnicodeString, -1, NULL, 0, NULL, NULL);
00396 
00397         int iWritten = ::WideCharToMultiByte(CP_UTF8,                                                                   // code page
00398                                     0,                                                                      // performance and mapping flags
00399                                     in_pszUnicodeString,                                                    // wide-character string
00400                                     (int)AkMin( ( (AkUInt32)wcslen( in_pszUnicodeString )), in_uiOutBufferSize-1 ), // number of chars in string : -1 = NULL terminated string.
00401                                     io_pszAnsiString,                                                       // buffer for new string
00402                                     in_uiOutBufferSize,                                                     // size of buffer
00403                                     NULL,                                                                   // default for unmappable chars
00404                                     NULL);                                                                  // set when default char used
00405         io_pszAnsiString[iWritten] = 0;
00406         return iWritten;
00407     }
00408 
00409     /// String conversion helper
00410     inline AkInt32 AkCharToWideChar( const char*    in_pszAnsiString,
00411                                      AkUInt32       in_uiOutBufferSize,
00412                                      void*          io_pvUnicodeStringBuffer )
00413     {
00414         return ::MultiByteToWideChar(   CP_UTF8,                            // code page
00415                                         0,                                  // performance and mapping flags
00416                                         in_pszAnsiString,                   // wide-character string
00417                                         -1,                                 // number of chars in string : -1 = NULL terminated string.
00418                                         (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
00419                                         in_uiOutBufferSize);                // size of buffer
00420     }
00421 
00422     /// String conversion helper
00423     inline AkInt32 AkUtf8ToWideChar( const char*    in_pszUtf8String,
00424                                      AkUInt32       in_uiOutBufferSize,
00425                                      void*          io_pvUnicodeStringBuffer )
00426     {
00427         return ::MultiByteToWideChar(   CP_UTF8,                            // code page
00428                                         0,                                  // performance and mapping flags
00429                                         in_pszUtf8String,                   // wide-character string
00430                                         -1,                                 // number of chars in string : -1 = NULL terminated string.
00431                                         (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
00432                                         in_uiOutBufferSize);                // size of buffer
00433     }
00434 
00435     /// Safe unicode string copy.
00436     inline void SafeStrCpy( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
00437     {
00438         size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, wcslen( in_pSrc ) + 1 );
00439         wcsncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
00440         in_pDest[iSizeCopy] = '\0';
00441     }
00442 
00443     /// Safe string copy.
00444     inline void SafeStrCpy( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
00445     {
00446         size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, strlen( in_pSrc ) + 1 );
00447         strncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
00448         in_pDest[iSizeCopy] = '\0';
00449     }
00450 
00451     /// Safe unicode string concatenation.
00452     inline void SafeStrCat( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
00453     {
00454         int iAvailableSize = (int)( in_uDestMaxNumChars - wcslen( in_pDest ) - 1 );
00455         wcsncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)wcslen( in_pSrc ) ) );
00456     }
00457 
00458     /// Safe string concatenation.
00459     inline void SafeStrCat( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
00460     {
00461         int iAvailableSize = (int)( in_uDestMaxNumChars - strlen( in_pDest ) - 1 );
00462         strncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)strlen( in_pSrc ) ) );
00463     }
00464 
00465     /// Stack allocations.
00466     #define AkAlloca( _size_ ) _alloca( _size_ )
00467 
00468     /// Output a debug message on the console
00469 #if ! ( defined(AK_USE_UWP_API) || defined(AK_OPTIMIZED) )
00470     inline void OutputDebugMsg( const wchar_t* in_pszMsg )
00471     {
00472         OutputDebugStringW( in_pszMsg );
00473     }
00474 
00475     /// Output a debug message on the console
00476     inline void OutputDebugMsg( const char* in_pszMsg )
00477     {
00478         OutputDebugStringA( in_pszMsg );
00479     }
00480 #else
00481     inline void OutputDebugMsg( const wchar_t* ){}
00482     inline void OutputDebugMsg( const char* ){}
00483 #endif
00484 
00485     /// Converts a wchar_t string to an AkOSChar string.
00486     /// \remark On some platforms the AkOSChar string simply points to the same string,
00487     /// on others a new buffer is allocated on the stack using AkAlloca. This means
00488     /// you must make sure that:
00489     /// - The source string stays valid and unmodified for as long as you need the
00490     ///   AkOSChar string (for cases where they point to the same string)
00491     /// - The AkOSChar string is used within this scope only -- for example, do NOT
00492     ///   return that string from a function (for cases where it is allocated on the stack)
00493     #define CONVERT_WIDE_TO_OSCHAR( _wstring_, _oscharstring_ ) ( _oscharstring_ ) = (AkOSChar*)( _wstring_ )
00494 
00495     /// Converts a char string to an AkOSChar string.
00496     /// \remark On some platforms the AkOSChar string simply points to the same string,
00497     /// on others a new buffer is allocated on the stack using AkAlloca. This means
00498     /// you must make sure that:
00499     /// - The source string stays valid and unmodified for as long as you need the
00500     ///   AkOSChar string (for cases where they point to the same string)
00501     /// - The AkOSChar string is used within this scope only -- for example, do NOT
00502     ///   return that string from a function (for cases where it is allocated on the stack)
00503     #define CONVERT_CHAR_TO_OSCHAR( _astring_, _oscharstring_ ) \
00504            _oscharstring_ = (AkOSChar*)AkAlloca( (1 + strlen( _astring_ )) * sizeof(AkOSChar)); \
00505            AKPLATFORM::AkCharToWideChar( _astring_, (AkUInt32)(1 + strlen(_astring_ )), (AkOSChar*)( _oscharstring_ ) )
00506 
00507     /// Converts a AkOSChar string into wide char string.
00508     /// \remark On some platforms the AkOSChar string simply points to the same string,
00509     /// on others a new buffer is allocated on the stack using AkAlloca. This means
00510     /// you must make sure that:
00511     /// - The source string stays valid and unmodified for as long as you need the
00512     ///   AkOSChar string (for cases where they point to the same string)
00513     /// - The AkOSChar string is used within this scope only -- for example, do NOT
00514     ///   return that string from a function (for cases where it is allocated on the stack)
00515     #define CONVERT_OSCHAR_TO_WIDE( _osstring_, _wstring_ ) _wstring_ = _osstring_
00516 
00517     /// Converts a AkOSChar string into char string.
00518     /// \remark On some platforms the AkOSChar string simply points to the same string,
00519     /// on others a new buffer is allocated on the stack using AkAlloca. This means
00520     /// you must make sure that:
00521     /// - The source string stays valid and unmodified for as long as you need the
00522     ///   AkOSChar string (for cases where they point to the same string)
00523     /// - The AkOSChar string is used within this scope only -- for example, do NOT
00524     ///   return that string from a function (for cases where it is allocated on the stack)
00525     #define CONVERT_OSCHAR_TO_CHAR( _osstring_, _astring_ ) \
00526             _astring_ = (char*)AkAlloca( 1 + wcslen( _osstring_ )); \
00527             AKPLATFORM::AkWideCharToChar( _osstring_, AkUInt32(1 + wcslen( _osstring_ )), _astring_ );
00528 
00529     /// Get the length, in characters, of a NULL-terminated AkUtf16 string
00530     /// \return The length, in characters, of the specified string (excluding terminating NULL)
00531     inline size_t AkUtf16StrLen( const AkUtf16* in_pStr )
00532     {
00533         return ( wcslen( in_pStr ) );
00534     }
00535 
00536     /// Get the length, in characters, of a NULL-terminated AkOSChar string
00537     /// \return The length, in characters, of the specified string (excluding terminating NULL)
00538     inline size_t OsStrLen( const AkOSChar* in_pszString )
00539     {
00540         return ( wcslen( in_pszString ) );
00541     }
00542 
00543     /// AkOSChar version of sprintf().
00544     #define AK_OSPRINTF swprintf_s
00545 
00546     /// Compare two NULL-terminated AkOSChar strings
00547     /// \return
00548     /// - < 0 if in_pszString1 < in_pszString2
00549     /// -    0 if the two strings are identical
00550     /// - > 0 if in_pszString1 > in_pszString2
00551     /// \remark The comparison is case-sensitive
00552     inline int OsStrCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2 )
00553     {
00554         return ( wcscmp( in_pszString1,  in_pszString2 ) );
00555     }
00556 
00557     /// Compare two NULL-terminated AkOSChar strings up to the specified count of characters.
00558     /// \return
00559     /// - < 0 if in_pszString1 < in_pszString2
00560     /// -    0 if the two strings are identical
00561     /// - > 0 if in_pszString1 > in_pszString2
00562     /// \remark The comparison is case-sensitive
00563     inline int OsStrNCmp(  const AkOSChar* in_pszString1, const AkOSChar* in_pszString2, size_t in_MaxCountSize)
00564     {
00565         return wcsncmp(in_pszString1, in_pszString2, in_MaxCountSize);
00566     }
00567     
00568     #define AK_UTF16_TO_WCHAR(  in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00569     #define AK_WCHAR_TO_UTF16(  in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00570     #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00571     #define AK_UTF16_TO_CHAR(   in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
00572     #define AK_CHAR_TO_UTF16(   in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
00573     #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00574 
00575     // Use with AkOSChar.
00576     #define AK_PATH_SEPARATOR   (L"\\")
00577 
00578     #if defined(AK_ENABLE_PERF_RECORDING)
00579     
00580         static AkUInt32 g_uAkPerfRecExecCount = 0;  
00581         static AkReal32 g_fAkPerfRecExecTime = 0.f;
00582 
00583         #define AK_PERF_RECORDING_RESET()   \
00584             AKPLATFORM::g_uAkPerfRecExecCount = 0;\
00585             AKPLATFORM::g_fAkPerfRecExecTime = 0.f;
00586 
00587         #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )                       \
00588             AkInt64 iAkPerfRecTimeBefore;                                                                                           \
00589             if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) )    \
00590                 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeBefore );
00591 
00592         #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )                        \
00593         if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) )    \
00594             {                                                                                                                       \
00595                 AkInt64 iAkPerfRecTimeAfter;                                                                                        \
00596                 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeAfter );                                                             \
00597                 AKPLATFORM::g_fAkPerfRecExecTime += AKPLATFORM::Elapsed( iAkPerfRecTimeAfter, iAkPerfRecTimeBefore );                           \
00598                 if ( AKPLATFORM::g_uAkPerfRecExecCount == (__uExecutionCountStop__) )                                                           \
00599                 {                                                                                                                   \
00600                     AkReal32 fAverageExecutionTime = AKPLATFORM::g_fAkPerfRecExecTime/((__uExecutionCountStop__)-(__uExecutionCountStart__));   \
00601                     char str[256];                                                                                                  \
00602                     sprintf_s(str, 256, "%s average execution time: %f\n", __StorageName__, fAverageExecutionTime);                 \
00603                     AKPLATFORM::OutputDebugMsg( str );                                                                              \
00604                 }                                                                                                                   \
00605             }                                                                                                                       \
00606             AKPLATFORM::g_uAkPerfRecExecCount++;
00607     #endif // AK_ENABLE_PERF_RECORDING
00608 }
00609 
00610 #ifdef AK_ENABLE_INSTRUMENT
00611     #ifdef AK_XBOXONE
00612         #include <AK/Tools/XBoxOne/AkInstrument.h>
00613     #endif
00614 #endif
00615 
00616 #endif  // _AK_PLATFORM_FUNCS_H_