Repository: RustPython/RustPython (language: rust)

Issue:
switch `winapi` to `windows` in `_winapi` module
#4078


Discussion / hints:
It may be convenient to temporarily modify `.github/workflows/ci.yaml` to focus on the CI operations that run on Windows.

Fix patch:
diff --git a/vm/Cargo.toml b/vm/Cargo.toml
index ec1190d165..ed226016e3 100644
--- a/vm/Cargo.toml
+++ b/vm/Cargo.toml
@@ -130,8 +130,10 @@ features = [
   "Win32_System_Console",
   "Win32_System_LibraryLoader",
   "Win32_System_Pipes",
+  "Win32_System_SystemServices",
   "Win32_System_Threading",
   "Win32_UI_Shell",
+  "Win32_UI_WindowsAndMessaging",
 ]
 
 [target.'cfg(windows)'.dependencies.winapi]
diff --git a/vm/src/lib.rs b/vm/src/lib.rs
index 71ca05369b..aae29a9a28 100644
--- a/vm/src/lib.rs
+++ b/vm/src/lib.rs
@@ -79,6 +79,8 @@ pub mod utils;
 pub mod version;
 pub mod vm;
 pub mod warn;
+#[cfg(windows)]
+pub mod windows;
 
 pub use self::compiler::parser::source_code;
 pub use self::convert::{TryFromBorrowedObject, TryFromObject};
diff --git a/vm/src/stdlib/winapi.rs b/vm/src/stdlib/winapi.rs
index 34ec941531..ed88fabceb 100644
--- a/vm/src/stdlib/winapi.rs
+++ b/vm/src/stdlib/winapi.rs
@@ -6,13 +6,13 @@ mod _winapi {
     use crate::{
         builtins::PyStrRef,
         common::windows::ToWideString,
-        convert::{ToPyException, ToPyObject, ToPyResult},
+        convert::{ToPyException, ToPyResult},
         function::{ArgMapping, ArgSequence, OptionalArg},
         stdlib::os::errno_err,
+        windows::WindowsSysResult,
         PyObjectRef, PyResult, TryFromObject, VirtualMachine,
     };
     use std::ptr::{null, null_mut};
-    use winapi::um::winbase;
     use windows::{
         core::PCWSTR,
         Win32::Foundation::{HANDLE, HINSTANCE, MAX_PATH},
@@ -20,109 +20,43 @@ mod _winapi {
     use windows_sys::Win32::Foundation::{BOOL, HANDLE as RAW_HANDLE};
 
     #[pyattr]
-    use winapi::{
-        shared::winerror::{
-            ERROR_ALREADY_EXISTS, ERROR_BROKEN_PIPE, ERROR_IO_PENDING, ERROR_MORE_DATA,
-            ERROR_NETNAME_DELETED, ERROR_NO_DATA, ERROR_NO_SYSTEM_RESOURCES,
-            ERROR_OPERATION_ABORTED, ERROR_PIPE_BUSY, ERROR_PIPE_CONNECTED, ERROR_SEM_TIMEOUT,
-            WAIT_TIMEOUT,
+    use windows_sys::Win32::{
+        Foundation::{
+            DUPLICATE_CLOSE_SOURCE, DUPLICATE_SAME_ACCESS, ERROR_ALREADY_EXISTS, ERROR_BROKEN_PIPE,
+            ERROR_IO_PENDING, ERROR_MORE_DATA, ERROR_NETNAME_DELETED, ERROR_NO_DATA,
+            ERROR_NO_SYSTEM_RESOURCES, ERROR_OPERATION_ABORTED, ERROR_PIPE_BUSY,
+            ERROR_PIPE_CONNECTED, ERROR_SEM_TIMEOUT, GENERIC_READ, GENERIC_WRITE, STILL_ACTIVE,
+            WAIT_ABANDONED, WAIT_ABANDONED_0, WAIT_OBJECT_0, WAIT_TIMEOUT,
         },
-        um::{
-            fileapi::OPEN_EXISTING,
-            memoryapi::{
-                FILE_MAP_ALL_ACCESS, FILE_MAP_COPY, FILE_MAP_EXECUTE, FILE_MAP_READ, FILE_MAP_WRITE,
+        Storage::FileSystem::{
+            FILE_FLAG_FIRST_PIPE_INSTANCE, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ,
+            FILE_GENERIC_WRITE, FILE_TYPE_CHAR, FILE_TYPE_DISK, FILE_TYPE_PIPE, FILE_TYPE_REMOTE,
+            FILE_TYPE_UNKNOWN, OPEN_EXISTING, PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, SYNCHRONIZE,
+        },
+        System::{
+            Console::{STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
+            Memory::{
+                FILE_MAP_ALL_ACCESS, MEM_COMMIT, MEM_FREE, MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE,
+                MEM_RESERVE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
+                PAGE_EXECUTE_WRITECOPY, PAGE_GUARD, PAGE_NOACCESS, PAGE_NOCACHE, PAGE_READONLY,
+                PAGE_READWRITE, PAGE_WRITECOMBINE, PAGE_WRITECOPY, SEC_COMMIT, SEC_IMAGE,
+                SEC_LARGE_PAGES, SEC_NOCACHE, SEC_RESERVE, SEC_WRITECOMBINE,
+            },
+            Pipes::{
+                PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_WAIT,
             },
-            minwinbase::STILL_ACTIVE,
-            winbase::{
+            SystemServices::LOCALE_NAME_MAX_LENGTH,
+            Threading::{
                 ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS,
                 CREATE_BREAKAWAY_FROM_JOB, CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE,
-                CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW, DETACHED_PROCESS,
-                FILE_FLAG_FIRST_PIPE_INSTANCE, FILE_FLAG_OVERLAPPED, FILE_TYPE_CHAR,
-                FILE_TYPE_DISK, FILE_TYPE_PIPE, FILE_TYPE_REMOTE, FILE_TYPE_UNKNOWN,
-                HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, INFINITE, NORMAL_PRIORITY_CLASS,
-                PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE,
-                PIPE_UNLIMITED_INSTANCES, PIPE_WAIT, REALTIME_PRIORITY_CLASS, STARTF_USESHOWWINDOW,
-                STARTF_USESTDHANDLES, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
-                WAIT_ABANDONED, WAIT_ABANDONED_0, WAIT_OBJECT_0,
+                CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW, DETACHED_PROCESS, HIGH_PRIORITY_CLASS,
+                IDLE_PRIORITY_CLASS, INFINITE, NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+                REALTIME_PRIORITY_CLASS, STARTF_USESHOWWINDOW, STARTF_USESTDHANDLES,
             },
-            winnt::{
-                DUPLICATE_CLOSE_SOURCE, DUPLICATE_SAME_ACCESS, FILE_GENERIC_READ,
-                FILE_GENERIC_WRITE, GENERIC_READ, GENERIC_WRITE, LOCALE_NAME_MAX_LENGTH,
-                MEM_COMMIT, MEM_FREE, MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE, MEM_RESERVE,
-                PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY,
-                PAGE_GUARD, PAGE_NOACCESS, PAGE_NOCACHE, PAGE_READONLY, PAGE_READWRITE,
-                PAGE_WRITECOMBINE, PAGE_WRITECOPY, PROCESS_DUP_HANDLE, SEC_COMMIT, SEC_IMAGE,
-                SEC_LARGE_PAGES, SEC_NOCACHE, SEC_RESERVE, SEC_WRITECOMBINE, SYNCHRONIZE,
-            },
-            winuser::SW_HIDE,
         },
+        UI::WindowsAndMessaging::SW_HIDE,
     };
 
-    fn GetLastError() -> u32 {
-        unsafe { winapi::um::errhandlingapi::GetLastError() }
-    }
-
-    trait WindowsSysResultValue {
-        type Ok: ToPyObject;
-        fn is_err(&self) -> bool;
-        fn into_ok(self) -> Self::Ok;
-    }
-
-    impl WindowsSysResultValue for RAW_HANDLE {
-        type Ok = HANDLE;
-        fn is_err(&self) -> bool {
-            *self == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE
-        }
-        fn into_ok(self) -> Self::Ok {
-            HANDLE(self)
-        }
-    }
-
-    impl WindowsSysResultValue for BOOL {
-        type Ok = ();
-        fn is_err(&self) -> bool {
-            *self == 0
-        }
-        fn into_ok(self) -> Self::Ok {}
-    }
-
-    struct WindowsSysResult<T>(T);
-
-    impl<T: WindowsSysResultValue> WindowsSysResult<T> {
-        fn is_err(&self) -> bool {
-            self.0.is_err()
-        }
-        fn into_pyresult(self, vm: &VirtualMachine) -> PyResult<T::Ok> {
-            if self.is_err() {
-                Err(errno_err(vm))
-            } else {
-                Ok(self.0.into_ok())
-            }
-        }
-    }
-
-    impl<T: WindowsSysResultValue> ToPyResult for WindowsSysResult<T> {
-        fn to_pyresult(self, vm: &VirtualMachine) -> PyResult {
-            let ok = self.into_pyresult(vm)?;
-            Ok(ok.to_pyobject(vm))
-        }
-    }
-
-    type HandleInt = usize; // TODO: change to isize when fully ported to windows-rs
-
-    impl TryFromObject for HANDLE {
-        fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
-            let handle = HandleInt::try_from_object(vm, obj)?;
-            Ok(HANDLE(handle as isize))
-        }
-    }
-
-    impl ToPyObject for HANDLE {
-        fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
-            (self.0 as HandleInt).to_pyobject(vm)
-        }
-    }
-
     #[pyfunction]
     fn CloseHandle(handle: HANDLE) -> WindowsSysResult<BOOL> {
         WindowsSysResult(unsafe { windows_sys::Win32::Foundation::CloseHandle(handle.0) })
@@ -193,7 +127,7 @@ mod _winapi {
         vm: &VirtualMachine,
     ) -> PyResult<windows_sys::Win32::Storage::FileSystem::FILE_TYPE> {
         let file_type = unsafe { windows_sys::Win32::Storage::FileSystem::GetFileType(h.0) };
-        if file_type == 0 && GetLastError() != 0 {
+        if file_type == 0 && unsafe { windows_sys::Win32::Foundation::GetLastError() } != 0 {
             Err(errno_err(vm))
         } else {
             Ok(file_type)
@@ -227,7 +161,8 @@ mod _winapi {
         args: CreateProcessArgs,
         vm: &VirtualMachine,
     ) -> PyResult<(HANDLE, HANDLE, u32, u32)> {
-        let mut si = winbase::STARTUPINFOEXW::default();
+        let mut si: windows_sys::Win32::System::Threading::STARTUPINFOEXW =
+            unsafe { std::mem::zeroed() };
         si.StartupInfo.cb = std::mem::size_of_val(&si) as _;
 
         macro_rules! si_attr {
@@ -292,11 +227,11 @@ mod _winapi {
                 std::ptr::null(),
                 args.inherit_handles,
                 args.creation_flags
-                    | winbase::EXTENDED_STARTUPINFO_PRESENT
-                    | winbase::CREATE_UNICODE_ENVIRONMENT,
+                    | windows_sys::Win32::System::Threading::EXTENDED_STARTUPINFO_PRESENT
+                    | windows_sys::Win32::System::Threading::CREATE_UNICODE_ENVIRONMENT,
                 env as _,
                 current_dir,
-                &mut si as *mut winbase::STARTUPINFOEXW as _,
+                &mut si as *mut _ as *mut _,
                 procinfo.as_mut_ptr(),
             ))
             .into_pyresult(vm)?;
@@ -390,7 +325,8 @@ mod _winapi {
                     (result, size.assume_init())
                 };
                 if !result.is_err()
-                    || GetLastError() != winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER
+                    || unsafe { windows_sys::Win32::Foundation::GetLastError() }
+                        != windows_sys::Win32::Foundation::ERROR_INSUFFICIENT_BUFFER
                 {
                     return Err(errno_err(vm));
                 }
diff --git a/vm/src/windows.rs b/vm/src/windows.rs
new file mode 100644
index 0000000000..9216f839fe
--- /dev/null
+++ b/vm/src/windows.rs
@@ -0,0 +1,68 @@
+use crate::{
+    convert::{ToPyObject, ToPyResult},
+    stdlib::os::errno_err,
+    PyObjectRef, PyResult, TryFromObject, VirtualMachine,
+};
+use windows::Win32::Foundation::HANDLE;
+use windows_sys::Win32::Foundation::{BOOL, HANDLE as RAW_HANDLE};
+
+pub(crate) trait WindowsSysResultValue {
+    type Ok: ToPyObject;
+    fn is_err(&self) -> bool;
+    fn into_ok(self) -> Self::Ok;
+}
+
+impl WindowsSysResultValue for RAW_HANDLE {
+    type Ok = HANDLE;
+    fn is_err(&self) -> bool {
+        *self == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE
+    }
+    fn into_ok(self) -> Self::Ok {
+        HANDLE(self)
+    }
+}
+
+impl WindowsSysResultValue for BOOL {
+    type Ok = ();
+    fn is_err(&self) -> bool {
+        *self == 0
+    }
+    fn into_ok(self) -> Self::Ok {}
+}
+
+pub(crate) struct WindowsSysResult<T>(pub T);
+
+impl<T: WindowsSysResultValue> WindowsSysResult<T> {
+    pub fn is_err(&self) -> bool {
+        self.0.is_err()
+    }
+    pub fn into_pyresult(self, vm: &VirtualMachine) -> PyResult<T::Ok> {
+        if self.is_err() {
+            Err(errno_err(vm))
+        } else {
+            Ok(self.0.into_ok())
+        }
+    }
+}
+
+impl<T: WindowsSysResultValue> ToPyResult for WindowsSysResult<T> {
+    fn to_pyresult(self, vm: &VirtualMachine) -> PyResult {
+        let ok = self.into_pyresult(vm)?;
+        Ok(ok.to_pyobject(vm))
+    }
+}
+
+type HandleInt = usize; // TODO: change to isize when fully ported to windows-rs
+
+impl TryFromObject for HANDLE {
+    fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
+        let handle = HandleInt::try_from_object(vm, obj)?;
+        Ok(HANDLE(handle as isize))
+    }
+}
+
+impl ToPyObject for HANDLE {
+    fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
+        (self.0 as HandleInt).to_pyobject(vm)
+    }
+}


Test patch: