/**************************************************************************** * * File: sysinfo.cpp * Project: DxDiag (DirectX Diagnostic Tool) * Author: Mike Anderson (manders@microsoft.com) * CPU type detection code by Rich Granshaw * CPU speed code by Michael Lyons * Purpose: Gather system information (OS, hardware, name, etc.) on this machine * * \Multimedia\Testsrc\Tools\ShowCPUID\ can be used to debug CPUID problems. * * (C) Copyright 1998 Microsoft Corp. All rights reserved. * ****************************************************************************/ #include #include #include #include #include #include #include #include #include "dsprv.h" #include "dsprvobj.h" #include "sysinfo.h" #include "fileinfo.h" // for GetLanguageFromFile #include "resource.h" #define REGSTR_PATH_D3D TEXT("Software\\Microsoft\\Direct3D") #define REGSTR_VAL_DDRAW_LOADDEBUGRUNTIME TEXT("LoadDebugRuntime") #define REGSTR_DINPUT_DLL TEXT("CLSID\\{25E609E4-B259-11CF-BFC7-444553540000}\\InProcServer32") #define REGSTR_DMUSIC_DLL TEXT("CLSID\\{480FF4B0-28B2-11D1-BEF7-00C04FBF8FEF}\\InProcServer32") struct PROCESSOR_ID_NUMBERS { DWORD dwType; // Intel: 0 = standard, 1 = Overdrive, 2 = dual processor. DWORD dwFamily; DWORD dwModel; DWORD dwSteppingID; }; extern IWbemServices* g_pIWbemServices; typedef INT (WINAPI* LPDXSETUPGETVERSION)(DWORD* pdwVersion, DWORD* pdwRevision); static VOID GetProcessorDescription(BOOL bNT, SYSTEM_INFO* psi, TCHAR* pszDesc, BOOL* pbNoCPUSpeed); static VOID GetProcessorVendorNameAndType(OSVERSIONINFO& OSVersionInfo, SYSTEM_INFO& SystemInfo, TCHAR* pszProcessor, BOOL* pbNoCPUSpeed); static VOID GetVendorNameAndCaps(TCHAR* pszVendorName, TCHAR* pszIDTLongName, PROCESSOR_ID_NUMBERS& ProcessorIdNumbers, BOOL* pbIsMMX, BOOL* pbIs3DNow, BOOL* pbIsKatmai, /*Pentium III/Streaming SIMD Instrucs*/ LPDWORD pdwKBytesLevel2Cache, LPDWORD pdwIntelBrandIndex, BOOL* pbNoCPUSpeed); #ifdef _X86_ static INT GetCPUSpeed(VOID); static INT GetCPUSpeedViaWMI(VOID); #endif static VOID GetComputerSystemInfo(TCHAR* szSystemManufacturerEnglish, TCHAR* szSystemModelEnglish); static VOID GetBIOSInfo(TCHAR* szBIOSEnglish); static VOID GetFileSystemStoringD3D8Cache( TCHAR* strFileSystemBuffer ); static VOID GetDXDebugLevels(SysInfo* pSysInfo); static int GetDSDebugLevel(); static BOOL IsDMusicDebugRuntime(); static BOOL IsDMusicDebugRuntimeAvailable(); static int GetDMDebugLevel(); static BOOL IsDInput8DebugRuntime(); static BOOL IsDInput8DebugRuntimeAvailable(); static int GetDIDebugLevel(); static BOOL IsD3DDebugRuntime(); static BOOL IsD3D8DebugRuntimeAvailable(); static BOOL IsDDrawDebugRuntime(); static BOOL IsDPlayDebugRuntime(); static BOOL IsDSoundDebugRuntime(); static BOOL IsNetMeetingRunning(); /**************************************************************************** * * BIsPlatformNT * ****************************************************************************/ BOOL BIsPlatformNT(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); } /**************************************************************************** * * BIsPlatform9x * ****************************************************************************/ BOOL BIsPlatform9x(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); } /**************************************************************************** * * BIsWin2k * ****************************************************************************/ BOOL BIsWin2k(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return ( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion == 5 && OSVersionInfo.dwMinorVersion == 0 ); // should be 05.00.xxxx } /**************************************************************************** * * BIsWhistler * ****************************************************************************/ BOOL BIsWhistler(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return ( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion == 5 && OSVersionInfo.dwMinorVersion == 1 ); // should be 05.01.xxxx } /**************************************************************************** * * BIsWinNT * ****************************************************************************/ BOOL BIsWinNT(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return ( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion <= 4 ); } /**************************************************************************** * * BIsWinME * ****************************************************************************/ BOOL BIsWinME(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && OSVersionInfo.dwMajorVersion >= 4 && OSVersionInfo.dwMinorVersion >= 90 ); // should be 4.90.xxxx } /**************************************************************************** * * BIsWin98 - from http://kbinternal/kb/articles/q189/2/49.htm * ****************************************************************************/ BOOL BIsWin98(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && OSVersionInfo.dwMajorVersion == 4 && OSVersionInfo.dwMinorVersion == 10 ); // should be 4.10.xxxx } /**************************************************************************** * * BIsWin95 - from http://kbinternal/kb/articles/q189/2/49.htm * ****************************************************************************/ BOOL BIsWin95(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && OSVersionInfo.dwMajorVersion == 4 && OSVersionInfo.dwMinorVersion < 10 ); // should be 4.00.0950 } /**************************************************************************** * * BIsWin3x * ****************************************************************************/ BOOL BIsWin3x(VOID) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); return( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && OSVersionInfo.dwMajorVersion < 4 ); // should be 3.xx.xxxx } /**************************************************************************** * * BIsIA64 * ****************************************************************************/ BOOL BIsIA64(VOID) { OSVERSIONINFO OSVersionInfo; SYSTEM_INFO SystemInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); GetSystemInfo(&SystemInfo); return( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ); } /**************************************************************************** * * GetSystemInfo * ****************************************************************************/ VOID GetSystemInfo(SysInfo* pSysInfo) { TCHAR szSystemPath[MAX_PATH]; HKEY hKey = NULL; HKEY hSubKey = NULL; ULONG ulType; OSVERSIONINFO OSVersionInfo; SYSTEM_INFO SystemInfo; DWORD cbData; LCID lcid; DWORD dwKeyboardSubType; WORD wLanguage; TCHAR sz[200]; TCHAR szDebug[100]; // Get current time TCHAR szDate[100]; TCHAR szTime[100]; GetLocalTime(&pSysInfo->m_time); GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL, szDate, 100); wsprintf(szTime, TEXT("%02d:%02d:%02d"), pSysInfo->m_time.wHour, pSysInfo->m_time.wMinute, pSysInfo->m_time.wSecond); wsprintf(pSysInfo->m_szTimeLocal, TEXT("%s, %s"), szDate, szTime); wsprintf(szDate, TEXT("%d/%d/%d"), pSysInfo->m_time.wMonth, pSysInfo->m_time.wDay, pSysInfo->m_time.wYear); wsprintf(pSysInfo->m_szTime, TEXT("%s, %s"), szDate, szTime); // Get the computer network name cbData = sizeof(pSysInfo->m_szMachine) - 1; if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"), 0, KEY_READ, &hKey) && !RegQueryValueEx(hKey, TEXT("ComputerName"), 0, &ulType, (LPBYTE)pSysInfo->m_szMachine, &cbData) && ulType == REG_SZ) { // Got data OK. } else { LoadString(NULL, IDS_NOMACHINENAME, pSysInfo->m_szMachine, 200); } if (hKey) { RegCloseKey(hKey); hKey = 0; } // Check for NEC PC-98 pSysInfo->m_bNECPC98 = FALSE; lcid = GetSystemDefaultLCID(); if (lcid == 0x0411) // Windows 95 J { dwKeyboardSubType = GetKeyboardType(1); if (HIBYTE(dwKeyboardSubType) == 0x0D) // NEC PC-98 series { pSysInfo->m_bNECPC98 = TRUE; LoadString(NULL, IDS_NECPC98, sz, 200); lstrcat(pSysInfo->m_szMachine, sz); } } // Get Windows version OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); pSysInfo->m_dwMajorVersion = OSVersionInfo.dwMajorVersion; pSysInfo->m_dwMinorVersion = OSVersionInfo.dwMinorVersion; pSysInfo->m_dwBuildNumber = OSVersionInfo.dwBuildNumber; pSysInfo->m_dwPlatformID = OSVersionInfo.dwPlatformId; lstrcpy(pSysInfo->m_szCSDVersion, OSVersionInfo.szCSDVersion); pSysInfo->m_bDebug = (GetSystemMetrics(SM_DEBUG) > 0); // Get OS Name TCHAR* pszWindowsKey; if (pSysInfo->m_dwPlatformID == VER_PLATFORM_WIN32_NT) pszWindowsKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"); else pszWindowsKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion"); if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszWindowsKey, 0, KEY_READ, &hKey)) { cbData = 100; RegQueryValueEx(hKey, TEXT("ProductName"), 0, &ulType, (LPBYTE)pSysInfo->m_szOS, &cbData); cbData = 100; RegQueryValueEx(hKey, TEXT("BuildLab"), 0, &ulType, (LPBYTE)pSysInfo->m_szBuildLab, &cbData); RegCloseKey(hKey); } if (lstrlen(pSysInfo->m_szOS) == 0) { // it is very strange for ProductName registry info // (see above) to be missing. lstrcpy(pSysInfo->m_szOS, TEXT("Windows")); } if (pSysInfo->m_dwPlatformID == VER_PLATFORM_WIN32_NT) { // 25598: Append product type (professional, server, etc) OSVERSIONINFOEX osve; ZeroMemory(&osve, sizeof(osve)); osve.dwOSVersionInfoSize = sizeof(osve); GetVersionEx((OSVERSIONINFO*)&osve); if (osve.wProductType == VER_NT_SERVER && osve.wSuiteMask & VER_SUITE_DATACENTER) { lstrcat(pSysInfo->m_szOS, TEXT(" ")); LoadString(NULL, IDS_DATACENTERSERVER, sz, 200); lstrcat(pSysInfo->m_szOS, sz); } else if (osve.wProductType == VER_NT_SERVER && osve.wSuiteMask & VER_SUITE_ENTERPRISE) { lstrcat(pSysInfo->m_szOS, TEXT(" ")); LoadString(NULL, IDS_ADVANCEDSERVER, sz, 200); lstrcat(pSysInfo->m_szOS, sz); } else if (osve.wProductType == VER_NT_SERVER) { lstrcat(pSysInfo->m_szOS, TEXT(" ")); LoadString(NULL, IDS_SERVER, sz, 200); lstrcat(pSysInfo->m_szOS, sz); } else if (osve.wProductType == VER_NT_WORKSTATION && (osve.wSuiteMask & VER_SUITE_PERSONAL)) { lstrcat(pSysInfo->m_szOS, TEXT(" ")); LoadString(NULL, IDS_PERSONAL, sz, 200); lstrcat(pSysInfo->m_szOS, sz); } else if (osve.wProductType == VER_NT_WORKSTATION) { lstrcat(pSysInfo->m_szOS, TEXT(" ")); LoadString(NULL, IDS_PROFESSIONAL, sz, 200); lstrcat(pSysInfo->m_szOS, sz); } } // Format Windows version LoadString(NULL, IDS_WINVERFMT, sz, 200); LoadString(NULL, IDS_DEBUG, szDebug, 100); lstrcat(szDebug, TEXT(" ")); wsprintf(pSysInfo->m_szOSEx, sz, pSysInfo->m_bDebug ? szDebug : TEXT(""), pSysInfo->m_szOS, pSysInfo->m_dwMajorVersion, pSysInfo->m_dwMinorVersion, LOWORD(pSysInfo->m_dwBuildNumber)); TCHAR szOSTmp[200]; if( _tcslen( pSysInfo->m_szCSDVersion) ) wsprintf( szOSTmp, TEXT("%s %s"), pSysInfo->m_szOSEx, pSysInfo->m_szCSDVersion ); else wsprintf( szOSTmp, TEXT("%s"), pSysInfo->m_szOSEx ); if( _tcslen( pSysInfo->m_szBuildLab ) ) wsprintf( pSysInfo->m_szOSExLong, TEXT("%s (%s)"), szOSTmp, pSysInfo->m_szBuildLab ); else wsprintf( pSysInfo->m_szOSExLong, TEXT("%s"), szOSTmp ); // Get the original language. GetSystemDirectory(szSystemPath, MAX_PATH); if (wLanguage = GetLanguageFromFile(TEXT("user.exe"), szSystemPath)) { lcid = MAKELCID(wLanguage, SORT_DEFAULT); } // Get the language and regional setting and store them (in English) for saved file: TCHAR szLanguage[200]; TCHAR szLanguageRegional[200]; if ((!GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, szLanguage, 200))) szLanguage[0] = '\0'; if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, szLanguageRegional, 200)) szLanguageRegional[0] = '\0'; LoadString(NULL, IDS_LANGUAGEFMT_ENGLISH, sz, 200); wsprintf(pSysInfo->m_szLanguages, sz, szLanguage, szLanguageRegional); // Now get same info in local language for display: if ((!GetLocaleInfo(lcid, LOCALE_SNATIVELANGNAME, szLanguage, 200))) szLanguage[0] = '\0'; if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, szLanguageRegional, 200)) szLanguageRegional[0] = '\0'; LoadString(NULL, IDS_LANGUAGEFMT, sz, 200); wsprintf(pSysInfo->m_szLanguagesLocal, sz, szLanguage, szLanguageRegional); // Get info about processor manufacturer and type BOOL bNoCPUSpeed = TRUE; GetSystemInfo(&SystemInfo); GetProcessorDescription(pSysInfo->m_dwPlatformID == VER_PLATFORM_WIN32_NT, &SystemInfo, pSysInfo->m_szProcessor, &bNoCPUSpeed); GetComputerSystemInfo(pSysInfo->m_szSystemManufacturerEnglish, pSysInfo->m_szSystemModelEnglish); GetBIOSInfo(pSysInfo->m_szBIOSEnglish); #ifdef _X86_ // Append processor speed, if it can be computed if ( bNoCPUSpeed ) { INT iMhz = GetCPUSpeed(); if (iMhz > 0) { TCHAR szSpeed[50]; wsprintf(szSpeed, TEXT(", ~%dMHz"), iMhz); lstrcat(pSysInfo->m_szProcessor, szSpeed); } } #endif BOOL bGotMem = FALSE; // Get system memory information if( BIsPlatformNT() ) { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\kernel32.dll")); HINSTANCE hKernel32 = LoadLibrary(szPath); if( hKernel32 != NULL ) { typedef BOOL (WINAPI* PGlobalMemoryStatusEx)(OUT LPMEMORYSTATUSEX lpBuffer); PGlobalMemoryStatusEx pGlobalMemoryStatusEx = (PGlobalMemoryStatusEx)GetProcAddress(hKernel32, "GlobalMemoryStatusEx"); if( pGlobalMemoryStatusEx != NULL ) { MEMORYSTATUSEX MemoryStatus; MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX); pGlobalMemoryStatusEx(&MemoryStatus); pSysInfo->m_ullPhysicalMemory = MemoryStatus.ullTotalPhys; pSysInfo->m_ullUsedPageFile = MemoryStatus.ullTotalPageFile - MemoryStatus.ullAvailPageFile; pSysInfo->m_ullAvailPageFile = MemoryStatus.ullAvailPageFile; bGotMem = TRUE; } FreeLibrary(hKernel32); } } if( !bGotMem ) // Win9x or LoadLib failed { MEMORYSTATUS MemoryStatus; MemoryStatus.dwLength = sizeof MemoryStatus; GlobalMemoryStatus(&MemoryStatus); pSysInfo->m_ullPhysicalMemory = MemoryStatus.dwTotalPhys; pSysInfo->m_ullUsedPageFile = MemoryStatus.dwTotalPageFile - MemoryStatus.dwAvailPageFile; pSysInfo->m_ullAvailPageFile = MemoryStatus.dwAvailPageFile; } // Format memory information: DWORDLONG dwMB = (DWORDLONG)(pSysInfo->m_ullPhysicalMemory >> 20); dwMB += dwMB % 2; // round up to even number _stprintf(pSysInfo->m_szPhysicalMemory, TEXT("%I64dMB RAM"), dwMB); DWORDLONG dwUsedMB = (pSysInfo->m_ullUsedPageFile >> 20); DWORDLONG dwAvailMB = (pSysInfo->m_ullAvailPageFile >> 20); LoadString(NULL, IDS_PAGEFILEFMT, sz, 200); _stprintf(pSysInfo->m_szPageFile, sz, dwUsedMB, dwAvailMB); LoadString(NULL, IDS_PAGEFILEFMT_ENGLISH, sz, 200); _stprintf(pSysInfo->m_szPageFileEnglish, sz, dwUsedMB, dwAvailMB); // Get DxDiag version: TCHAR szFile[MAX_PATH]; if (0 != GetModuleFileName(NULL, szFile, MAX_PATH)) GetFileVersion(szFile, pSysInfo->m_szDxDiagVersion, NULL, NULL, NULL, NULL); // Get DirectX Version using dsetup.dll TCHAR szSetupPath[MAX_PATH]; HINSTANCE hInstDSetup; LPDXSETUPGETVERSION pDXSGetVersion; BOOL bFound = FALSE; LoadString(NULL, IDS_NOTFOUND, pSysInfo->m_szDirectXVersionLong, 100); if (!BIsPlatformNT() && GetDxSetupFolder(szSetupPath)) { lstrcat(szSetupPath, TEXT("\\dsetup.dll")); hInstDSetup = LoadLibrary(szSetupPath); if (hInstDSetup != NULL) { pDXSGetVersion = (LPDXSETUPGETVERSION)GetProcAddress(hInstDSetup, "DirectXSetupGetVersion"); if (pDXSGetVersion != NULL) { DWORD dwVersion = 0; DWORD dwRevision = 0; if (pDXSGetVersion(&dwVersion, &dwRevision) != 0) { wsprintf(pSysInfo->m_szDirectXVersion, TEXT("%d.%02d.%02d.%04d"), HIWORD(dwVersion), LOWORD(dwVersion), HIWORD(dwRevision), LOWORD(dwRevision)); bFound = TRUE; } } FreeLibrary(hInstDSetup); } } if (!bFound) { // Look in registry for DX version instead HKEY hkey; DWORD cbData; ULONG ulType; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\DirectX"), 0, KEY_READ, &hkey)) { cbData = 100; RegQueryValueEx(hkey, TEXT("Version"), 0, &ulType, (LPBYTE)pSysInfo->m_szDirectXVersion, &cbData); RegCloseKey(hkey); if (lstrlen(pSysInfo->m_szDirectXVersion) > 6 && lstrlen(pSysInfo->m_szDirectXVersion) < 20) { bFound = TRUE; } } } if (!bFound && !BIsPlatformNT()) { // Report ddraw.dll version instead // (except on Win2000, where ddraw.dll version is way different from DX version) TCHAR szDDrawPath[MAX_PATH]; GetSystemDirectory(szDDrawPath, MAX_PATH); lstrcat(szDDrawPath, TEXT("\\ddraw.dll")); GetFileVersion(szDDrawPath, pSysInfo->m_szDirectXVersion, NULL, NULL, NULL); } if (lstrlen(pSysInfo->m_szDirectXVersion) > 0) { // Bug 18501: Add "friendly" version of version name DWORD dwMajor; DWORD dwMinor; DWORD dwRevision; DWORD dwBuild; TCHAR szFriendly[100]; lstrcpy(szFriendly, TEXT("")); _stscanf(pSysInfo->m_szDirectXVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild); wsprintf(pSysInfo->m_szDirectXVersion, TEXT("%d.%02d.%02d.%04d"), dwMajor, dwMinor, dwRevision, dwBuild); // According to http://xevious/directx/versions.htm: // 4.02.xx.xxxx is DX1 // 4.03.xx.xxxx is DX2 // 4.04.xx.xxxx is DX3 // 4.05.xx.xxxx is DX5 // 4.06.00.xxxx is DX6 // 4.06.02.xxxx is DX6.1 // 4.06.03.xxxx is DX6.1A // 4.07.00.xxxx is DX7.0 // 4.07.01.xxxx is DX7.1 // Beyond that, who knows... pSysInfo->m_dwDirectXVersionMajor = 0; pSysInfo->m_dwDirectXVersionMinor = 0; pSysInfo->m_cDirectXVersionLetter = TEXT(' '); if (dwMajor == 4 && dwMinor == 2) { lstrcpy(szFriendly, TEXT("DirectX 1")); pSysInfo->m_dwDirectXVersionMajor = 1; } if (dwMajor == 4 && dwMinor == 3) { lstrcpy(szFriendly, TEXT("DirectX 2")); pSysInfo->m_dwDirectXVersionMajor = 2; } if (dwMajor == 4 && dwMinor == 4) { lstrcpy(szFriendly, TEXT("DirectX 3")); pSysInfo->m_dwDirectXVersionMajor = 3; } if (dwMajor == 4 && dwMinor == 5) { lstrcpy(szFriendly, TEXT("DirectX 5")); pSysInfo->m_dwDirectXVersionMajor = 5; } else if (dwMajor == 4 && dwMinor == 6 && dwRevision == 0) { lstrcpy(szFriendly, TEXT("DirectX 6")); pSysInfo->m_dwDirectXVersionMajor = 6; } else if (dwMajor == 4 && dwMinor == 6 && dwRevision == 2) { lstrcpy(szFriendly, TEXT("DirectX 6.1")); pSysInfo->m_dwDirectXVersionMajor = 6; pSysInfo->m_dwDirectXVersionMinor = 1; } else if (dwMajor == 4 && dwMinor == 6 && dwRevision == 3) { lstrcpy(szFriendly, TEXT("DirectX 6.1a")); pSysInfo->m_dwDirectXVersionMajor = 6; pSysInfo->m_dwDirectXVersionMinor = 1; pSysInfo->m_cDirectXVersionLetter = TEXT('a'); } else if (dwMajor == 4 && dwMinor == 7 && dwRevision == 0 && dwBuild == 716) { lstrcpy(szFriendly, TEXT("DirectX 7.0a")); pSysInfo->m_dwDirectXVersionMajor = 7; pSysInfo->m_cDirectXVersionLetter = TEXT('a'); } else if (dwMajor == 4 && dwMinor == 7 && dwRevision == 0) { lstrcpy(szFriendly, TEXT("DirectX 7.0")); pSysInfo->m_dwDirectXVersionMajor = 7; } else if (dwMajor == 4 && dwMinor == 7 && dwRevision == 1) { lstrcpy(szFriendly, TEXT("DirectX 7.1")); pSysInfo->m_dwDirectXVersionMajor = 7; pSysInfo->m_dwDirectXVersionMinor = 1; } else if (dwMajor == 4 && dwMinor == 8 && dwRevision == 0 ) { lstrcpy(szFriendly, TEXT("DirectX 8.0")); pSysInfo->m_dwDirectXVersionMajor = 8; } else { lstrcpy(szFriendly, TEXT("DirectX 8.1")); pSysInfo->m_dwDirectXVersionMajor = dwMinor; pSysInfo->m_dwDirectXVersionMinor = dwRevision; } if (lstrlen(szFriendly) > 0) wsprintf(pSysInfo->m_szDirectXVersionLong, TEXT("%s (%s)"), szFriendly, pSysInfo->m_szDirectXVersion); else lstrcpy(pSysInfo->m_szDirectXVersionLong, pSysInfo->m_szDirectXVersion); } // 24169: Detect setup switches pSysInfo->m_dwSetupParam = 0xffffffff; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\DirectX"), 0, NULL, &hKey)) { cbData = sizeof(DWORD); RegQueryValueEx(hKey, TEXT("Command"), NULL, &ulType, (BYTE*)&(pSysInfo->m_dwSetupParam), &cbData); RegCloseKey(hKey); } // 48330: add debug level in txt file GetDXDebugLevels( pSysInfo ); switch (pSysInfo->m_dwSetupParam) { case 0xffffffff: lstrcpy(pSysInfo->m_szSetupParam, TEXT("Not found")); break; case 0: lstrcpy(pSysInfo->m_szSetupParam, TEXT("None")); break; case 1: lstrcpy(pSysInfo->m_szSetupParam, TEXT("/Silent")); break; case 2: lstrcpy(pSysInfo->m_szSetupParam, TEXT("/WindowsUpdate")); break; case 3: lstrcpy(pSysInfo->m_szSetupParam, TEXT("/PackageInstall")); break; case 4: lstrcpy(pSysInfo->m_szSetupParam, TEXT("/Silent /Reboot")); break; case 5: lstrcpy(pSysInfo->m_szSetupParam, TEXT("/Reboot")); break; default: wsprintf(pSysInfo->m_szSetupParam, TEXT("Unknown Switch (%d)"), pSysInfo->m_dwSetupParam); break; } GetFileSystemStoringD3D8Cache( pSysInfo->m_szD3D8CacheFileSystem ); pSysInfo->m_bNetMeetingRunning = IsNetMeetingRunning(); } /**************************************************************************** * * GetProcessorDescription * ****************************************************************************/ VOID GetProcessorDescription(BOOL bNT, SYSTEM_INFO* psi, TCHAR* pszDesc, BOOL* pbNoCPUSpeed) { OSVERSIONINFO OSVersionInfo; SYSTEM_INFO SystemInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo; GetVersionEx(&OSVersionInfo); GetSystemInfo(&SystemInfo); GetProcessorVendorNameAndType(OSVersionInfo, SystemInfo, pszDesc, pbNoCPUSpeed); if (SystemInfo.dwNumberOfProcessors > 1) { TCHAR szFmt[100]; TCHAR szNumProc[100]; LoadString(NULL, IDS_NUMPROCFMT, szFmt, 100); wsprintf(szNumProc, szFmt, SystemInfo.dwNumberOfProcessors); lstrcat(pszDesc, szNumProc); } } /**************************************************************************** * * GetProcessorVendorNameAndType * ****************************************************************************/ VOID GetProcessorVendorNameAndType(OSVERSIONINFO& OSVersionInfo, SYSTEM_INFO& SystemInfo, TCHAR* pszProcessor, BOOL* pbNoCPUSpeed) { TCHAR szVendorName[50]; TCHAR szLongName[50]; TCHAR szDesc[100]; BOOL bIsMMX = FALSE; BOOL bIs3DNow = FALSE; // 10/27/98(RichGr): Intel's Katmai New Instructions (KNI). BOOL bIsKatmai = FALSE; /* 2/04/99(RichGr): Pentium III/Streaming SIMD Instrucs*/ PROCESSOR_ID_NUMBERS ProcessorIdNumbers; DWORD dwKBytesLevel2Cache; DWORD dwIntelBrandIndex; memset(&szVendorName[0], 0, sizeof szVendorName); memset(&szLongName[0], 0, sizeof szLongName); memset(&ProcessorIdNumbers, 0, sizeof ProcessorIdNumbers); // 6/21/99(RichGr): On the Intel, we can now interpret a 1-byte descriptor to give us // the size of the Level 2 cache, if present. dwKBytesLevel2Cache = 0; // 4/26/01(RichGr): On the Intel, we have a new 1-byte index that specifies the brand. dwIntelBrandIndex = 0; if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS // Win9x || (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT // WinNT && SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)) { GetVendorNameAndCaps(szVendorName, szLongName, ProcessorIdNumbers, &bIsMMX, &bIs3DNow, &bIsKatmai, &dwKBytesLevel2Cache, &dwIntelBrandIndex, pbNoCPUSpeed); if (szLongName[0]) // Use this if there's anything there. lstrcpy(pszProcessor, szLongName); else { lstrcpy(pszProcessor, szVendorName); lstrcat(pszProcessor, TEXT(" ")); if ( !lstrcmp(szVendorName, TEXT("Intel"))) { if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_386) lstrcat(pszProcessor, TEXT("80386")); else if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_486) lstrcat(pszProcessor, TEXT("80486")); else if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM) { // 6/21/99(RichGr): A lot of this code is now derived from \\muroc\slm\proj\win\src\shell\cpls\system\sysset.c. switch ( ProcessorIdNumbers.dwFamily ) { // We should, of course, never hit these - they've been dealt with above. case 0: case 1: case 2: case 3: case 4: lstrcat(pszProcessor, TEXT("80486")); break; case 5: lstrcat(pszProcessor, TEXT("Pentium")); if ( ProcessorIdNumbers.dwModel == 3 ) lstrcat(pszProcessor, TEXT(" Overdrive")); break; case 6: switch ( ProcessorIdNumbers.dwModel ) { // //Model 1 and 2 are Pentium Pro // case 0: case 1: case 2: lstrcat(pszProcessor, TEXT("Pentium Pro")); break; // //Model 3 and 4 are Pentium II // case 3: case 4: lstrcat(pszProcessor, TEXT("Pentium II")); break; // //Model 5 is either Pentium II or Celeron (depending on if the chip //has L2 cache or not) // case 5: if ( dwKBytesLevel2Cache == 0 ) // //No L2 cache so it is a Celeron // lstrcat(pszProcessor, TEXT("Celeron")); else // //L2 cache so it is at least a Pentium II. // if ( bIsKatmai ) lstrcat(pszProcessor, TEXT("Pentium III")); else lstrcat(pszProcessor, TEXT("Pentium II")); break; case 6: if ( dwKBytesLevel2Cache > 128 ) // //L2 cache > 128K so it is at least a Pentium II // if ( bIsKatmai ) lstrcat(pszProcessor, TEXT("Pentium III")); else lstrcat(pszProcessor, TEXT("Pentium II")); else // //L2 cache <= 128K so it is a Celeron // lstrcat(pszProcessor, TEXT("Celeron")); break; case 7: lstrcat(pszProcessor, TEXT("Pentium III")); break; default: if ( bIsKatmai ) { // 4/26/01(RichGr): Pentium III Xeons and later have a one-byte Brand Index that we can use. // More recent machines have a Brand String as well. // see ftp://download.intel.com/design/Pentium4/manuals/24547103.pdf if (dwIntelBrandIndex == 1) lstrcat(pszProcessor, TEXT("Celeron")); else if (dwIntelBrandIndex == 0 || dwIntelBrandIndex == 2) lstrcat(pszProcessor, TEXT("Pentium III")); else if (dwIntelBrandIndex == 3) lstrcat(pszProcessor, TEXT("Pentium III Xeon")); else if (dwIntelBrandIndex == 8) lstrcat(pszProcessor, TEXT("Pentium 4")); else lstrcat(pszProcessor, TEXT("Pentium")); } else lstrcat(pszProcessor, TEXT("Pentium II")); break; } break; default: wsprintf( szDesc, TEXT("x86 Family %u Model %u Stepping %u"), ProcessorIdNumbers.dwFamily, ProcessorIdNumbers.dwModel, ProcessorIdNumbers.dwSteppingID ); lstrcat(pszProcessor, szDesc); break; } } } else if ( !lstrcmp(szVendorName, TEXT("AMD"))) { if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_486) lstrcat(pszProcessor, TEXT("Am486 or Am5X86")); else if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM) { if (ProcessorIdNumbers.dwFamily == 5) { if (ProcessorIdNumbers.dwModel < 6) { wsprintf(szDesc, TEXT("K5 (Model %d)"), ProcessorIdNumbers.dwModel); lstrcat(pszProcessor, szDesc); } else { lstrcat(pszProcessor, TEXT("K6")); } } else { wsprintf(szDesc, TEXT("K%d (Model %d)"), ProcessorIdNumbers.dwFamily, ProcessorIdNumbers.dwModel); lstrcat(pszProcessor, szDesc); } } } else if ( !lstrcmp(szVendorName, TEXT("Cyrix"))) { if (ProcessorIdNumbers.dwFamily == 4) { if (ProcessorIdNumbers.dwModel == 4) lstrcat(pszProcessor, TEXT("MediaGX")); } else if (ProcessorIdNumbers.dwFamily == 5) { if (ProcessorIdNumbers.dwModel == 2) lstrcat(pszProcessor, TEXT("6x86")); else if (ProcessorIdNumbers.dwModel == 4) lstrcat(pszProcessor, TEXT("GXm")); } else if (ProcessorIdNumbers.dwFamily == 6) { lstrcat(pszProcessor, TEXT("6x86MX")); } } else if ( !lstrcmp(szVendorName, TEXT("IDT"))) { // 4/21/98(RichGr): There's only 1 chip available at present. // 7/07/98(RichGr): Now there are two chips. // Note: Although the C6 is MMX-compatible, Intel does not allow IDT to display the word "MMX" // in association with the name IDT, so we'll skip that. // See http://www.winchip.com/ for more info. if (ProcessorIdNumbers.dwFamily == 5) { if (ProcessorIdNumbers.dwModel == 4) lstrcat(pszProcessor, TEXT("WinChip C6")); else if (ProcessorIdNumbers.dwModel >= 8) // 7/07/98(RichGr): Assume later models have the same feature. lstrcat(pszProcessor, TEXT("WinChip 2")); } else lstrcat(pszProcessor, TEXT("WinChip")); } else { if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_486) lstrcat(pszProcessor, TEXT("486")); else if (SystemInfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM) { if (ProcessorIdNumbers.dwFamily == 5) lstrcat(pszProcessor, TEXT("P5")); else if (ProcessorIdNumbers.dwFamily == 6) lstrcat(pszProcessor, TEXT("P6")); else lstrcat(pszProcessor, TEXT("P5")); } } } if (bIsKatmai && !lstrcmp(szVendorName, TEXT("Intel"))) ; else { if (bIsMMX || bIs3DNow) lstrcat(pszProcessor, TEXT(", ")); if (bIsMMX) lstrcat(pszProcessor, TEXT(" MMX")); if (bIs3DNow) { if (bIsMMX) lstrcat(pszProcessor, TEXT(", ")); lstrcat(pszProcessor, TEXT(" 3DNow")); } } } else if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) // WinNT { if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { lstrcpy(pszProcessor, TEXT("IA64")); } else if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS) { lstrcpy(pszProcessor, TEXT("MIPS ")); wsprintf(szDesc, TEXT("R%d000"), SystemInfo.wProcessorLevel); lstrcat(pszProcessor, szDesc); if (SystemInfo.wProcessorRevision) { wsprintf(szDesc, TEXT(" rev. %d"), LOBYTE(SystemInfo.wProcessorRevision)); lstrcat(pszProcessor, szDesc); } } else if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) { lstrcpy(pszProcessor, TEXT("Alpha ")); wsprintf(szDesc, TEXT("%d"), SystemInfo.wProcessorLevel); lstrcat(pszProcessor, szDesc); if (SystemInfo.wProcessorRevision) { wsprintf(szDesc, TEXT(" Model %C - Pass %d"), HIBYTE(SystemInfo.wProcessorRevision) + 'A', LOBYTE(SystemInfo.wProcessorRevision)); lstrcat(pszProcessor, szDesc); } } else if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC) { lstrcpy(pszProcessor, TEXT("Power PC ")); if (SystemInfo.wProcessorLevel == 1) lstrcat(pszProcessor, TEXT("601")); else if (SystemInfo.wProcessorLevel == 3) lstrcat(pszProcessor, TEXT("603")); else if (SystemInfo.wProcessorLevel == 4) lstrcat(pszProcessor, TEXT("604")); else if (SystemInfo.wProcessorLevel == 6) lstrcat(pszProcessor, TEXT("603+")); else if (SystemInfo.wProcessorLevel == 9) lstrcat(pszProcessor, TEXT("604+")); else if (SystemInfo.wProcessorLevel == 20) lstrcat(pszProcessor, TEXT("620")); if (SystemInfo.wProcessorRevision) { wsprintf(szDesc, TEXT(" rev. %d.%d"), HIBYTE(SystemInfo.wProcessorRevision), LOBYTE(SystemInfo.wProcessorRevision)); lstrcat(pszProcessor, szDesc); } } else lstrcpy(pszProcessor, TEXT("Unknown ")); } } /**************************************************************************** * * GetVendorNameAndCaps * ****************************************************************************/ VOID GetVendorNameAndCaps(TCHAR* pszVendorName, TCHAR* pszLongName, PROCESSOR_ID_NUMBERS& ProcessorIdNumbers, BOOL* pbIsMMX, BOOL* pbIs3DNow, BOOL* pbIsKatmai, /*Pentium III/Streaming SIMD Instrucs*/ LPDWORD pdwKBytesLevel2Cache, LPDWORD pdwIntelBrandIndex, BOOL* pbNoCPUSpeed) { CHAR szVendorLabel[13]; CHAR szLongName[50]; DWORD dwFamilyModelStep; BOOL bCPUID_works; DWORD dwFeaturesFlags; BYTE byteCacheDescriptors[4] = {0,0,0,0}; DWORD dwIntelBrandIndex; PCHAR psz; memset(&szVendorLabel[0], 0, sizeof szVendorLabel); memset(&szLongName[0], 0, sizeof szLongName); dwFamilyModelStep = 0; dwFeaturesFlags = 0; *pbIsMMX = FALSE; *pbIs3DNow = FALSE; *pbIsKatmai = FALSE; /* 2/04/99(RichGr): Pentium III/Streaming SIMD Instrucs*/ bCPUID_works = FALSE; *pdwKBytesLevel2Cache = 0; dwIntelBrandIndex = 0; #ifdef _X86_ // Determine whether CPUID instruction can be executed. __asm { // CPUID trashes lots - save everything. Also, Retail build makes assumptions about reg values. pushad // Load value of flags register into eax. pushfd pop eax // Save original flags register value in ebx. mov ebx, eax // Alter bit 21 and write new value into flags register. xor eax, 0x00200000 push eax popfd // Retrieve the new value of the flags register. pushfd pop eax // Compare with the original value. xor eax, ebx // If the new value is the same as the old, the CPUID instruction cannot // be executed. Most 486s and all Pentium-class processors should be able // to execute CPUID. // 4/21/98(RichGr): One Cyrix 6x86 machine in the Apps Lab (AP_LAREDO) can't execute // CPUID in ring 3, for no apparent reason. Another similar machine works fine. je done1 mov bCPUID_works, 1 // bCPUID_works = TRUE // Execute CPUID with eax = 0 to get Vendor Label. xor eax, eax _emit 0x0F // CPUID _emit 0xA2 // Move Vendor Label from regs to string. mov dword ptr[szVendorLabel + 0], ebx mov dword ptr[szVendorLabel + 4], edx mov dword ptr[szVendorLabel + 8], ecx // Execute CPUID with eax = 1 to pick up Family, Model and Stepping ID, and to check for MMX support. mov eax, 1 _emit 0x0F // CPUID _emit 0xA2 // Save Family/Model/Stepping ID. mov dwFamilyModelStep, eax // 4/26/01(RichGr): Save Brand Index (new for PIII Xeons and after). This is the low byte only. mov dwIntelBrandIndex, ebx // 2/04/99(RichGr): Save Features Flags. mov dwFeaturesFlags, edx // 6/21/99(RichGr): Execute CPUID with eax == 2 to pick up descriptor for size of Level 2 cache. mov eax, 2 _emit 0x0F // CPUID _emit 0xA2 // Save Level 2 cache size descriptor in byte 0, together with 3 other cache descriptors in bytes 1 - 3. // See \\muroc\slm\proj\win\src\shell\cpls\system\sysset.c and cpuid.asm, // and Intel Architecture Software Developer's Manual (1997), volume 2, p. 105. mov dword ptr[byteCacheDescriptors], edx done1: // Restore everything. popad } #endif // _X86_ dwIntelBrandIndex &= 0xFF; *pdwIntelBrandIndex = dwIntelBrandIndex; // 6/21/99(RichGr): The following values were helpfully provided by David Penley(Intel): /* 40H No L2 Cache 41H L2 Unified cache: 128K Bytes, 4-way set associative, 32 byte line size 42H L2 Unified cache: 256K Bytes, 4-way set associative, 32 byte line size 43H L2 Unified cache: 512K Bytes, 4-way set associative, 32 byte line size 44H L2 Unified cache: 1M Byte, 4-way set associative, 32 byte line size 45H L2 Unified cache: 2M Byte, 4-way set associative, 32 byte line size Updated manuals can be had at... http://developer.intel.com/design/pentiumiii/xeon/manuals/ */ if (szVendorLabel[0]) { if ( !strcmp(&szVendorLabel[0], "GenuineIntel")) { lstrcpy(pszVendorName, TEXT("Intel")); // 4/29/01: This doesn't cover the Pentium 4, but we don't need cache size // for it at present. if ( byteCacheDescriptors[0] == 0x40 ) *pdwKBytesLevel2Cache = 0; else if ( byteCacheDescriptors[0] == 0x41 ) *pdwKBytesLevel2Cache = 128; else if ( byteCacheDescriptors[0] == 0x42 ) *pdwKBytesLevel2Cache = 256; else if ( byteCacheDescriptors[0] == 0x43 ) *pdwKBytesLevel2Cache = 512; else if ( byteCacheDescriptors[0] == 0x44 ) *pdwKBytesLevel2Cache = 1024; else if ( byteCacheDescriptors[0] == 0x45 ) *pdwKBytesLevel2Cache = 2048; } else if ( !strcmp(&szVendorLabel[0], "AuthenticAMD")) lstrcpy(pszVendorName, TEXT("AMD")); else if ( !strcmp(&szVendorLabel[0], "CyrixInstead")) lstrcpy(pszVendorName, TEXT("Cyrix")); else if ( !strcmp(&szVendorLabel[0], "CentaurHauls")) lstrcpy(pszVendorName, TEXT("IDT")); else { #ifdef UNICODE MultiByteToWideChar(CP_ACP, 0, szVendorLabel, -1, pszVendorName, 50); #else lstrcpy(pszVendorName, szVendorLabel); #endif } } else lstrcpy(pszVendorName, TEXT("Intel")); if (dwFamilyModelStep) { ProcessorIdNumbers.dwType = (dwFamilyModelStep & 0x00003000) >> 12; ProcessorIdNumbers.dwFamily = (dwFamilyModelStep & 0x00000F00) >> 8; ProcessorIdNumbers.dwModel = (dwFamilyModelStep & 0x000000F0) >> 4; ProcessorIdNumbers.dwSteppingID = dwFamilyModelStep & 0x0000000F; } if (dwFeaturesFlags) { // Check whether MMX is supported. if (dwFeaturesFlags & 0x00800000) *pbIsMMX = TRUE; // 2/04/99(RichGr): Check whether Katmai is supported (aka Pentium III/Streaming SIMD Instrucs). if ((dwFeaturesFlags & 0x02000000) && !lstrcmp(pszVendorName, TEXT("Intel"))) *pbIsKatmai = TRUE; } // 7/07/98(RichGr): Added for IDT's Long Name feature. // 9/10/98(RichGr): Attempt this on all processors, and skip if there's nothing there. #ifdef _X86_ if (bCPUID_works) { __asm { // CPUID trashes lots - save everything. Also, Retail build makes assumptions about reg values. pushad // 9/10/98(RichGr): Check for extended CPUID support. mov eax, 0x80000000 _emit 0x0F // CPUID _emit 0xA2 cmp eax, 0x80000001 // Jump if no extended CPUID. jb done2 // Check for AMD's 3DNow feature. Note: They believe this may be added to other non-AMD CPUs as well. // Adapted from one of AMD's webpages at: http://www.amd.com/3dsdk/library/macros/amddcpu.html mov eax, 0x80000001 _emit 0x0F // CPUID _emit 0xA2 test edx, 0x80000000 // Check for 3DNow flag. jz LongName mov eax, pbIs3DNow mov dword ptr[eax], 1 // bIs3DNow = TRUE // Execute CPUID with eax = 0x80000002 thru 0x80000004 to get 48-byte Long Name (for instance: "IDT WinChip 2-3D"). LongName: mov esi, 0x80000001 xor edi, edi NameLoop: inc esi mov eax,esi cmp eax, 0x80000004 jg done2 _emit 0x0F // CPUID _emit 0xA2 // 9/10/98(RichGr): The first time thru, check that there's valid alphanumeric data. cmp esi, 0x80000002 // First time? jg Move // If not, skip this test. cmp al, 0x20 // If first character < ' ', skip. jl done2 cmp al, 0x7a // If first character > 'z', skip. jg done2 // Move Long Name from regs to string. Move: mov dword ptr[szLongName + edi + 0x0], eax mov dword ptr[szLongName + edi + 0x4], ebx mov dword ptr[szLongName + edi + 0x8], ecx mov dword ptr[szLongName + edi + 0x0c], edx add edi, 0x10 jmp NameLoop done2: // Restore everything. popad } if ( szLongName[0] ) { // Move beyond Intel's leading spaces. for (psz = &szLongName[0]; *psz == ' '; psz++); if (*psz) { #ifdef UNICODE MultiByteToWideChar(CP_ACP, 0, psz, -1, pszLongName, 50); #else strcpy(pszLongName, psz); #endif // 4/29/01(RichGr): Intel Brand Strings show the maximum rated CPU Speed, no need for further detection. if ( !lstrcmp(pszVendorName, TEXT("Intel"))) *pbNoCPUSpeed = FALSE; } } } #endif // _X86_ } #ifdef _X86_ // Some static variables used by GetCPUSpeed static int s_milliseconds; static __int64 s_ticks; /**************************************************************************** * * fabs * ****************************************************************************/ FLOAT inline fabs(FLOAT a) { if (a < 0.0f) return -a; else return a; } /**************************************************************************** * * StartTimingCPU * ****************************************************************************/ int StartTimingCPU( HANDLE& hProcess, DWORD& oldclass ) { // // detect ability to get info // // 4/03/2000(RichGr): The RDTSC instruction is crashing on some older Cyrix machines, // so wrap a __try/__except around everything. __try { __asm { pushfd ; push extended flags pop eax ; store eflags into eax mov ebx, eax ; save EBX for testing later xor eax, (1<<21) ; switch bit 21 push eax ; push eflags popfd ; pop them again pushfd ; push extended flags pop eax ; store eflags into eax cmp eax, ebx ; see if bit 21 has changed jz no_cpuid ; make sure it's now on } // // start timing // // 10/31/99(RichGr): Bump up the priority to real-time, drawing from ToddLa's code. // See file:\\pyrex\user\toddla\speed.c hProcess = GetCurrentProcess(); oldclass = GetPriorityClass(hProcess); SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); Sleep(10); s_milliseconds = -(int)timeGetTime(); __asm { lea ecx, s_ticks ; get the offset mov dword ptr [ecx], 0 ; zero the memory mov dword ptr [ecx+4], 0 ; // rdtsc ; read time-stamp counter __emit 0fh __emit 031h sub [ecx], eax ; store the negative sbb [ecx+4], edx ; in the variable } } __except(EXCEPTION_EXECUTE_HANDLER) { goto no_cpuid; } return 0; no_cpuid: // 10/31/99(RichGr): In case someone changes the code, make sure that the priority is restored // to normal if there is an error return. if ( hProcess && oldclass ) SetPriorityClass( hProcess, oldclass ); return -1; } /**************************************************************************** * * StopTimingCPU * ****************************************************************************/ void StopTimingCPU( HANDLE& hProcess, DWORD& oldclass ) { s_milliseconds += (int)timeGetTime(); __asm { lea ecx, s_ticks ; get the offset // rdtsc ; read time-stamp counter __emit 0fh __emit 031h add [ecx], eax ; add the tick count adc [ecx+4], edx ; } // 10/31/99(RichGr): Restore the priority to normal. if ( hProcess && oldclass ) SetPriorityClass( hProcess, oldclass ); return; } /**************************************************************************** * * CalcCPUSpeed * ****************************************************************************/ INT CalcCPUSpeed(VOID) { // // get the actual cpu speed in MHz, and // then find the one in the CPU speed list // that is closest // const struct tagCPUSPEEDS { float fSpeed; int iSpeed; } cpu_speeds[] = { // // valid CPU speeds that are not integrally divisible by // 16.67 MHz // { 60.00f, 60 }, { 75.00f, 75 }, { 90.00f, 90 }, { 120.00f, 120 }, { 180.00f, 180 }, }; // // find the closest one // float fSpeed=((float)s_ticks)/((float)s_milliseconds*1000.0f); int iSpeed=cpu_speeds[0].iSpeed; float fDiff=(float)fabs(fSpeed-cpu_speeds[0].fSpeed); for (int i=1 ; i fIncr) { // // get the number of fIncr quantums the speed is // int iQuantums = (int)((fSpeed / fIncr) + 0.5f); float fQuantumSpeed = (float)iQuantums * fIncr; float fTmpDiff = (float)fabs(fQuantumSpeed - fSpeed); if (fTmpDiff < fDiff) { iSpeed = (iQuantums * iIncr) >> 8; fDiff=fTmpDiff; } } return iSpeed; } /**************************************************************************** * * GetCPUSpeed * ****************************************************************************/ INT GetCPUSpeed(VOID) { INT nCPUSpeed; // Try first using WMI - may not work on Win9x nCPUSpeed = GetCPUSpeedViaWMI(); if( nCPUSpeed != -1 ) return nCPUSpeed; // If WMI fails, then fall back on brute force cpu detection. #undef MAX_SAMPLES #define MAX_SAMPLES 10 int nSpeed = 0, nSpeeds[MAX_SAMPLES] = {0}; int nCount = 0, nCounts[MAX_SAMPLES] = {0}; int i, j; HANDLE hProcess = NULL; DWORD oldclass = 0; // 10/12/99(RichGr): Pick up the most frequently occurring speed in a number of short samples, // instead of waiting once for a whole second (see DxDiag). for ( i = 0; i < MAX_SAMPLES; i++ ) { if ( !StartTimingCPU( hProcess, oldclass )) { // 10/21/99(RichGr): Sleep() time is important. On a 266 MHz running Win98 under the kernel // debugger, the original value of Sleep(10) sometimes gave a speed of 283 MHz. // Sleep(5) to Sleep(30) were also unreliable. Sleep(40) and Sleep(50) looked good, // and I picked (50) for a little margin. Sleep(50); StopTimingCPU( hProcess, oldclass ); nSpeed = CalcCPUSpeed(); for ( j = 0; j < MAX_SAMPLES; j++ ) { if ( nSpeeds[j] == 0 || nSpeed == nSpeeds[j] ) // If the speed matches, increment the count. { nSpeeds[j] = nSpeed; nCounts[j]++; break; } } } } // Find the speed with the biggest count. for ( i = j = 0, nCount = 0; i < MAX_SAMPLES; i++ ) { if ( nCounts[i] > nCount ) { nCount = nCounts[i]; j = i; } } return nSpeeds[j]; } /**************************************************************************** * * GetCPUSpeedViaWMI * ****************************************************************************/ INT GetCPUSpeedViaWMI(VOID) { HRESULT hr; INT nCPUSpeed = -1; IEnumWbemClassObject* pEnumProcessorDevs = NULL; IWbemClassObject* pProcessorDev = NULL; BSTR pClassName = NULL; BSTR pPropName = NULL; VARIANT var; DWORD uReturned = 0; ZeroMemory( &var, sizeof(VARIANT) ); VariantClear( &var ); if( NULL == g_pIWbemServices ) return -1; pClassName = SysAllocString( L"Win32_Processor" ); hr = g_pIWbemServices->CreateInstanceEnum( pClassName, 0, NULL, &pEnumProcessorDevs ); if( FAILED(hr) || pEnumProcessorDevs == NULL ) goto LCleanup; // Get the first one in the list hr = pEnumProcessorDevs->Next( 1000, // timeout in two seconds 1, // return just one storage device &pProcessorDev, // pointer to storage device &uReturned ); // number obtained: one or zero if( FAILED(hr) || uReturned == 0 || pProcessorDev == NULL ) goto LCleanup; // 298510: MaxClockSpeed on WMI on Whistler & beyond works if( BIsWhistler() ) pPropName = SysAllocString( L"MaxClockSpeed" ); else pPropName = SysAllocString( L"CurrentClockSpeed" ); hr = pProcessorDev->Get( pPropName, 0L, &var, NULL, NULL ); if( FAILED(hr) ) goto LCleanup; // Success - record VT_I4 value in nCPUSpeed nCPUSpeed = var.lVal; LCleanup: VariantClear( &var ); if(pPropName) SysFreeString(pPropName); if(pClassName) SysFreeString(pClassName); if(pProcessorDev) pProcessorDev->Release(); if(pEnumProcessorDevs) pEnumProcessorDevs->Release(); // Return either -1 or the CPU speed we found. return nCPUSpeed; } #endif // _X86_ /**************************************************************************** * * GetComputerSystemInfo * ****************************************************************************/ VOID GetComputerSystemInfo(TCHAR* szSystemManufacturerEnglish, TCHAR* szSystemModelEnglish) { HRESULT hr; IEnumWbemClassObject* pEnumDevices = NULL; IWbemClassObject* pDevice = NULL; BSTR pClassName = NULL; BSTR pPropName = NULL; DWORD uReturned = 0; VARIANT var; ZeroMemory( &var, sizeof(VARIANT) ); VariantClear( &var ); if( NULL == g_pIWbemServices ) goto LCleanup; pClassName = SysAllocString( L"Win32_ComputerSystem" ); hr = g_pIWbemServices->CreateInstanceEnum( pClassName, 0, NULL, &pEnumDevices ); if( FAILED(hr) || pEnumDevices == NULL ) goto LCleanup; // Get the first one in the list hr = pEnumDevices->Next( 1000, // timeout in two seconds 1, // return just one storage device &pDevice, // pointer to storage device &uReturned ); // number obtained: one or zero if( FAILED(hr) || uReturned == 0 || pDevice == NULL ) goto LCleanup; pPropName = SysAllocString( L"Manufacturer" ); hr = pDevice->Get( pPropName, 0L, &var, NULL, NULL ); if( FAILED(hr) ) goto LCleanup; if(pPropName) { SysFreeString(pPropName); pPropName = NULL; } if( var.bstrVal != NULL ) { #ifdef UNICODE lstrcpy(szSystemManufacturerEnglish, var.bstrVal); #else WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), szSystemManufacturerEnglish, 199, NULL, NULL); #endif } VariantClear( &var ); pPropName = SysAllocString( L"Model" ); hr = pDevice->Get( pPropName, 0L, &var, NULL, NULL ); if( FAILED(hr) ) goto LCleanup; if(pPropName) { SysFreeString(pPropName); pPropName = NULL; } if( var.bstrVal != NULL ) { #ifdef UNICODE lstrcpy(szSystemModelEnglish, var.bstrVal); #else WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), szSystemModelEnglish, 199, NULL, NULL); #endif } VariantClear( &var ); LCleanup: if( NULL == szSystemModelEnglish ) lstrcpy( szSystemModelEnglish, TEXT("n/a") ); if( NULL == szSystemManufacturerEnglish ) lstrcpy( szSystemManufacturerEnglish, TEXT("n/a") ); if(pPropName) SysFreeString(pPropName); if(pClassName) SysFreeString(pClassName); if(pDevice) pDevice->Release(); if(pEnumDevices) pEnumDevices->Release(); return; } /**************************************************************************** * * GetBIOSInfo * ****************************************************************************/ VOID GetBIOSInfo(TCHAR* szBIOSEnglish) { HRESULT hr; IEnumWbemClassObject* pEnumDevices = NULL; IWbemClassObject* pDevice = NULL; BSTR pClassName = NULL; BSTR pPropName = NULL; DWORD uReturned = 0; VARIANT var; ZeroMemory( &var, sizeof(VARIANT) ); VariantClear( &var ); if( NULL == g_pIWbemServices ) goto LCleanup; pClassName = SysAllocString( L"Win32_BIOS" ); hr = g_pIWbemServices->CreateInstanceEnum( pClassName, 0, NULL, &pEnumDevices ); if( FAILED(hr) || pEnumDevices == NULL ) goto LCleanup; // Get the first one in the list hr = pEnumDevices->Next( 1000, // timeout in two seconds 1, // return just one storage device &pDevice, // pointer to storage device &uReturned ); // number obtained: one or zero if( FAILED(hr) || uReturned == 0 || pDevice == NULL ) goto LCleanup; pPropName = SysAllocString( L"Version" ); hr = pDevice->Get( pPropName, 0L, &var, NULL, NULL ); if( FAILED(hr) ) goto LCleanup; if( var.bstrVal != NULL ) { #ifdef UNICODE lstrcpy(szBIOSEnglish, var.bstrVal); #else WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), szBIOSEnglish, 199, NULL, NULL); #endif } VariantClear( &var ); LCleanup: if( NULL == szBIOSEnglish ) lstrcpy( szBIOSEnglish, TEXT("n/a") ); if(pPropName) SysFreeString(pPropName); if(pClassName) SysFreeString(pClassName); if(pDevice) pDevice->Release(); if(pEnumDevices) pEnumDevices->Release(); return; } /**************************************************************************** * * GetDXDebugLevels * ****************************************************************************/ VOID GetDXDebugLevels(SysInfo* pSysInfo) { pSysInfo->m_bIsD3D8DebugRuntimeAvailable = IsD3D8DebugRuntimeAvailable(); pSysInfo->m_bIsD3DDebugRuntime = IsD3DDebugRuntime(); pSysInfo->m_bIsDInput8DebugRuntimeAvailable = IsDInput8DebugRuntimeAvailable(); pSysInfo->m_bIsDInput8DebugRuntime = IsDInput8DebugRuntime(); pSysInfo->m_bIsDMusicDebugRuntimeAvailable = IsDMusicDebugRuntimeAvailable(); pSysInfo->m_bIsDMusicDebugRuntime = IsDMusicDebugRuntime(); pSysInfo->m_bIsDDrawDebugRuntime = IsDDrawDebugRuntime(); pSysInfo->m_bIsDPlayDebugRuntime = IsDPlayDebugRuntime(); pSysInfo->m_bIsDSoundDebugRuntime = IsDSoundDebugRuntime(); pSysInfo->m_nD3DDebugLevel = (int) GetProfileInt(TEXT("Direct3D"), TEXT("debug"), 0); pSysInfo->m_nDDrawDebugLevel = (int) GetProfileInt(TEXT("DirectDraw"),TEXT("debug"), 0); pSysInfo->m_nDIDebugLevel = GetDIDebugLevel(); pSysInfo->m_nDMusicDebugLevel = GetDMDebugLevel(); pSysInfo->m_nDPlayDebugLevel = (int) GetProfileInt(TEXT("DirectPlay"), TEXT("Debug"), 0); pSysInfo->m_nDSoundDebugLevel = GetDSDebugLevel(); } /**************************************************************************** * * IsD3D8DebugRuntimeAvailable * ****************************************************************************/ BOOL IsD3D8DebugRuntimeAvailable() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\d3d8d.dll")); if (GetFileAttributes(szPath) != -1) return TRUE; else return FALSE; } /**************************************************************************** * * IsD3DDebugRuntime * ****************************************************************************/ BOOL IsD3DDebugRuntime() { DWORD size; DWORD type; DWORD lData; HKEY hkey; BOOL rc; rc = FALSE; if (!RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_D3D, &hkey)) { size = sizeof(DWORD); if (!RegQueryValueEx(hkey, REGSTR_VAL_DDRAW_LOADDEBUGRUNTIME, NULL, &type, (LPBYTE)&lData, &size)) if (lData) rc = TRUE; RegCloseKey(hkey); } return rc; } /**************************************************************************** * * GetDIDebugLevel * ****************************************************************************/ int GetDIDebugLevel() { DWORD dwDebugBits; DWORD dwDebugBitsMax; LONG iGenerator; dwDebugBitsMax = 0; dwDebugBits = GetProfileInt(TEXT("Debug"), TEXT("dinput"), 0); if (dwDebugBits > dwDebugBitsMax) dwDebugBitsMax = dwDebugBits; enum { GENERATOR_KBD = 0, GENERATOR_MOUSE, GENERATOR_JOY, GENERATOR_HID, GENERATOR_MAX }; static TCHAR* szGeneratorNames[] = { TEXT("DInput.06"), TEXT("DInput.04"), TEXT("DInput.08"), TEXT("DInput.17"), }; static BOOL bGeneratorArray[4]; for (iGenerator = 0; iGenerator < GENERATOR_MAX; iGenerator++) { dwDebugBits = GetProfileInt(TEXT("Debug"), szGeneratorNames[iGenerator], 0); bGeneratorArray[iGenerator] = (dwDebugBits > 0); if (dwDebugBits > dwDebugBitsMax) dwDebugBitsMax = dwDebugBits; } if (dwDebugBitsMax & 0x20) // verbose return 5; if (dwDebugBitsMax & 0x02) // function entry return 4; if (dwDebugBitsMax & 0x01) // trace return 3; if (dwDebugBitsMax & 0x08) // benign return 2; if (dwDebugBitsMax & 0x10) // severe return 1; return 0; } /**************************************************************************** * * IsDInput8DebugRuntimeAvailable * ****************************************************************************/ BOOL IsDInput8DebugRuntimeAvailable() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\dinput8d.dll")); if (GetFileAttributes(szPath) != -1) return TRUE; else return FALSE; } /**************************************************************************** * * IsDInput8DebugRuntime * ****************************************************************************/ BOOL IsDInput8DebugRuntime() { DWORD size; DWORD type; TCHAR szData[MAX_PATH]; HKEY hkey; BOOL rc; rc = FALSE; if (!RegOpenKey(HKEY_CLASSES_ROOT, REGSTR_DINPUT_DLL, &hkey)) { size = sizeof(szData); if (!RegQueryValueEx(hkey, NULL, NULL, &type, (LPBYTE)&szData, &size)) { if (_tcsstr(szData, TEXT("dinput8d.dll"))) rc = TRUE; } RegCloseKey(hkey); } return rc; } /**************************************************************************** * * GetDMDebugLevel * ****************************************************************************/ int GetDMDebugLevel() { DWORD dwDMusicDebugLevel = 0; DWORD dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMBAND"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMCOMPOS"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMIME"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMLOADER"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMUSIC"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMUSIC16"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMUSIC32"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMSTYLE"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMSYNTH"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DMSCRIPT"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; if ((dw = GetProfileInt( TEXT("Debug"), TEXT("DSWAVE"), 0)) > dwDMusicDebugLevel) dwDMusicDebugLevel = dw; return dwDMusicDebugLevel; } /**************************************************************************** * * IsDMusicDebugRuntimeAvailable * ****************************************************************************/ BOOL IsDMusicDebugRuntimeAvailable() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\dmusicd.dll")); if (GetFileAttributes(szPath) != -1) return TRUE; else return FALSE; } /**************************************************************************** * * IsDMusicDebugRuntime * ****************************************************************************/ BOOL IsDMusicDebugRuntime() { DWORD size; DWORD type; TCHAR szData[MAX_PATH]; HKEY hkey; BOOL rc; rc = FALSE; if (!RegOpenKey(HKEY_CLASSES_ROOT, REGSTR_DMUSIC_DLL, &hkey)) { size = sizeof(szData); if (!RegQueryValueEx(hkey, NULL, NULL, &type, (LPBYTE)&szData, &size)) { if (_tcsstr(szData, TEXT("dmusicd.dll")) || _tcsstr(szData, TEXT("DMUSICD.DLL"))) { rc = TRUE; } } RegCloseKey(hkey); } return rc; } /**************************************************************************** * * GetDSDebugLevel * ****************************************************************************/ int GetDSDebugLevel() { DWORD dwSoundLevel = 0; // Pick up the DMusic DLL debug settings that are controlled on the // DSound page HRESULT hr; HINSTANCE hinst; LPKSPROPERTYSET pksps = NULL; hinst = LoadLibrary(TEXT("dsound.dll")); if (hinst != NULL) { if (SUCCEEDED(hr = DirectSoundPrivateCreate(&pksps))) { hr = PrvGetDebugInformation(pksps, NULL, &dwSoundLevel, NULL, NULL); pksps->Release(); } FreeLibrary(hinst); } return dwSoundLevel; } /**************************************************************************** * * IsFileDebug * ****************************************************************************/ BOOL IsFileDebug( TCHAR* szPath ) { UINT cb; DWORD dwHandle; BYTE FileVersionBuffer[4096]; VS_FIXEDFILEINFO* pVersion = NULL; cb = GetFileVersionInfoSize(szPath, &dwHandle/*ignored*/); if (cb > 0) { if (cb > sizeof(FileVersionBuffer)) cb = sizeof(FileVersionBuffer); if(GetFileVersionInfo(szPath, 0, cb, &FileVersionBuffer)) { if(VerQueryValue(&FileVersionBuffer, TEXT("\\"), (VOID**)&pVersion, &cb)) { if( pVersion ) { if( pVersion->dwFileFlags & VS_FF_DEBUG ) return TRUE; else return FALSE; } } } } return FALSE; } /**************************************************************************** * * IsDDrawDebugRuntime * ****************************************************************************/ BOOL IsDDrawDebugRuntime() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\ddraw.dll")); return IsFileDebug(szPath); } /**************************************************************************** * * IsDPlayDebugRuntime * ****************************************************************************/ BOOL IsDPlayDebugRuntime() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\dpnet.dll")); return IsFileDebug(szPath); } /**************************************************************************** * * IsDSoundDebugRuntime * ****************************************************************************/ BOOL IsDSoundDebugRuntime() { TCHAR szPath[MAX_PATH]; GetSystemDirectory(szPath, MAX_PATH); lstrcat(szPath, TEXT("\\dsound.dll")); return IsFileDebug(szPath); } /**************************************************************************** * * BIsDxDiag64Bit * ****************************************************************************/ BOOL BIsDxDiag64Bit(VOID) { #ifdef _WIN64 return TRUE; #else return FALSE; #endif } /**************************************************************************** * * GetFileSystemStoringD3D8Cache * ****************************************************************************/ VOID GetFileSystemStoringD3D8Cache( TCHAR* strFileSystemBuffer ) { TCHAR strPath[MAX_PATH + 16]; BOOL bFound = FALSE; GetSystemDirectory( strPath, MAX_PATH); lstrcat( strPath, TEXT("\\d3d8caps.dat") ); if (GetFileAttributes(strPath) != 0xffffffff) bFound = TRUE; if( !bFound && BIsPlatformNT() ) { // stolen from \dxg\d3d8\fw\fcache.cpp, OpenCacheFile(). HMODULE hShlwapi = NULL; typedef HRESULT (WINAPI * PSHGETSPECIALFOLDERPATH) (HWND, LPTSTR, int, BOOL); PSHGETSPECIALFOLDERPATH pSHGetSpecialFolderPath = NULL; hShlwapi = LoadLibrary( TEXT("SHELL32.DLL") ); if( NULL != hShlwapi ) { #ifdef UNICODE pSHGetSpecialFolderPath = (PSHGETSPECIALFOLDERPATH) GetProcAddress(hShlwapi,"SHGetSpecialFolderPathW"); #else pSHGetSpecialFolderPath = (PSHGETSPECIALFOLDERPATH) GetProcAddress(hShlwapi,"SHGetSpecialFolderPathA"); #endif if(pSHGetSpecialFolderPath) { HRESULT hr; // \Local Settings\Applicaiton Data (non roaming) hr = pSHGetSpecialFolderPath( NULL, strPath, CSIDL_LOCAL_APPDATA, FALSE ); if( SUCCEEDED(hr) ) { lstrcat( strPath, TEXT("\\d3d8caps.dat") ); if (GetFileAttributes(strPath) != 0xffffffff) bFound = TRUE; } } FreeLibrary(hShlwapi); } } if( bFound ) { DWORD dwVolumeSerialNumber; DWORD dwMaxComponentLength; DWORD dwFileSystemFlags; // Trim to root dir -- "x:\" strPath[3] = 0; BOOL bSuccess = GetVolumeInformation( strPath, NULL, 0, &dwVolumeSerialNumber, &dwMaxComponentLength, &dwFileSystemFlags, strFileSystemBuffer, MAX_PATH ); if( !bSuccess ) lstrcpy( strFileSystemBuffer, TEXT("Unknown") ); } else { lstrcpy( strFileSystemBuffer, TEXT("n/a") ); } return; } /**************************************************************************** * * IsNetMeetingRunning * ****************************************************************************/ BOOL IsNetMeetingRunning() { HWND hNetMeeting = FindWindow( TEXT("MPWClass"), NULL ); return( hNetMeeting != NULL ); }