1- // COPYRIGHT 2015 by the Open Rails project.
2- //
1+ // COPYRIGHT 2009 - 2023 by the Open Rails project.
2+ //
33// This file is part of Open Rails.
4- //
4+ //
55// Open Rails is free software: you can redistribute it and/or modify
66// it under the terms of the GNU General Public License as published by
77// the Free Software Foundation, either version 3 of the License, or
88// (at your option) any later version.
9- //
9+ //
1010// Open Rails is distributed in the hope that it will be useful,
1111// but WITHOUT ANY WARRANTY; without even the implied warranty of
1212// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313// GNU General Public License for more details.
14- //
14+ //
1515// You should have received a copy of the GNU General Public License
1616// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
1717
18- using Microsoft . Win32 ;
1918using System ;
20- using System . Diagnostics ;
2119using System . IO ;
20+ using System . Linq ;
2221using System . Management ;
2322using System . Runtime . InteropServices ;
24- using System . Text ;
25- using System . Windows . Forms ;
26- using Microsoft . Xna . Framework . Graphics ;
23+ using System . Text . RegularExpressions ;
24+ using System . Collections . Generic ;
25+ using System . Globalization ;
26+ using System . Diagnostics ;
27+ using SharpDX . DXGI ;
2728
2829namespace ORTS . Common
2930{
3031 public static class SystemInfo
3132 {
32- public static void WriteSystemDetails ( TextWriter output )
33+ static readonly Regex NameAndVersionRegex = new Regex ( "^(.*?) +([0-9.]+)$" ) ;
34+ static readonly NativeStructs . MemoryStatusExtended MemoryStatusExtended = new NativeStructs . MemoryStatusExtended ( )
3335 {
34- output . WriteLine ( "Date/time = {0} ({1:u})" , DateTime . Now , DateTime . UtcNow ) ;
35- WriteEnvironment ( output ) ;
36- WriteAvailableRuntimes ( output ) ;
37- output . WriteLine ( "Runtime = {0} ({1}bit)" , Environment . Version , IntPtr . Size * 8 ) ;
38- WriteGraphicsAdapter ( output ) ;
39- }
36+ Size = 64
37+ } ;
4038
41- static void WriteEnvironment ( TextWriter output )
39+ static SystemInfo ( )
4240 {
43- var buffer = new NativeStructs . MemoryStatusExtended { Size = 64 } ;
44- NativeMethods . GlobalMemoryStatusEx ( buffer ) ;
45- try
41+ Application = new Platform
4642 {
47- foreach ( ManagementObject bios in new ManagementClass ( "Win32_BIOS" ) . GetInstances ( ) )
48- {
49- output . WriteLine ( "BIOS = {0} ({1})" , ( string ) bios [ "Description" ] , ( string ) bios [ "Manufacturer" ] ) ;
50- }
51- }
52- catch ( Exception error )
53- {
54- Trace . WriteLine ( error ) ;
55- }
56- try
57- {
58- foreach ( ManagementObject processor in new ManagementClass ( "Win32_Processor" ) . GetInstances ( ) )
59- {
60- output . Write ( "Processor = {0} ({2} threads, {1} cores, {3:F1} GHz)" , ( string ) processor [ "Name" ] , ( uint ) processor [ "NumberOfCores" ] , ( uint ) processor [ "NumberOfLogicalProcessors" ] , ( float ) ( uint ) processor [ "MaxClockSpeed" ] / 1000 ) ;
61- foreach ( ManagementObject cpuCache in processor . GetRelated ( "Win32_CacheMemory" ) )
62- {
63- output . Write ( " ({0} {1:F0} KB)" , ( string ) cpuCache [ "Purpose" ] , ( float ) ( uint ) cpuCache [ "InstalledSize" ] ) ;
64- }
65- output . WriteLine ( ) ;
66- }
67- }
68- catch ( Exception error )
69- {
70- Trace . WriteLine ( error ) ;
71- }
72- output . WriteLine ( "Memory = {0:F1} GB" , ( float ) buffer . TotalPhysical / 1024 / 1024 / 1024 ) ;
73- try
74- {
75- foreach ( ManagementObject display in new ManagementClass ( "Win32_VideoController" ) . GetInstances ( ) )
76- {
77- // ? used as display["AdapterRAM"] may be null on a virtual machine (e.g. VMWare)
78- output . WriteLine ( "Video = {0} ({1:F1} GB RAM){2}" , ( string ) display [ "Description" ] , ( float ? ) ( uint ? ) display [ "AdapterRAM" ] / 1024 / 1024 / 1024 , GetPnPDeviceDrivers ( display ) ) ;
79- }
80- }
81- catch ( Exception error )
82- {
83- Trace . WriteLine ( error ) ;
84- }
85- try
86- {
87- foreach ( var screen in Screen . AllScreens )
88- {
89- output . WriteLine ( "Display = {0} ({3} x {4}, {5}-bit{6}, {1} x {2})" , screen . DeviceName , screen . Bounds . X , screen . Bounds . Y , screen . Bounds . Width , screen . Bounds . Height , screen . BitsPerPixel , screen . Primary ? ", primary" : "" ) ;
90- }
91- }
92- catch ( Exception error )
43+ Name = System . Windows . Forms . Application . ProductName ,
44+ Version = VersionInfo . VersionOrBuild ,
45+ Architecture = RuntimeInformation . ProcessArchitecture . ToString ( ) ,
46+ } ;
47+
48+ var runtime = NameAndVersionRegex . Match ( RuntimeInformation . FrameworkDescription . Trim ( ) ) ;
49+ Runtime = new Platform
9350 {
94- Trace . WriteLine ( error ) ;
95- }
51+ Name = runtime . Groups [ 1 ] . Value ,
52+ Version = runtime . Groups [ 2 ] . Value ,
53+ } ;
54+
9655 try
9756 {
98- foreach ( ManagementObject sound in new ManagementClass ( "Win32_SoundDevice" ) . GetInstances ( ) )
57+ // Almost nothing will correctly identify Windows 11 at this point, so we have to use WMI.
58+ var operatingSystem = new ManagementClass ( "Win32_OperatingSystem" ) . GetInstances ( ) . Cast < ManagementObject > ( ) . First ( ) ;
59+ OperatingSystem = new Platform
9960 {
100- output . WriteLine ( "Sound = {0}{1}" , ( string ) sound [ "Description" ] , GetPnPDeviceDrivers ( sound ) ) ;
101- }
61+ Name = ( string ) operatingSystem [ "Caption" ] ,
62+ Version = ( string ) operatingSystem [ "Version" ] ,
63+ Architecture = RuntimeInformation . OSArchitecture . ToString ( ) ,
64+ Language = CultureInfo . CurrentUICulture . IetfLanguageTag ,
65+ Languages = ( string [ ] ) operatingSystem [ "MUILanguages" ] ,
66+ } ;
10267 }
103- catch ( Exception error )
68+ catch ( ManagementException error )
10469 {
10570 Trace . WriteLine ( error ) ;
10671 }
72+
73+ NativeMethods . GlobalMemoryStatusEx ( MemoryStatusExtended ) ;
74+ InstalledMemoryMB = ( int ) ( MemoryStatusExtended . TotalPhysical / 1024 / 1024 ) ;
75+
10776 try
10877 {
109- foreach ( ManagementObject disk in new ManagementClass ( "Win32_LogicalDisk " ) . GetInstances ( ) )
78+ CPUs = new ManagementClass ( "Win32_Processor " ) . GetInstances ( ) . Cast < ManagementObject > ( ) . Select ( processor => new CPU
11079 {
111- output . Write ( "Disk = {0} ({1}, {2}" , ( string ) disk [ "Name" ] , ( string ) disk [ "Description" ] , ( string ) disk [ "FileSystem" ] ) ;
112- if ( disk [ "Size" ] != null && disk [ "FreeSpace" ] != null )
113- output . WriteLine ( ", {0:F1} GB, {1:F1} GB free)" , ( float ) ( ulong ) disk [ "Size" ] / 1024 / 1024 / 1024 , ( float ) ( ulong ) disk [ "FreeSpace" ] / 1024 / 1024 / 1024 ) ;
114- else
115- output . WriteLine ( ")" ) ;
116- }
80+ Name = ( string ) processor [ "Name" ] ,
81+ Manufacturer = ( string ) processor [ "Manufacturer" ] ,
82+ ThreadCount = ( uint ) processor [ "ThreadCount" ] ,
83+ MaxClockMHz = ( uint ) processor [ "MaxClockSpeed" ] ,
84+ } ) . ToList ( ) ;
11785 }
118- catch ( Exception error )
86+ catch ( ManagementException error )
11987 {
12088 Trace . WriteLine ( error ) ;
12189 }
90+
91+ // The WMI data for AdapterRAM is unreliable, so we have to use DXGI to get the real numbers.
92+ // Alas, DXGI doesn't give us the manufacturer name for the adapter, so we combine it with WMI.
93+ var descriptions = new Factory1 ( ) . Adapters . Select ( adapter => adapter . Description ) . ToArray ( ) ;
12294 try
12395 {
124- foreach ( ManagementObject os in new ManagementClass ( "Win32_OperatingSystem " ) . GetInstances ( ) )
96+ GPUs = new ManagementClass ( "Win32_VideoController " ) . GetInstances ( ) . Cast < ManagementObject > ( ) . Select ( adapter => new GPU
12597 {
126- output . WriteLine ( "OS = {0} {1} ({2})" , ( string ) os [ "Caption" ] , ( string ) os [ "OSArchitecture" ] , ( string ) os [ "Version" ] ) ;
127- }
98+ Name = ( string ) adapter [ "Name" ] ,
99+ Manufacturer = ( string ) adapter [ "AdapterCompatibility" ] ,
100+ MemoryMB = ( uint ) ( ( long ) descriptions . FirstOrDefault ( desc => desc . Description == ( string ) adapter [ "Name" ] ) . DedicatedVideoMemory / 1024 / 1024 ) ,
101+ } ) . ToList ( ) ;
128102 }
129- catch ( Exception error )
103+ catch ( ManagementException error )
130104 {
131105 Trace . WriteLine ( error ) ;
132106 }
133- }
134107
135- static string GetPnPDeviceDrivers ( ManagementObject device )
136- {
137- var output = new StringBuilder ( ) ;
138- foreach ( ManagementObject pnpDevice in device . GetRelated ( "Win32_PnPEntity" ) )
139- {
140- foreach ( ManagementObject dataFile in pnpDevice . GetRelated ( "CIM_DataFile" ) )
108+ var featureLevels = new uint [ ] {
109+ NativeMethods . D3D_FEATURE_LEVEL_12_2 ,
110+ NativeMethods . D3D_FEATURE_LEVEL_12_1 ,
111+ NativeMethods . D3D_FEATURE_LEVEL_12_0 ,
112+ NativeMethods . D3D_FEATURE_LEVEL_11_1 ,
113+ NativeMethods . D3D_FEATURE_LEVEL_11_0 ,
114+ NativeMethods . D3D_FEATURE_LEVEL_10_1 ,
115+ NativeMethods . D3D_FEATURE_LEVEL_10_0 ,
116+ NativeMethods . D3D_FEATURE_LEVEL_9_3 ,
117+ NativeMethods . D3D_FEATURE_LEVEL_9_2 ,
118+ NativeMethods . D3D_FEATURE_LEVEL_9_1 ,
119+ } ;
120+ foreach ( var featureLevel in featureLevels )
121+ {
122+ var levels = new uint [ ] { featureLevel } ;
123+ try
141124 {
142- output . AppendFormat ( " ({0} {1})" , ( string ) dataFile [ "FileName" ] , ( string ) dataFile [ "Version" ] ) ;
125+ var rv = NativeMethods . D3D11CreateDevice ( IntPtr . Zero , NativeMethods . D3D_DRIVER_TYPE_HARDWARE , IntPtr . Zero , 0 , levels , levels . Length , NativeMethods . D3D11_SDK_VERSION , IntPtr . Zero , out uint level , IntPtr . Zero ) ;
126+ if ( level == featureLevel ) Direct3DFeatureLevels . Add ( string . Format ( "{0}_{1}" , level >> 12 & 0xF , level >> 8 & 0xF ) ) ;
143127 }
128+ catch ( EntryPointNotFoundException ) { }
129+ catch ( DllNotFoundException ) { }
144130 }
145- return output . ToString ( ) ;
146131 }
147132
148- static void WriteAvailableRuntimes ( TextWriter output )
133+ public static readonly Platform Application ;
134+ public static readonly Platform Runtime ;
135+ public static readonly Platform OperatingSystem ;
136+ public static readonly int InstalledMemoryMB ;
137+ public static readonly List < CPU > CPUs = new List < CPU > ( ) ;
138+ public static readonly List < GPU > GPUs = new List < GPU > ( ) ;
139+ public static readonly List < string > Direct3DFeatureLevels = new List < string > ( ) ;
140+
141+ public static void WriteSystemDetails ( TextWriter output )
149142 {
150- output . Write ( "Runtimes =" ) ;
151- try
152- {
153- // This remote access is necessary to ensure we get the correct bitness view of the registry.
154- using ( var frameworksKey = RegistryKey . OpenRemoteBaseKey ( RegistryHive . LocalMachine , "" ) . OpenSubKey ( @"SOFTWARE\Microsoft\NET Framework Setup\NDP" , false ) )
155- {
156- foreach ( var versionKeyName in frameworksKey . GetSubKeyNames ( ) )
157- {
158- if ( ! versionKeyName . StartsWith ( "v" ) )
159- continue ;
160-
161- using ( var versionKey = frameworksKey . OpenSubKey ( versionKeyName ) )
162- {
163- var fullVersion = WriteInstalledRuntimes ( output , versionKeyName , versionKey ) ;
164- if ( fullVersion != "" )
165- continue ;
166-
167- foreach ( var skuKeyName in versionKey . GetSubKeyNames ( ) )
168- {
169- using ( var skuKey = versionKey . OpenSubKey ( skuKeyName ) )
170- {
171- WriteInstalledRuntimes ( output , versionKeyName + " " + skuKeyName , skuKey ) ;
172- }
173- }
174- }
175- }
176- }
177- output . WriteLine ( ) ;
178- }
179- catch ( Exception error )
180- {
181- Trace . WriteLine ( error ) ;
182- }
143+ output . WriteLine ( "Date/time = {0} ({1:u})" ,
144+ DateTime . Now , DateTime . UtcNow ) ;
145+ output . WriteLine ( "Application = {0} {1} ({2})" , Application . Name , Application . Version , Application . Architecture ) ;
146+ output . WriteLine ( "Runtime = {0} {1}" , Runtime . Name , Runtime . Version ) ;
147+ output . WriteLine ( "System = {0} {1} ({2}; {3}; {4})" , OperatingSystem . Name , OperatingSystem . Version , OperatingSystem . Architecture , OperatingSystem . Language , string . Join ( "," , OperatingSystem . Languages ?? new string [ 0 ] ) ) ;
148+ output . WriteLine ( "Memory = {0:N0} MB" , InstalledMemoryMB ) ;
149+ foreach ( var cpu in CPUs ) output . WriteLine ( "CPU = {0} ({1}; {2} threads; {3:N0} MHz)" , cpu . Name , cpu . Manufacturer , cpu . ThreadCount , cpu . MaxClockMHz ) ;
150+ foreach ( var gpu in GPUs ) output . WriteLine ( "GPU = {0} ({1}; {2:N0} MB)" , gpu . Name , gpu . Manufacturer , gpu . MemoryMB ) ;
151+ output . WriteLine ( "Direct3D = {0}" , string . Join ( "," , Direct3DFeatureLevels ) ) ;
183152 }
184153
185- static string WriteInstalledRuntimes ( TextWriter output , string versionKeyName , RegistryKey versionKey )
154+ public struct Platform
186155 {
187- var installed = SafeReadKey ( versionKey , "Install" , - 1 ) ;
188- var fullVersion = SafeReadKey ( versionKey , "Version" , "" ) ;
189- var servicePack = SafeReadKey ( versionKey , "SP" , - 1 ) ;
190-
191- if ( installed == 1 && servicePack != - 1 )
192- {
193- output . Write ( " {0} SP{2} " , versionKeyName . Substring ( 1 ) , fullVersion , servicePack ) ;
194- }
195- else if ( installed == 1 )
196- {
197- output . Write ( " {0} " , versionKeyName . Substring ( 1 ) , fullVersion ) ;
198- }
199- return fullVersion ;
156+ public string Name ;
157+ public string Version ;
158+ public string Architecture ;
159+ public string Language ;
160+ public string [ ] Languages ;
200161 }
201162
202- static void WriteGraphicsAdapter ( TextWriter output )
163+ public struct CPU
203164 {
204- try {
205- foreach ( var adapter in GraphicsAdapter . Adapters )
206- {
207- try
208- {
209- output . WriteLine ( "{0} = {1}" , adapter . DeviceName , adapter . Description ) ;
210- }
211- catch ( Exception ) { }
212- }
213- }
214- catch ( Exception error )
215- {
216- output . WriteLine ( error ) ;
217- }
165+ public string Name ;
166+ public string Manufacturer ;
167+ public uint ThreadCount ;
168+ public uint MaxClockMHz ;
218169 }
219170
220- static T SafeReadKey < T > ( RegistryKey key , string name , T defaultValue )
171+ public struct GPU
221172 {
222- try
223- {
224- return ( T ) key . GetValue ( name , defaultValue ) ;
225- }
226- catch
227- {
228- return defaultValue ;
229- }
173+ public string Name ;
174+ public string Manufacturer ;
175+ public uint MemoryMB ;
230176 }
231177
232178 static class NativeStructs
@@ -250,6 +196,35 @@ static class NativeMethods
250196 {
251197 [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
252198 public static extern bool GlobalMemoryStatusEx ( [ In , Out ] NativeStructs . MemoryStatusExtended buffer ) ;
199+
200+ public const uint D3D11_SDK_VERSION = 7 ;
201+
202+ public const uint D3D_DRIVER_TYPE_HARDWARE = 1 ;
203+
204+ public const uint D3D_FEATURE_LEVEL_9_1 = 0x9100 ;
205+ public const uint D3D_FEATURE_LEVEL_9_2 = 0x9200 ;
206+ public const uint D3D_FEATURE_LEVEL_9_3 = 0x9300 ;
207+ public const uint D3D_FEATURE_LEVEL_10_0 = 0xA000 ;
208+ public const uint D3D_FEATURE_LEVEL_10_1 = 0xA100 ;
209+ public const uint D3D_FEATURE_LEVEL_11_0 = 0xB000 ;
210+ public const uint D3D_FEATURE_LEVEL_11_1 = 0xB100 ;
211+ public const uint D3D_FEATURE_LEVEL_12_0 = 0xC000 ;
212+ public const uint D3D_FEATURE_LEVEL_12_1 = 0xC100 ;
213+ public const uint D3D_FEATURE_LEVEL_12_2 = 0xC200 ;
214+
215+ [ DllImport ( "d3d11.dll" , ExactSpelling = true ) ]
216+ public static extern uint D3D11CreateDevice (
217+ IntPtr adapter ,
218+ uint driverType ,
219+ IntPtr software ,
220+ uint flags ,
221+ [ In ] uint [ ] featureLevels ,
222+ int featureLevelCount ,
223+ uint sdkVersion ,
224+ IntPtr device ,
225+ out uint featureLevel ,
226+ IntPtr immediateContext
227+ ) ;
253228 }
254229 }
255230}
0 commit comments