2019-08-23 11:56:54 -07:00
|
|
|
namespace System
|
|
|
|
{
|
|
|
|
class OperatingSystem
|
|
|
|
{
|
2020-05-06 05:31:05 -07:00
|
|
|
#if BF_PLATFORM_WINDOWS
|
|
|
|
const String Arch32 = "32-bit Edition";
|
|
|
|
const String Arch64 = "64-bit Edition";
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
const uint8 VER_EQUAL = 1;
|
|
|
|
const uint8 VER_PRODUCT_TYPE = 0x00000080;
|
|
|
|
const uint8 VER_NT_WORKSTATION = 0x00000001;
|
|
|
|
const uint8 PROCESSOR_ARCHITECTURE_AMD64 = 9;
|
|
|
|
const uint8 SM_SERVERR2 = 89;
|
2020-05-05 18:28:38 +02:00
|
|
|
|
|
|
|
[CRepr]
|
2020-05-06 05:31:05 -07:00
|
|
|
struct OSVersionInfoA
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
public uint32 dwOSVersionInfoSize;
|
|
|
|
public uint32 dwMajorVersion;
|
|
|
|
public uint32 dwMinorVersion;
|
|
|
|
public uint32 dwBuildNumber;
|
|
|
|
public uint32 dwPlatformId;
|
|
|
|
public uint8[128] szCSDVersion; // Maintenance UnicodeString for PSS usage
|
|
|
|
|
|
|
|
}
|
|
|
|
[CRepr]
|
2020-05-06 05:31:05 -07:00
|
|
|
struct OSVersionInfoExA : OSVersionInfoA
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
public uint16 wServicePackMajor;
|
|
|
|
public uint16 wServicePackMinor;
|
|
|
|
public uint16 wSuiteMask;
|
|
|
|
public uint8 wProductType;
|
|
|
|
public uint8 wReserved;
|
|
|
|
}
|
|
|
|
|
|
|
|
[CRepr]
|
2020-05-06 05:31:05 -07:00
|
|
|
struct SystemInfo
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
public uint16 wProcessorArchitecture;
|
|
|
|
public uint16 wReserved;
|
|
|
|
public uint32 dwPageSize;
|
|
|
|
public void* lpMinimumApplicationAddress;
|
|
|
|
public void* lpMaximumApplicationAddress;
|
|
|
|
public uint32* dwActiveProcessorMask;
|
|
|
|
public uint32 dwNumberOfProcessors;
|
|
|
|
public uint32 dwProcessorType;
|
|
|
|
public uint32 dwAllocationGranularity;
|
|
|
|
public int16 wProcessorLevel;
|
|
|
|
public int16 wProcessorRevision;
|
|
|
|
}
|
|
|
|
|
|
|
|
[CRepr]
|
2020-05-06 05:31:05 -07:00
|
|
|
struct WKSTA_INFO_100
|
2020-05-05 18:28:38 +02:00
|
|
|
{
|
|
|
|
public uint32 wki100_platform_id;
|
|
|
|
public uint32 wki100_computername;
|
|
|
|
public uint32 wki100_langroup;
|
|
|
|
public uint32 wki100_ver_major;
|
|
|
|
public uint32 wki100_ver_minor;
|
|
|
|
}
|
|
|
|
typealias LPWKSTA_INFO_100 = WKSTA_INFO_100*;
|
|
|
|
|
|
|
|
[CRepr]
|
2020-05-06 05:31:05 -07:00
|
|
|
struct VSFixedFileInfo
|
2020-05-05 18:28:38 +02:00
|
|
|
{
|
|
|
|
public uint32 dwSignature; // e.g. $feef04bd
|
|
|
|
public uint32 dwStrucVersion; // e.g. $00000042 = "0.42"
|
|
|
|
public uint32 dwFileVersionMS; // e.g. $00030075 = "3.75"
|
|
|
|
public uint32 dwFileVersionLS; // e.g. $00000031 = "0.31"
|
|
|
|
public uint32 dwProductVersionMS; // e.g. $00030010 = "3.10"
|
|
|
|
public uint32 dwProductVersionLS; // e.g. $00000031 = "0.31"
|
|
|
|
public uint32 dwFileFlagsMask; // = $3F for version "0.42"
|
|
|
|
public uint32 dwFileFlags; // e.g. VFF_DEBUG | VFF_PRERELEASE
|
|
|
|
public uint32 dwFileOS; // e.g. VOS_DOS_WINDOWS16
|
|
|
|
public uint32 dwFileType; // e.g. VFT_DRIVER
|
|
|
|
public uint32 dwFileSubtype; // e.g. VFT2_DRV_KEYBOARD
|
|
|
|
public uint32 dwFileDateMS; // e.g. 0
|
|
|
|
public uint32 dwFileDateLS; // e.g. 0
|
|
|
|
}
|
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[CLink, StdCall]
|
|
|
|
extern static bool GetVersionExA(OSVersionInfoExA* lpVersionInformation);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[CLink, StdCall]
|
|
|
|
extern static bool VerifyVersionInfoA(OSVersionInfoExA* lpVersionInformation, uint32 dwTypeMask, uint64 dwlConditionMask);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[CLink, StdCall]
|
|
|
|
extern static uint64 VerSetConditionMask(uint64 dwlConditionMask, uint32 dwTypeBitMask, uint8 dwConditionMask);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[CLink, StdCall]
|
|
|
|
extern static void GetNativeSystemInfo(SystemInfo* lpSystemInformation);
|
|
|
|
[CLink, StdCall]
|
|
|
|
extern static void GetSystemInfo(SystemInfo* lpSystemInfo);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
|
|
|
[Import("netapi32.lib"), CLink, StdCall]
|
2020-05-06 05:31:05 -07:00
|
|
|
extern static uint32 NetWkstaGetInfo(char16* ServerName, uint32 Level, LPWKSTA_INFO_100* BufPtr);
|
2020-05-05 18:28:38 +02:00
|
|
|
[Import("netapi32.lib"), CLink, StdCall]
|
2020-05-06 05:31:05 -07:00
|
|
|
extern static int32 NetApiBufferFree(LPWKSTA_INFO_100 BufPtr);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[CLink, StdCall]
|
|
|
|
extern static uint32 GetFileVersionInfoSizeA(char8* lptstrFilename, uint32* lpdwHandle);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[Import("version.lib"), CLink, StdCall]
|
|
|
|
extern static bool GetFileVersionInfoA(char8* lptstrFilename, uint32* dwHandle, uint32 dwLen, void* lpData);
|
|
|
|
[Import("version.lib"), CLink, StdCall]
|
|
|
|
extern static bool VerQueryValueA(void* pBlock, char8* lpSubBlock, void** lplpBuffer, uint32* puLen);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
[Import("user32.lib"), CLink, StdCall]
|
|
|
|
extern static int GetSystemMetrics(int nIndex);
|
2020-05-05 18:28:38 +02:00
|
|
|
#endif
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
public Version Version;
|
2020-05-05 18:28:38 +02:00
|
|
|
public PlatformID Platform;
|
|
|
|
public String Name = new .() ~ delete _;
|
2020-05-06 05:31:05 -07:00
|
|
|
#if BF_PLATFORM_LINUX
|
2020-05-05 18:28:38 +02:00
|
|
|
public String PrettyName = new .() ~ delete _;
|
2020-05-06 05:31:05 -07:00
|
|
|
#endif
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
public this()
|
|
|
|
{
|
2020-05-06 05:31:05 -07:00
|
|
|
#if BF_PLATFORM_WINDOWS
|
2020-05-05 18:28:38 +02:00
|
|
|
bool isWinSrv()
|
|
|
|
{
|
|
|
|
OSVersionInfoExA osvi = .();
|
|
|
|
uint64 dwlCondMask;
|
|
|
|
|
|
|
|
osvi.wProductType = VER_NT_WORKSTATION;
|
|
|
|
|
|
|
|
dwlCondMask = VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
|
|
|
|
|
|
|
|
return VerifyVersionInfoA(&osvi, VER_PRODUCT_TYPE, dwlCondMask) == false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GetProductVersion(out uint32 major, out uint32 minor, out uint32 build)
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
major = 0;
|
|
|
|
minor = 0;
|
|
|
|
build = 0;
|
2020-05-06 05:47:37 -07:00
|
|
|
uint32 verSize, wnd;
|
2020-05-05 18:28:38 +02:00
|
|
|
VSFixedFileInfo* FI = &VSFixedFileInfo();
|
|
|
|
|
2020-05-06 05:47:37 -07:00
|
|
|
uint32 infoSize = GetFileVersionInfoSizeA("kernel32.dll", &wnd);
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:47:37 -07:00
|
|
|
if (infoSize != 0)
|
|
|
|
{
|
|
|
|
void* verBuf = new uint8[infoSize]*;
|
|
|
|
defer delete verBuf;
|
2020-05-05 18:28:38 +02:00
|
|
|
|
2020-05-06 05:47:37 -07:00
|
|
|
if (GetFileVersionInfoA("kernel32.dll", &wnd, infoSize, verBuf))
|
|
|
|
{
|
|
|
|
if (VerQueryValueA(verBuf, "\\", (void**)(&FI), &verSize))
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
major = FI.dwProductVersionMS >> 16;
|
|
|
|
minor = (uint16)FI.dwProductVersionMS;
|
|
|
|
build = FI.dwProductVersionLS >> 16;
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GetNetWkstaMajorMinor(out uint32 major, out uint32 minor)
|
|
|
|
{
|
|
|
|
LPWKSTA_INFO_100 LBuf = null;
|
|
|
|
bool result = NetWkstaGetInfo(null, 100, &LBuf) == 0;
|
|
|
|
|
2020-05-06 05:47:37 -07:00
|
|
|
if (result)
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
major = LBuf.wki100_ver_major;
|
|
|
|
minor = LBuf.wki100_ver_minor;
|
2020-05-06 05:47:37 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
major = 0;
|
|
|
|
minor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LBuf != null)
|
|
|
|
NetApiBufferFree(LBuf);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemInfo SysInfo = .();
|
|
|
|
OSVersionInfoExA VerInfo = .();
|
|
|
|
uint32 MajorNum, MinorNum, BuildNum;
|
|
|
|
|
|
|
|
VerInfo.dwOSVersionInfoSize = sizeof(OSVersionInfoExA);
|
|
|
|
GetVersionExA(&VerInfo);
|
|
|
|
|
|
|
|
Platform = .Win32NT;
|
|
|
|
Version.Major = VerInfo.dwMajorVersion;
|
|
|
|
Version.Minor = VerInfo.dwMinorVersion;
|
|
|
|
Version.Build = VerInfo.dwBuildNumber;
|
|
|
|
Version.Revision = VerInfo.wServicePackMajor;
|
|
|
|
|
|
|
|
if (Version.Check(5, 1)) // GetNativeSystemInfo not supported on Windows 2000
|
|
|
|
GetNativeSystemInfo(&SysInfo);
|
|
|
|
|
2020-05-06 05:47:37 -07:00
|
|
|
if ((Version.Major > 6) || ((Version.Major == 6) && (Version.Minor > 1)))
|
|
|
|
{
|
|
|
|
if (GetProductVersion(out MajorNum, out MinorNum, out BuildNum))
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
Version.Major = MajorNum;
|
|
|
|
Version.Minor = MinorNum;
|
|
|
|
Version.Build = BuildNum;
|
2020-05-06 05:47:37 -07:00
|
|
|
}
|
|
|
|
else if (GetNetWkstaMajorMinor(out MajorNum, out MinorNum))
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
Version.Major = MajorNum;
|
|
|
|
Version.Minor = MinorNum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Name.Append("Windows");
|
|
|
|
|
2020-05-06 05:31:05 -07:00
|
|
|
switch(Version.Major)
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
case 10:
|
2020-05-06 05:31:05 -07:00
|
|
|
switch(Version.Minor)
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
case 0: Name.Append(!isWinSrv() ? " 10" : " Server 2016");
|
|
|
|
// Server 2019 is also 10.0
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
2020-05-06 05:31:05 -07:00
|
|
|
switch(Version.Minor)
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
case 0: Name.Append(VerInfo.wProductType == VER_NT_WORKSTATION ? " Vista" : " Server 2008");
|
|
|
|
case 1: Name.Append(VerInfo.wProductType == VER_NT_WORKSTATION ? " 7" : " Server 2008 R2");
|
|
|
|
case 2: Name.Append(VerInfo.wProductType == VER_NT_WORKSTATION ? " 8" : " Server 2012");
|
|
|
|
case 3: Name.Append(!isWinSrv() ? " 8.1" : " Server 2012 R2");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5:
|
2020-05-06 05:31:05 -07:00
|
|
|
switch(Version.Minor)
|
|
|
|
{
|
2020-05-05 18:28:38 +02:00
|
|
|
case 0: Name.Append(" 2000");
|
|
|
|
case 1: Name.Append(" XP");
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
if ((VerInfo.wProductType == VER_NT_WORKSTATION) &&
|
|
|
|
(SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)) {
|
|
|
|
Name.Append(" XP");
|
|
|
|
} else {
|
|
|
|
Name.Append(GetSystemMetrics(SM_SERVERR2) == 0 ? " Server 2003" : " Server 2003 R2");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-05-06 05:31:05 -07:00
|
|
|
#elif BF_PLATFORM_LINUX
|
2019-08-23 11:56:54 -07:00
|
|
|
Version.Major = 5; //TODO:
|
2020-05-05 18:28:38 +02:00
|
|
|
Platform = PlatformID.Unix;
|
2020-05-06 05:31:05 -07:00
|
|
|
#else // MACOS and ANDROID
|
2020-05-05 18:28:38 +02:00
|
|
|
Version.Major = 5; //TODO:
|
|
|
|
Platform = PlatformID.MacOSX;
|
2020-05-06 05:31:05 -07:00
|
|
|
#endif
|
2020-05-05 18:28:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public override void ToString(String outVar)
|
|
|
|
{
|
2020-05-06 05:31:05 -07:00
|
|
|
#if BF_PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
#if BF_64_BIT
|
2020-05-05 18:28:38 +02:00
|
|
|
String arch = Arch64;
|
2020-05-06 05:31:05 -07:00
|
|
|
#else
|
2020-05-05 18:28:38 +02:00
|
|
|
String arch = Arch32;
|
2020-05-06 05:31:05 -07:00
|
|
|
#endif
|
|
|
|
if (Version.Revision == 0)
|
2020-05-05 18:28:38 +02:00
|
|
|
outVar.AppendF("{} (Version {}.{}, Build {}, {})", Name, Version.Major, Version.Minor, Version.Build, arch);
|
2020-05-06 05:31:05 -07:00
|
|
|
else
|
2020-05-05 18:28:38 +02:00
|
|
|
outVar.AppendF("{} Service Pack {} (Version {}.{}, Build {}, {})", Name, Version.Revision, Version.Major, Version.Minor, Version.Build, arch);
|
2020-05-06 05:31:05 -07:00
|
|
|
#elif BF_PLATFORM_LINUX
|
2020-05-05 18:28:38 +02:00
|
|
|
outVar.AppendF("{} {} (Version {}.{}.{})", PrettyName, Name, Version.Major, Version.Minor, Version.Revision);
|
2020-05-06 05:31:05 -07:00
|
|
|
#else // MACOS and ANDROID
|
2020-05-05 18:28:38 +02:00
|
|
|
outVar.AppendF("{} (Version {}.{}.{})", Name, Version.Major, Version.Minor, Version.Revision);
|
2020-05-06 05:31:05 -07:00
|
|
|
#endif
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|