@@ -22,12 +22,23 @@ mod sys {
22
22
vm:: { Settings , VirtualMachine } ,
23
23
} ;
24
24
use num_traits:: ToPrimitive ;
25
+ #[ cfg( windows) ]
26
+ use std:: os:: windows:: ffi:: OsStrExt ;
25
27
use std:: {
26
28
env:: { self , VarError } ,
27
29
path,
28
30
sync:: atomic:: Ordering ,
29
31
} ;
30
32
33
+ #[ cfg( windows) ]
34
+ use windows_sys:: Win32 :: {
35
+ Foundation :: MAX_PATH ,
36
+ Storage :: FileSystem :: {
37
+ GetFileVersionInfoSizeW , GetFileVersionInfoW , VS_FIXEDFILEINFO , VerQueryValueW ,
38
+ } ,
39
+ System :: LibraryLoader :: { GetModuleFileNameW , GetModuleHandleW } ,
40
+ } ;
41
+
31
42
// not the same as CPython (e.g. rust's x86_x64-unknown-linux-gnu is just x86_64-linux-gnu)
32
43
// but hopefully that's just an implementation detail? TODO: copy CPython's multiarch exactly,
33
44
// https://github.com/python/cpython/blob/3.8/configure.ac#L725
@@ -485,6 +496,78 @@ mod sys {
485
496
vm. trace_func . borrow ( ) . clone ( )
486
497
}
487
498
499
+ #[ cfg( windows) ]
500
+ fn get_kernel32_version ( ) -> std:: io:: Result < ( u32 , u32 , u32 ) > {
501
+ unsafe {
502
+ // Create a wide string for "kernel32.dll"
503
+ let module_name: Vec < u16 > = std:: ffi:: OsStr :: new ( "kernel32.dll" )
504
+ . encode_wide ( )
505
+ . chain ( Some ( 0 ) )
506
+ . collect ( ) ;
507
+ let h_kernel32 = GetModuleHandleW ( module_name. as_ptr ( ) ) ;
508
+ if h_kernel32. is_null ( ) {
509
+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
510
+ }
511
+
512
+ // Prepare a buffer for the module file path
513
+ let mut kernel32_path = [ 0u16 ; MAX_PATH as usize ] ;
514
+ let len = GetModuleFileNameW (
515
+ h_kernel32,
516
+ kernel32_path. as_mut_ptr ( ) ,
517
+ kernel32_path. len ( ) as u32 ,
518
+ ) ;
519
+ if len == 0 {
520
+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
521
+ }
522
+
523
+ // Get the size of the version information block
524
+ let verblock_size =
525
+ GetFileVersionInfoSizeW ( kernel32_path. as_ptr ( ) , std:: ptr:: null_mut ( ) ) ;
526
+ if verblock_size == 0 {
527
+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
528
+ }
529
+
530
+ // Allocate a buffer to hold the version information
531
+ let mut verblock = vec ! [ 0u8 ; verblock_size as usize ] ;
532
+ if GetFileVersionInfoW (
533
+ kernel32_path. as_ptr ( ) ,
534
+ 0 ,
535
+ verblock_size,
536
+ verblock. as_mut_ptr ( ) as * mut _ ,
537
+ ) == 0
538
+ {
539
+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
540
+ }
541
+
542
+ // Prepare an empty sub-block string (L"") as required by VerQueryValueW
543
+ let sub_block: Vec < u16 > = std:: ffi:: OsStr :: new ( "" )
544
+ . encode_wide ( )
545
+ . chain ( Some ( 0 ) )
546
+ . collect ( ) ;
547
+
548
+ let mut ffi_ptr: * mut VS_FIXEDFILEINFO = std:: ptr:: null_mut ( ) ;
549
+ let mut ffi_len: u32 = 0 ;
550
+ if VerQueryValueW (
551
+ verblock. as_ptr ( ) as * const _ ,
552
+ sub_block. as_ptr ( ) ,
553
+ & mut ffi_ptr as * mut * mut VS_FIXEDFILEINFO as * mut * mut _ ,
554
+ & mut ffi_len as * mut u32 ,
555
+ ) == 0
556
+ || ffi_ptr. is_null ( )
557
+ {
558
+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
559
+ }
560
+
561
+ // Extract the version numbers from the VS_FIXEDFILEINFO structure.
562
+ let ffi = * ffi_ptr;
563
+ let real_major = ( ffi. dwProductVersionMS >> 16 ) & 0xFFFF ;
564
+ let real_minor = ffi. dwProductVersionMS & 0xFFFF ;
565
+ let real_build = ( ffi. dwProductVersionLS >> 16 ) & 0xFFFF ;
566
+
567
+ Ok ( ( real_major, real_minor, real_build) )
568
+ }
569
+ }
570
+
488
571
#[ cfg( windows) ]
489
572
#[ pyfunction]
490
573
fn getwindowsversion ( vm : & VirtualMachine ) -> PyResult < crate :: builtins:: tuple:: PyTupleRef > {
@@ -519,21 +602,18 @@ mod sys {
519
602
sp. into_string ( )
520
603
. map_err ( |_| vm. new_os_error ( "service pack is not ASCII" . to_owned ( ) ) ) ?
521
604
} ;
605
+ let real_version = get_kernel32_version ( ) . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
522
606
Ok ( WindowsVersion {
523
- major : version . dwMajorVersion ,
524
- minor : version . dwMinorVersion ,
525
- build : version . dwBuildNumber ,
607
+ major : real_version . 0 ,
608
+ minor : real_version . 1 ,
609
+ build : real_version . 2 ,
526
610
platform : version. dwPlatformId ,
527
611
service_pack,
528
612
service_pack_major : version. wServicePackMajor ,
529
613
service_pack_minor : version. wServicePackMinor ,
530
614
suite_mask : version. wSuiteMask ,
531
615
product_type : version. wProductType ,
532
- platform_version : (
533
- version. dwMajorVersion ,
534
- version. dwMinorVersion ,
535
- version. dwBuildNumber ,
536
- ) , // TODO Provide accurate version, like CPython impl
616
+ platform_version : ( real_version. 0 , real_version. 1 , real_version. 2 ) , // TODO Provide accurate version, like CPython impl
537
617
}
538
618
. into_struct_sequence ( vm) )
539
619
}
0 commit comments