@@ -130,6 +130,11 @@ private static (long? FrequencyMHz, string? MemoryType) GetLinuxOrWindowsMemoryD
130130 {
131131 try
132132 {
133+ if ( OsDetector . IsWindows7OrLater ( ) )
134+ {
135+ return GetWindowsSmbiosMemoryDetails ( ) ;
136+ }
137+
133138 // Try reading /sys/devices/system/edac/mc/ on Linux
134139 if ( Directory . Exists ( "/sys/devices/system/edac/mc" ) )
135140 {
@@ -156,6 +161,97 @@ private static (long? FrequencyMHz, string? MemoryType) GetLinuxOrWindowsMemoryD
156161 return ( null , null ) ;
157162 }
158163
164+ [ SupportedOSPlatform ( "windows5.1.2600" ) ]
165+ private static ( long ? FrequencyMHz , string ? MemoryType ) GetWindowsSmbiosMemoryDetails ( )
166+ {
167+ try
168+ {
169+ const uint rsMb = 0x52534D42 ; // 'RSMB'
170+ uint bufferSize = NativeMethods . GetSystemFirmwareTable ( rsMb , 0 , IntPtr . Zero , 0 ) ;
171+ if ( bufferSize == 0 )
172+ return ( null , null ) ;
173+
174+ byte [ ] buffer = new byte [ bufferSize ] ;
175+ if ( NativeMethods . GetSystemFirmwareTable ( rsMb , 0 , buffer , bufferSize ) == 0 )
176+ return ( null , null ) ;
177+
178+ // SMBIOS table header: Data at offset 8
179+ int offset = 8 ;
180+ long ? maxSpeed = null ;
181+ string ? detectedType = null ;
182+
183+ while ( offset + 4 <= buffer . Length )
184+ {
185+ byte type = buffer [ offset ] ;
186+ byte length = buffer [ offset + 1 ] ;
187+
188+ if ( length < 4 || offset + length > buffer . Length )
189+ break ;
190+
191+ // Type 17: Memory Device
192+ if ( type == 17 && length >= 0x15 )
193+ {
194+ // Memory Type at offset 0x12
195+ byte rawMemoryType = buffer [ offset + 0x12 ] ;
196+ string ? memTypeStr = MapSmbiosMemoryType ( rawMemoryType ) ;
197+ if ( memTypeStr != null && detectedType == null )
198+ {
199+ detectedType = memTypeStr ;
200+ }
201+
202+ // Speed in MHz at offset 0x15 (WORD)
203+ if ( length >= 0x17 )
204+ {
205+ ushort speed = ( ushort ) ( buffer [ offset + 0x15 ] | ( buffer [ offset + 0x16 ] << 8 ) ) ;
206+ if ( speed > 0 && speed < 0xFFFF )
207+ {
208+ if ( maxSpeed == null || speed > maxSpeed . Value )
209+ {
210+ maxSpeed = speed ;
211+ }
212+ }
213+ }
214+ }
215+
216+ // Move past formatted area
217+ offset += length ;
218+
219+ // Skip unformatted string section (double null-terminated)
220+ while ( offset < buffer . Length - 1 && ! ( buffer [ offset ] == 0 && buffer [ offset + 1 ] == 0 ) )
221+ {
222+ offset ++ ;
223+ }
224+ offset += 2 ;
225+ }
226+
227+ return ( maxSpeed , detectedType ) ;
228+ }
229+ catch
230+ {
231+ return ( null , null ) ;
232+ }
233+ }
234+
235+ private static class NativeMethods
236+ {
237+ [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
238+ public static extern uint GetSystemFirmwareTable ( uint firmwareTableProviderSignature , uint firmwareTableID , byte [ ] pFirmwareTableBuffer , uint bufferSize ) ;
239+
240+ [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
241+ public static extern uint GetSystemFirmwareTable ( uint firmwareTableProviderSignature , uint firmwareTableID , IntPtr pFirmwareTableBuffer , uint bufferSize ) ;
242+ }
243+
244+ private static string ? MapSmbiosMemoryType ( byte type ) => type switch
245+ {
246+ 0x1A => "DDR3" ,
247+ 0x1A + 1 => "DDR4" ,
248+ 0x1A + 2 => "LPDDR3" ,
249+ 0x1A + 3 => "LPDDR4" ,
250+ 0x22 => "DDR5" ,
251+ 0x23 => "LPDDR5" ,
252+ _ => null
253+ } ;
254+
159255 private static PhysicalMemoryInfo ? GetMacMemory ( )
160256 {
161257 long total = 0 ;
0 commit comments