/*========================================================================== * * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved. * * File: OSInd.cpp * Content: OS indirection functions to abstract OS specific items. * * History: * Date By Reason * ==== == ====== * 07/12/99 jtk Created * 09/21/99 rodtoll Fixed for retail builds * 09/22/99 jtk Added callstacks to memory allocations * 08/28/2000 masonb Voice Merge: Allow new and delete with size of 0 * 11/28/2000 rodtoll WinBug #206257 - Retail DPNET.DLL links to DebugBreak() * 12/22/2000 aarono ManBug # 190380 use process heap for retail * 10/16/2001 vanceo Add AssertNoCriticalSectionsTakenByThisThread capability ***************************************************************************/ #include "dncmni.h" #define PROF_SECT _T("DirectPlay8") //********************************************************************** // Constant definitions //********************************************************************** //********************************************************************** // Macro definitions //********************************************************************** //********************************************************************** // Structure definitions //********************************************************************** //********************************************************************** // Variable definitions //********************************************************************** // // debug variable to make sure we're initialized before having any functions // called // DEBUG_ONLY( static BOOL g_fOSIndirectionLayerInitialized = FALSE ); // // OS items // #if ((! defined(WINCE)) && (! defined(_XBOX))) static OSVERSIONINFO g_OSVersionInfo; #endif // ! WINCE and ! _XBOX #ifndef DPNBUILD_NOSERIALSP static HINSTANCE g_hApplicationInstance; #endif // ! DPNBUILD_NOSERIALSP // // Global Pools // #if ((! defined(DPNBUILD_LIBINTERFACE)) && (! defined(DPNBUILD_NOCLASSFACTORY))) CFixedPool g_fpClassFactories; CFixedPool g_fpObjectDatas; CFixedPool g_fpInterfaceLists; #endif // ! DPNBUILD_LIBINTERFACE and ! DPNBUILD_NOCLASSFACTORY #ifdef WINNT PSECURITY_ATTRIBUTES g_psa = NULL; SECURITY_ATTRIBUTES g_sa; BYTE g_pSD[SECURITY_DESCRIPTOR_MIN_LENGTH]; BOOL g_fDaclInited = FALSE; PACL g_pEveryoneACL = NULL; #endif // WINNT #ifndef DPNBUILD_LIBINTERFACE #define CLASSFAC_POOL_INITED 0x00000001 #define OBJDATA_POOL_INITED 0x00000002 #define INTLIST_POOL_INITED 0x00000004 #endif // ! DPNBUILD_LIBINTERFACE #ifdef DBG #define HANDLE_TRACKING_INITED 0x00000008 #endif // DBG #if ((defined(DBG)) || (defined(DPNBUILD_FIXEDMEMORYMODEL))) #define MEMORY_TRACKING_INITED 0x00000010 #endif // DBG or DPNBUILD_FIXEDMEMORYMODEL #if ((defined(DBG)) && (! defined(DPNBUILD_ONLYONETHREAD))) #define CRITSEC_TRACKING_INITED 0x00000020 #endif // DBG and ! DPNBUILD_ONLYONETHREAD #if !defined(DPNBUILD_LIBINTERFACE) || defined(DBG) || defined(DPNBUILD_FIXEDMEMORYMODEL) DWORD g_dwCommonInitFlags = 0; #endif // !defined(DPNBUILD_LIBINTERFACE) || defined(DBG) || defined(DPNBUILD_FIXEDMEMORYMODEL) //********************************************************************** // Function prototypes //********************************************************************** //********************************************************************** // Function definitions //********************************************************************** //********************************************************************** // ------------------------------ // DNOSIndirectionInit - initialize the OS indirection layer // // Entry: Nothing // // Exit: Boolean indicating success // TRUE = initialization successful // FALSE = initialization unsuccessful // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNOSIndirectionInit" BOOL DNOSIndirectionInit( DWORD_PTR dwpMaxMemUsage ) { BOOL fReturn; #ifdef DBG DNASSERT( g_fOSIndirectionLayerInitialized == FALSE ); #endif // DBG // // initialize // fReturn = TRUE; #if ((! defined(WINCE)) && (! defined(_XBOX))) // // note OS version // memset( &g_OSVersionInfo, 0x00, sizeof( g_OSVersionInfo ) ); g_OSVersionInfo.dwOSVersionInfoSize = sizeof( g_OSVersionInfo ); if ( GetVersionEx( &g_OSVersionInfo ) == FALSE ) { goto Failure; } #endif // ! WINCE and ! _XBOX #ifndef DPNBUILD_NOSERIALSP // // note application instance // g_hApplicationInstance = GetModuleHandle( NULL ); if ( g_hApplicationInstance == NULL ) { DWORD dwError; dwError = GetLastError(); DPFX(DPFPREP, 0, "Failed to GetModuleHandle: 0x%x", dwError ); goto Failure; } #endif // ! DPNBUILD_NOSERIALSP #if ((defined(DBG)) && (! defined(DPNBUILD_ONLYONETHREAD))) // // initialize critical section tracking code before anything else! // if ( DNCSTrackInitialize() == FALSE ) { DPFX(DPFPREP, 0, "Failed to initialize critsec tracking code!" ); DNASSERT( FALSE ); goto Failure; } g_dwCommonInitFlags |= CRITSEC_TRACKING_INITED; #endif // DBG and ! DPNBUILD_ONLYONETHREAD #if ((defined(DBG)) || (defined(DPNBUILD_FIXEDMEMORYMODEL))) // // initialize memory tracking before creating new memory heap // if ( DNMemoryTrackInitialize(dwpMaxMemUsage) == FALSE ) { DPFX(DPFPREP, 0, "Failed to initialize memory tracking code!" ); DNASSERT( FALSE ); goto Failure; } g_dwCommonInitFlags |= MEMORY_TRACKING_INITED; #endif // DBG or DPNBUILD_FIXEDMEMORYMODEL #ifdef DBG // // initialize handle tracking // if ( DNHandleTrackInitialize() == FALSE ) { DPFX(DPFPREP, 0, "Failed to initialize handle tracking code!" ); DNASSERT( FALSE ); goto Failure; } g_dwCommonInitFlags |= HANDLE_TRACKING_INITED; #endif // DBG #if ((! defined(DPNBUILD_LIBINTERFACE)) && (! defined(DPNBUILD_NOCLASSFACTORY))) // // Initialize global pools // if (!g_fpClassFactories.Initialize( sizeof( _IDirectPlayClassFactory ), NULL, NULL, NULL, NULL)) { DPFX(DPFPREP, 0, "Failed to initialize class factory pool!" ); goto Failure; } g_dwCommonInitFlags |= CLASSFAC_POOL_INITED; if (!g_fpObjectDatas.Initialize( sizeof( _OBJECT_DATA ), NULL, NULL, NULL, NULL)) { DPFX(DPFPREP, 0, "Failed to initialize object data pool!" ); goto Failure; } g_dwCommonInitFlags |= OBJDATA_POOL_INITED; if (!g_fpInterfaceLists.Initialize( sizeof( _INTERFACE_LIST ), NULL, NULL, NULL, NULL)) { DPFX(DPFPREP, 0, "Failed to initialize interface list pool!" ); goto Failure; } g_dwCommonInitFlags |= INTLIST_POOL_INITED; #endif // ! DPNBUILD_LIBINTERFACE and ! DPNBUILD_NOCLASSFACTORY srand(GETTIMESTAMP()); #if (((! defined(WINCE)) && (! defined(_XBOX))) || (! defined(DPNBUILD_NOSERIALSP)) || (defined(DBG)) || (defined(DPNBUILD_FIXEDMEMORYMODEL)) || ((! defined(DPNBUILD_LIBINTERFACE)) && (! defined(DPNBUILD_NOCLASSFACTORY))) ) Exit: #endif // (! WINCE and ! _XBOX) or ! DPNBUILD_NOSERIALSP or DBG or DPNBUILD_FIXEDMEMORYMODEL or (! DPNBUILD_LIBINTERFACE and ! DPNBUILD_NOCLASSFACTORY) if ( fReturn != FALSE ) { DEBUG_ONLY( g_fOSIndirectionLayerInitialized = TRUE ); } return fReturn; #if (((! defined(WINCE)) && (! defined(_XBOX))) || (! defined(DPNBUILD_NOSERIALSP)) || (defined(DBG)) || (defined(DPNBUILD_FIXEDMEMORYMODEL)) || ((! defined(DPNBUILD_LIBINTERFACE)) && (! defined(DPNBUILD_NOCLASSFACTORY))) ) Failure: fReturn = FALSE; DNOSIndirectionDeinit(); goto Exit; #endif // (! WINCE and ! _XBOX) or ! DPNBUILD_NOSERIALSP or DBG or DPNBUILD_FIXEDMEMORYMODEL or (! DPNBUILD_LIBINTERFACE and ! DPNBUILD_NOCLASSFACTORY) } //********************************************************************** //********************************************************************** // ------------------------------ // DNOSIndirectionDeinit - deinitialize OS indirection layer // // Entry: Nothing // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNOSIndirectionDeinit" void DNOSIndirectionDeinit( void ) { #if ((! defined(DPNBUILD_LIBINTERFACE)) && (! defined(DPNBUILD_NOCLASSFACTORY))) // // DeInitialize global pools // if (g_dwCommonInitFlags & CLASSFAC_POOL_INITED) { g_fpClassFactories.DeInitialize(); } if (g_dwCommonInitFlags & OBJDATA_POOL_INITED) { g_fpObjectDatas.DeInitialize(); } if (g_dwCommonInitFlags & INTLIST_POOL_INITED) { g_fpInterfaceLists.DeInitialize(); } #endif // ! DPNBUILD_LIBINTERFACE and ! DPNBUILD_NOCLASSFACTORY #ifdef DBG if (g_dwCommonInitFlags & HANDLE_TRACKING_INITED) { if (DNHandleTrackDumpLeaks()) { // There were leaks, break so we can look at the log DNASSERT(0); } DNHandleTrackDeinitialize(); } #endif // DBG #if ((defined(DBG)) && (! defined(DPNBUILD_ONLYONETHREAD))) // // Display CritSec leaks before displaying memory leaks, because displaying memory leaks // may free the memory for the CritSec and corrupt the CritSec bilink // if (g_dwCommonInitFlags & CRITSEC_TRACKING_INITED) { if (DNCSTrackDumpLeaks()) { // There were leaks, break so we can look at the log DNASSERT(0); } DNCSTrackDeinitialize(); } #endif // DBG and ! DPNBUILD_ONLYONETHREAD #if ((defined(DBG)) || (defined(DPNBUILD_FIXEDMEMORYMODEL))) if (g_dwCommonInitFlags & MEMORY_TRACKING_INITED) { #ifdef DBG if (DNMemoryTrackDumpLeaks()) { // There were leaks, break so we can look at the log DNASSERT(0); } #endif // DBG DNMemoryTrackDeinitialize(); } #endif // DBG or DPNBUILD_FIXEDMEMORYMODEL #ifdef WINNT // This should be done after functions that use a Dacl will no longer be // called (CreateMutex, CreateFile, etc). if (g_pEveryoneACL) { HeapFree(GetProcessHeap(), 0, g_pEveryoneACL); g_pEveryoneACL = NULL; } #endif // WINNT DEBUG_ONLY( g_fOSIndirectionLayerInitialized = FALSE ); #if !defined(DPNBUILD_LIBINTERFACE) || defined(DBG) g_dwCommonInitFlags = 0; #endif // !defined(DPNBUILD_LIBINTERFACE) || defined(DBG) } //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNinet_ntow" void DNinet_ntow( IN_ADDR in, WCHAR* pwsz ) { // NOTE: pwsz should be 16 characters (4 3-digit numbers + 3 '.' + \0) swprintf(pwsz, L"%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno); } #undef DPF_MODNAME #define DPF_MODNAME "DNGetRandomNumber" DWORD DNGetRandomNumber() { return (rand() | (rand() << 16)); } #if ((! defined(WINCE)) && (! defined(_XBOX))) //********************************************************************** // ------------------------------ // DNGetOSType - get OS type // // Entry: Nothing // // Exit: OS type // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNGetOSType" UINT_PTR DNGetOSType( void ) { #ifdef DBG DNASSERT( g_fOSIndirectionLayerInitialized != FALSE ); #endif // DBG return g_OSVersionInfo.dwPlatformId; } #endif // ! WINCE and ! _XBOX #ifdef WINNT //********************************************************************** // ------------------------------ // DNOSIsXPOrGreater - return TRUE if OS is WindowsXP or later or NT flavor // // Entry: Nothing // // Exit: BOOL // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNOSIsXPOrGreater" BOOL DNOSIsXPOrGreater( void ) { #ifdef DBG DNASSERT( g_fOSIndirectionLayerInitialized != FALSE ); #endif // DBG return ((g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && ((g_OSVersionInfo.dwMajorVersion > 5) || ((g_OSVersionInfo.dwMajorVersion == 5) && (g_OSVersionInfo.dwMinorVersion >= 1))) ); } //********************************************************************** //********************************************************************** // ------------------------------ // DNGetNullDacl - get a SECURITY_ATTRIBUTE structure that specifies a // NULL DACL which is accesible by all users. // // Entry: Nothing // // Exit: PSECURITY_ATTRIBUTES // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNGetNullDacl" PSECURITY_ATTRIBUTES DNGetNullDacl() { PSID psidEveryone = NULL; SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; DWORD dwAclSize; // This is done to make this function independent of DNOSIndirectionInit so that the debug // layer can call it before the indirection layer is initialized. if (!g_fDaclInited) { if (!InitializeSecurityDescriptor((SECURITY_DESCRIPTOR*)g_pSD, SECURITY_DESCRIPTOR_REVISION)) { DPFX(DPFPREP, 0, "Failed to initialize security descriptor" ); goto Error; } // Create SID for the Everyone group. if (!AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone)) { DPFX(DPFPREP, 0, "Failed to allocate Everyone SID" ); goto Error; } dwAclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidEveryone) - sizeof(DWORD); // Allocate the ACL, this won't be a tracked allocation and we will let process cleanup destroy it g_pEveryoneACL = (PACL)HeapAlloc(GetProcessHeap(), 0, dwAclSize); if (g_pEveryoneACL == NULL) { DPFX(DPFPREP, 0, "Failed to allocate ACL buffer" ); goto Error; } // Intialize the ACL. if (!InitializeAcl(g_pEveryoneACL, dwAclSize, ACL_REVISION)) { DPFX(DPFPREP, 0, "Failed to initialize ACL" ); goto Error; } // Add the ACE. if (!AddAccessAllowedAce(g_pEveryoneACL, ACL_REVISION, GENERIC_ALL, psidEveryone)) { DPFX(DPFPREP, 0, "Failed to add ACE to ACL" ); goto Error; } // We no longer need the SID that was allocated. FreeSid(psidEveryone); psidEveryone = NULL; // Add the ACL to the security descriptor.. if (!SetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)g_pSD, TRUE, g_pEveryoneACL, FALSE)) { DPFX(DPFPREP, 0, "Failed to add ACL to security descriptor" ); goto Error; } g_sa.nLength = sizeof(SECURITY_ATTRIBUTES); g_sa.lpSecurityDescriptor = g_pSD; g_sa.bInheritHandle = FALSE; g_psa = &g_sa; g_fDaclInited = TRUE; } Error: if (psidEveryone) { FreeSid(psidEveryone); psidEveryone = NULL; } return g_psa; } //********************************************************************** #endif // WINNT #ifndef DPNBUILD_NOSERIALSP //********************************************************************** // ------------------------------ // DNGetApplicationInstance - application instance // // Entry: Nothing // // Exit: Application instance // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNGetApplicationInstance" HINSTANCE DNGetApplicationInstance( void ) { #ifdef DBG DNASSERT( g_fOSIndirectionLayerInitialized != FALSE ); #endif // DBG return g_hApplicationInstance; } //********************************************************************** #endif // ! DPNBUILD_NOSERIALSP #ifndef DPNBUILD_ONLYONETHREAD //********************************************************************** // ------------------------------ // DNOSInitializeCriticalSection - initialize a critical section // // Entry: Pointer to critical section // // Exit: Boolean indicating success // TRUE = success // FALSE = failue // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNOSInitializeCriticalSection" BOOL DNOSInitializeCriticalSection( CRITICAL_SECTION* pCriticalSection ) { BOOL fReturn; DNASSERT( pCriticalSection != NULL ); fReturn = TRUE; // // attempt to enter the critical section once // _try { #ifdef WINNT // Pre-allocate the critsec event by setting the high bit of the spin count and set spin to 1000 // NT converts the spin to 0 for single proc machines. fReturn = InitializeCriticalSectionAndSpinCount( pCriticalSection , 0x80000000 | 1000); #else InitializeCriticalSection( pCriticalSection ); #endif // WINNT } _except( EXCEPTION_EXECUTE_HANDLER ) { fReturn = FALSE; } _try { if (fReturn) { EnterCriticalSection( pCriticalSection ); } } _except( EXCEPTION_EXECUTE_HANDLER ) { DeleteCriticalSection(pCriticalSection); fReturn = FALSE; } // // if we didn't fail on entering the critical section, make sure // we release it // if ( fReturn != FALSE ) { LeaveCriticalSection( pCriticalSection ); } return fReturn; } //********************************************************************** #endif // !DPNBUILD_ONLYONETHREAD #ifdef DBG #if ((defined(WINCE)) || ((defined(_XBOX)) && (! defined(XBOX_ON_DESKTOP)))) #undef DPF_MODNAME #define DPF_MODNAME "DNGetProfileInt" UINT DNGetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) { DWORD dwResult; #ifndef _XBOX CRegistry reg; #endif // ! _XBOX DNASSERT(_tcscmp(lpszSection, _T("DirectPlay8")) == 0); #ifdef _XBOX #pragma TODO(vanceo, "Implement GetProfileInt functionality for Xbox") dwResult = nDefault; #else // ! _XBOX if (!reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\DirectPlay8"))) { // NOTE: This will occur during DllRegisterServer for the first time return nDefault; } if (!reg.ReadDWORD(lpszEntry, &dwResult)) { return nDefault; } #endif // ! _XBOX return dwResult; } #endif // WINCE or (_XBOX and ! XBOX_ON_DESKTOP) #endif // DBG #if defined(WINCE) && !defined(WINCE_ON_DESKTOP) //********************************************************************** //** //** Begin CE layer. Here we implement functions we need that aren't on CE. //** //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "OpenEvent" HANDLE WINAPI OpenEvent(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName) { HANDLE h; h = CreateEvent(0, 1, 0, lpName); if (!h) { return NULL; } if (GetLastError() != ERROR_ALREADY_EXISTS) { CloseHandle(h); return NULL; } return h; } #undef DPF_MODNAME #define DPF_MODNAME "OpenFileMapping" HANDLE WINAPI OpenFileMapping(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName) { HANDLE h; DWORD dwFlags = 0; if (dwDesiredAccess & FILE_MAP_WRITE) { // If they ask for FILE_MAP_ALL_ACCESS or FILE_MAP_WRITE, they get read and write dwFlags = PAGE_READWRITE; } else { // If they only ask for FILE_MAP_READ, they get read only dwFlags = PAGE_READONLY; } h = CreateFileMapping(INVALID_HANDLE_VALUE, 0, dwFlags, 0, 1, lpName); if (!h) { return NULL; } if (GetLastError() != ERROR_ALREADY_EXISTS) { CloseHandle(h); return NULL; } return h; } #undef DPF_MODNAME #define DPF_MODNAME "OpenMutex" HANDLE WINAPI OpenMutex(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName) { HANDLE h; h = CreateMutex(0, 0, lpName); if (!h) { return NULL; } if (GetLastError() != ERROR_ALREADY_EXISTS) { CloseHandle(h); return NULL; } return h; } /* #ifdef _X86_ __declspec(naked) LONG WINAPI InterlockedExchangeAdd( LPLONG Addend, LONG Increment ) { __asm { mov ecx, [esp + 4] ; get addend address mov eax, [esp + 8] ; get increment value lock xadd [ecx], eax ; exchange add} ret } } #endif // _X86 */ #endif // WINCE //********************************************************************** //** //** End CE layer. Here we implement functions we need that aren't on CE. //** //********************************************************************** #if ((defined(WINCE)) || (defined(DPNBUILD_LIBINTERFACE))) #undef DPF_MODNAME #define DPF_MODNAME "DNCoCreateGuid" HRESULT DNCoCreateGuid(GUID* pguid) { pguid->Data1 = (rand() << 16) | rand(); pguid->Data2 = (WORD)rand(); pguid->Data3 = (WORD)rand(); pguid->Data4[0] = (BYTE)rand(); pguid->Data4[1] = (BYTE)rand(); pguid->Data4[2] = (BYTE)rand(); pguid->Data4[3] = (BYTE)rand(); pguid->Data4[4] = (BYTE)rand(); pguid->Data4[5] = (BYTE)rand(); pguid->Data4[6] = (BYTE)rand(); pguid->Data4[7] = (BYTE)rand(); return S_OK; } #endif // WINCE or DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_NOPARAMVAL BOOL IsValidStringA( const CHAR * const lpsz ) { #ifndef WINCE return (!IsBadStringPtrA( lpsz, 0xFFFF ) ); #else const char* szTmpLoc = lpsz; // // If it is a NULL pointer just return FALSE, they are always bad // if (szTmpLoc == NULL) { return FALSE; } _try { for( ; *szTmpLoc ; szTmpLoc++ ); } _except(EXCEPTION_EXECUTE_HANDLER) { return FALSE; } return TRUE; #endif // WINCE } BOOL IsValidStringW( const WCHAR * const lpwsz ) { #ifndef WINCE return (!IsBadStringPtrW( lpwsz, 0xFFFF ) ); #else const wchar_t *szTmpLoc = lpwsz; // // If it is a NULL pointer just return FALSE, they are always bad // if( szTmpLoc == NULL ) { return FALSE; } _try { for( ; *szTmpLoc ; szTmpLoc++ ); } _except( EXCEPTION_EXECUTE_HANDLER ) { return FALSE; } return TRUE; #endif // WINCE } #endif // !DPNBUILD_NOPARAMVAL