@@ -231,6 +231,78 @@ fn sys_displayhook(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
231
231
Ok ( ( ) )
232
232
}
233
233
234
+ #[ pystruct_sequence( module = "sys" , name = "getwindowsversion" ) ]
235
+ #[ derive( Default , Debug ) ]
236
+ #[ cfg( windows) ]
237
+ struct WindowsVersion {
238
+ major : u32 ,
239
+ minor : u32 ,
240
+ build : u32 ,
241
+ platform : u32 ,
242
+ service_pack : String ,
243
+ service_pack_major : u16 ,
244
+ service_pack_minor : u16 ,
245
+ suite_mask : u16 ,
246
+ product_type : u8 ,
247
+ platform_version : ( u32 , u32 , u32 ) ,
248
+ }
249
+
250
+ #[ cfg( windows) ]
251
+ fn sys_getwindowsversion ( vm : & VirtualMachine ) -> PyResult < crate :: obj:: objtuple:: PyTupleRef > {
252
+ use std:: ffi:: OsString ;
253
+ use std:: os:: windows:: ffi:: OsStringExt ;
254
+ use winapi:: um:: {
255
+ sysinfoapi:: GetVersionExW ,
256
+ winnt:: { LPOSVERSIONINFOEXW , LPOSVERSIONINFOW , OSVERSIONINFOEXW } ,
257
+ } ;
258
+
259
+ let mut version = OSVERSIONINFOEXW :: default ( ) ;
260
+ version. dwOSVersionInfoSize = std:: mem:: size_of :: < OSVERSIONINFOEXW > ( ) as u32 ;
261
+ let result = unsafe {
262
+ let osvi = & mut version as LPOSVERSIONINFOEXW as LPOSVERSIONINFOW ;
263
+ // SAFE: GetVersionExW accepts a pointer of OSVERSIONINFOW, but winapi crate's type currently doesn't allow to do so.
264
+ // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw#parameters
265
+ GetVersionExW ( osvi)
266
+ } ;
267
+
268
+ if result == 0 {
269
+ Err ( vm. new_os_error ( "failed to get windows version" . to_owned ( ) ) )
270
+ } else {
271
+ let service_pack = {
272
+ let ( last, _) = version
273
+ . szCSDVersion
274
+ . iter ( )
275
+ . take_while ( |& x| x != & 0 )
276
+ . enumerate ( )
277
+ . last ( )
278
+ . unwrap_or ( ( 0 , & 0 ) ) ;
279
+ let sp = OsString :: from_wide ( & version. szCSDVersion [ ..last] ) ;
280
+ if let Ok ( string) = sp. into_string ( ) {
281
+ string
282
+ } else {
283
+ return Err ( vm. new_os_error ( "service pack is not ASCII" . to_owned ( ) ) ) ;
284
+ }
285
+ } ;
286
+ WindowsVersion {
287
+ major : version. dwMajorVersion ,
288
+ minor : version. dwMinorVersion ,
289
+ build : version. dwBuildNumber ,
290
+ platform : version. dwPlatformId ,
291
+ service_pack,
292
+ service_pack_major : version. wServicePackMajor ,
293
+ service_pack_minor : version. wServicePackMinor ,
294
+ suite_mask : version. wSuiteMask ,
295
+ product_type : version. wProductType ,
296
+ platform_version : (
297
+ version. dwMajorVersion ,
298
+ version. dwMinorVersion ,
299
+ version. dwBuildNumber ,
300
+ ) , // TODO Provide accurate version, like CPython impl
301
+ }
302
+ . into_struct_sequence ( vm, vm. try_class ( "sys" , "_getwindowsversion_type" ) ?)
303
+ }
304
+ }
305
+
234
306
const PLATFORM : & str = {
235
307
cfg_if:: cfg_if! {
236
308
if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
@@ -474,6 +546,15 @@ settrace() -- set the global debug tracing function
474
546
"__displayhook__" => ctx. new_function( sys_displayhook) ,
475
547
} ) ;
476
548
549
+ #[ cfg( windows) ]
550
+ {
551
+ let getwindowsversion = WindowsVersion :: make_class ( ctx) ;
552
+ extend_module ! ( vm, module, {
553
+ "getwindowsversion" => ctx. new_function( sys_getwindowsversion) ,
554
+ "_getwindowsversion_type" => getwindowsversion, // XXX: This is not a python spec but required by current RustPython implementation
555
+ } )
556
+ }
557
+
477
558
modules. set_item ( "sys" , module. clone ( ) , vm) . unwrap ( ) ;
478
559
modules. set_item ( "builtins" , builtins. clone ( ) , vm) . unwrap ( ) ;
479
560
}
0 commit comments