@@ -231,6 +231,78 @@ fn sys_displayhook(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
231231 Ok ( ( ) )
232232}
233233
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+
234306const PLATFORM : & str = {
235307 cfg_if:: cfg_if! {
236308 if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
@@ -474,6 +546,15 @@ settrace() -- set the global debug tracing function
474546 "__displayhook__" => ctx. new_function( sys_displayhook) ,
475547 } ) ;
476548
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+
477558 modules. set_item ( "sys" , module. clone ( ) , vm) . unwrap ( ) ;
478559 modules. set_item ( "builtins" , builtins. clone ( ) , vm) . unwrap ( ) ;
479560}
0 commit comments