diff --git a/Cargo.lock b/Cargo.lock
index 1d40b8acc66..23a9f2bd2b7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -898,7 +898,7 @@ dependencies = [
  "tracing-subscriber",
  "unified-diff",
  "walkdir",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -2273,7 +2273,7 @@ dependencies = [
  "dirs",
  "gix-path",
  "libc",
- "windows",
+ "windows 0.43.0",
 ]
 
 [[package]]
@@ -4529,7 +4529,7 @@ dependencies = [
  "tempfile",
  "thin-vec",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -4588,7 +4588,7 @@ dependencies = [
  "rustc_ty_utils",
  "serde_json",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -4636,7 +4636,7 @@ dependencies = [
  "termize",
  "tracing",
  "unicode-width",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -5277,7 +5277,7 @@ dependencies = [
  "smallvec",
  "termize",
  "tracing",
- "winapi",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -6908,6 +6908,15 @@ dependencies = [
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
+dependencies = [
+ "windows-targets",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.42.0"
@@ -6934,9 +6943,9 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -6949,45 +6958,45 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "writeable"
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index f2a904a6654..24cf9812a25 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -36,8 +36,15 @@ elsa = "1.8"
 [dependencies.parking_lot]
 version = "0.11"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_Storage_FileSystem",
+    "Win32_System_IO",
+    "Win32_System_ProcessStatus",
+    "Win32_System_Threading",
+]
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 memmap2 = "0.2.1"
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index e395d8dbbbf..efdb44248d1 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -4,9 +4,6 @@
 //! green/native threading. This is just a bare-bones enough solution for
 //! librustdoc, it is not production quality at all.
 
-#![allow(non_camel_case_types)]
-#![allow(nonstandard_style)]
-
 cfg_if! {
     if #[cfg(target_os = "linux")] {
         mod linux;
@@ -16,7 +13,7 @@ cfg_if! {
         use unix as imp;
     } else if #[cfg(windows)] {
         mod windows;
-        use windows as imp;
+        use self::windows as imp;
     } else {
         mod unsupported;
         use unsupported as imp;
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 43e6caaa18d..da128f464a6 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -1,13 +1,16 @@
 use std::fs::{File, OpenOptions};
 use std::io;
-use std::mem;
 use std::os::windows::prelude::*;
 use std::path::Path;
 
-use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
-use winapi::um::fileapi::LockFileEx;
-use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED};
-use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
+use windows::{
+    Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE},
+    Win32::Storage::FileSystem::{
+        LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK,
+        LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS,
+    },
+    Win32::System::IO::OVERLAPPED,
+};
 
 #[derive(Debug)]
 pub struct Lock {
@@ -25,7 +28,7 @@ impl Lock {
         let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
         let mut open_options = OpenOptions::new();
-        open_options.read(true).share_mode(share_mode);
+        open_options.read(true).share_mode(share_mode.0);
 
         if create {
             open_options.create(true).write(true);
@@ -43,33 +46,42 @@ impl Lock {
             }
         };
 
-        let ret = unsafe {
-            let mut overlapped: OVERLAPPED = mem::zeroed();
-
-            let mut dwFlags = 0;
-            if !wait {
-                dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
-            }
-
-            if exclusive {
-                dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
-            }
-
-            debug!("attempting to acquire lock on lock file `{}`", p.display());
-            LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped)
-        };
-        if ret == 0 {
-            let err = io::Error::last_os_error();
-            debug!("failed acquiring file lock: {}", err);
-            Err(err)
-        } else {
-            debug!("successfully acquired lock");
-            Ok(Lock { _file: file })
+        let mut flags = LOCK_FILE_FLAGS::default();
+        if !wait {
+            flags |= LOCKFILE_FAIL_IMMEDIATELY;
         }
+
+        if exclusive {
+            flags |= LOCKFILE_EXCLUSIVE_LOCK;
+        }
+
+        let mut overlapped = OVERLAPPED::default();
+
+        debug!("attempting to acquire lock on lock file `{}`", p.display());
+
+        unsafe {
+            LockFileEx(
+                HANDLE(file.as_raw_handle() as isize),
+                flags,
+                0,
+                u32::MAX,
+                u32::MAX,
+                &mut overlapped,
+            )
+        }
+        .ok()
+        .map_err(|e| {
+            let err = io::Error::from_raw_os_error(e.code().0);
+            debug!("failed acquiring file lock: {}", err);
+            err
+        })?;
+
+        debug!("successfully acquired lock");
+        Ok(Lock { _file: file })
     }
 
     pub fn error_unsupported(err: &io::Error) -> bool {
-        err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+        err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32)
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 44331683694..3d9c7f6eae2 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -796,21 +796,26 @@ fn get_thread_id() -> u32 {
 cfg_if! {
     if #[cfg(windows)] {
         pub fn get_resident_set_size() -> Option<usize> {
-            use std::mem::{self, MaybeUninit};
-            use winapi::shared::minwindef::DWORD;
-            use winapi::um::processthreadsapi::GetCurrentProcess;
-            use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
+            use std::mem;
 
-            let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
-            match unsafe {
-                GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
-            } {
-                0 => None,
-                _ => {
-                    let pmc = unsafe { pmc.assume_init() };
-                    Some(pmc.WorkingSetSize as usize)
-                }
+            use windows::{
+                Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
+                Win32::System::Threading::GetCurrentProcess,
+            };
+
+            let mut pmc = PROCESS_MEMORY_COUNTERS::default();
+            let pmc_size = mem::size_of_val(&pmc);
+            unsafe {
+                K32GetProcessMemoryInfo(
+                    GetCurrentProcess(),
+                    &mut pmc,
+                    pmc_size as u32,
+                )
             }
+            .ok()
+            .ok()?;
+
+            Some(pmc.WorkingSetSize)
         }
     } else if #[cfg(target_os = "macos")] {
         pub fn get_resident_set_size() -> Option<usize> {
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 7b59a52cffe..73a1f79a020 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -54,8 +54,11 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_System_Diagnostics_Debug",
+]
 
 [features]
 llvm = ['rustc_interface/llvm']
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 555917c8b5e..8634c644176 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1246,11 +1246,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     interface::try_print_query_stack(&handler, num_frames);
 
     #[cfg(windows)]
-    unsafe {
-        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-            // Trigger a debugger if we crashed during bootstrap
-            winapi::um::debugapi::DebugBreak();
-        }
+    if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+        // Trigger a debugger if we crashed during bootstrap
+        unsafe { windows::Win32::System::Diagnostics::Debug::DebugBreak() };
     }
 }
 
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index cadd53fbd83..e1ead08ea66 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -25,8 +25,14 @@ termize = "0.1.1"
 serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_Security",
+    "Win32_System_Threading",
+    "Win32_System_WindowsProgramming",
+]
 
 [features]
 rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index a73472021d4..7db262abfde 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -16,10 +16,12 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     use std::ffi::CString;
     use std::io;
 
-    use winapi::shared::ntdef::HANDLE;
-    use winapi::um::handleapi::CloseHandle;
-    use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
-    use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
+    use windows::{
+        core::PCSTR,
+        Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
+        Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject},
+        Win32::System::WindowsProgramming::INFINITE,
+    };
 
     struct Handle(HANDLE);
 
@@ -42,49 +44,38 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     }
 
     let cname = CString::new(name).unwrap();
-    unsafe {
-        // Create a named mutex, with no security attributes and also not
-        // acquired when we create it.
-        //
-        // This will silently create one if it doesn't already exist, or it'll
-        // open up a handle to one if it already exists.
-        let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
-        if mutex.is_null() {
-            panic!(
-                "failed to create global mutex named `{}`: {}",
-                name,
-                io::Error::last_os_error()
-            );
-        }
-        let mutex = Handle(mutex);
+    // Create a named mutex, with no security attributes and also not
+    // acquired when we create it.
+    //
+    // This will silently create one if it doesn't already exist, or it'll
+    // open up a handle to one if it already exists.
+    let mutex = unsafe { CreateMutexA(None, false, PCSTR::from_raw(cname.as_ptr().cast())) }
+        .unwrap_or_else(|_| panic!("failed to create global mutex named `{}`", name));
+    let mutex = Handle(mutex);
 
-        // Acquire the lock through `WaitForSingleObject`.
-        //
-        // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
-        //
-        // A return value of `WAIT_ABANDONED` means that the previous holder of
-        // the thread exited without calling `ReleaseMutex`. This can happen,
-        // for example, when the compiler crashes or is interrupted via ctrl-c
-        // or the like. In this case, however, we are still transferred
-        // ownership of the lock so we continue.
-        //
-        // If an error happens.. well... that's surprising!
-        match WaitForSingleObject(mutex.0, INFINITE) {
-            WAIT_OBJECT_0 | WAIT_ABANDONED => {}
-            code => {
-                panic!(
-                    "WaitForSingleObject failed on global mutex named \
-                        `{}`: {} (ret={:x})",
-                    name,
-                    io::Error::last_os_error(),
-                    code
-                );
-            }
-        }
-
-        // Return a guard which will call `ReleaseMutex` when dropped.
-        Box::new(Guard(mutex))
+    // Acquire the lock through `WaitForSingleObject`.
+    //
+    // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
+    //
+    // A return value of `WAIT_ABANDONED` means that the previous holder of
+    // the thread exited without calling `ReleaseMutex`. This can happen,
+    // for example, when the compiler crashes or is interrupted via ctrl-c
+    // or the like. In this case, however, we are still transferred
+    // ownership of the lock so we continue.
+    //
+    // If an error happens.. well... that's surprising!
+    match unsafe { WaitForSingleObject(mutex.0, INFINITE) } {
+        WAIT_OBJECT_0 | WAIT_ABANDONED => (),
+        err => panic!(
+            "WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})",
+            name,
+            io::Error::last_os_error(),
+            err.0
+        ),
     }
+
+    // Return a guard which will call `ReleaseMutex` when dropped.
+    Box::new(Guard(mutex))
 }
 
 #[cfg(not(windows))]
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index d8db86c5f62..9e337dde995 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -24,5 +24,9 @@ termize = "0.1.1"
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["libloaderapi"] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_System_LibraryLoader",
+]
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index f1fbf38217d..e734599cbfc 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -87,35 +87,38 @@ fn current_dll_path() -> Result<PathBuf, String> {
     use std::ffi::OsString;
     use std::io;
     use std::os::windows::prelude::*;
-    use std::ptr;
 
-    use winapi::um::libloaderapi::{
-        GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+    use windows::{
+        core::PCWSTR,
+        Win32::Foundation::HINSTANCE,
+        Win32::System::LibraryLoader::{
+            GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+        },
     };
 
+    let mut module = HINSTANCE::default();
     unsafe {
-        let mut module = ptr::null_mut();
-        let r = GetModuleHandleExW(
+        GetModuleHandleExW(
             GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-            current_dll_path as usize as *mut _,
+            PCWSTR(current_dll_path as *mut u16),
             &mut module,
-        );
-        if r == 0 {
-            return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
-        }
-        let mut space = Vec::with_capacity(1024);
-        let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
-        if r == 0 {
-            return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
-        }
-        let r = r as usize;
-        if r >= space.capacity() {
-            return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
-        }
-        space.set_len(r);
-        let os = OsString::from_wide(&space);
-        Ok(PathBuf::from(os))
+        )
     }
+    .ok()
+    .map_err(|e| e.to_string())?;
+
+    let mut filename = vec![0; 1024];
+    let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize;
+    if n == 0 {
+        return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
+    }
+    if n >= filename.capacity() {
+        return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
+    }
+
+    filename.truncate(n);
+
+    Ok(OsString::from_wide(&filename).into())
 }
 
 pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index e861d520c53..833e155ed87 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -57,7 +57,7 @@ dependencies = [
  "tar",
  "toml",
  "walkdir",
- "winapi",
+ "windows",
  "xz2",
 ]
 
@@ -720,6 +720,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
+[[package]]
+name = "windows"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
+dependencies = [
+ "windows-targets",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.42.0"
@@ -736,46 +745,61 @@ dependencies = [
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+name = "windows-targets"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "xattr"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index afe3fc1741b..13ebd8af15b 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -59,18 +59,20 @@ sysinfo = { version = "0.26.0", optional = true }
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
 fd-lock = "3.0.8"
 
-[target.'cfg(windows)'.dependencies.winapi]
-version = "0.3"
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
 features = [
-    "fileapi",
-    "ioapiset",
-    "jobapi2",
-    "handleapi",
-    "winioctl",
-    "psapi",
-    "impl-default",
-    "timezoneapi",
-    "winbase",
+    "Win32_Foundation",
+    "Win32_Security",
+    "Win32_Storage_FileSystem",
+    "Win32_System_Diagnostics_Debug",
+    "Win32_System_IO",
+    "Win32_System_Ioctl",
+    "Win32_System_JobObjects",
+    "Win32_System_ProcessStatus",
+    "Win32_System_SystemServices",
+    "Win32_System_Threading",
+    "Win32_System_Time",
 ]
 
 [dev-dependencies]
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 9611c866df5..040fec3615b 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -281,41 +281,49 @@ fn format_rusage_data(_child: Child) -> Option<String> {
 #[cfg(windows)]
 fn format_rusage_data(child: Child) -> Option<String> {
     use std::os::windows::io::AsRawHandle;
-    use winapi::um::{processthreadsapi, psapi, timezoneapi};
-    let handle = child.as_raw_handle();
-    macro_rules! try_bool {
-        ($e:expr) => {
-            if $e != 1 {
-                return None;
-            }
-        };
-    }
+
+    use windows::{
+        Win32::Foundation::HANDLE,
+        Win32::System::ProcessStatus::{
+            K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
+        },
+        Win32::System::Threading::GetProcessTimes,
+        Win32::System::Time::FileTimeToSystemTime,
+    };
+
+    let handle = HANDLE(child.as_raw_handle() as isize);
 
     let mut user_filetime = Default::default();
     let mut user_time = Default::default();
     let mut kernel_filetime = Default::default();
     let mut kernel_time = Default::default();
-    let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default();
+    let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
 
     unsafe {
-        try_bool!(processthreadsapi::GetProcessTimes(
+        GetProcessTimes(
             handle,
             &mut Default::default(),
             &mut Default::default(),
             &mut kernel_filetime,
             &mut user_filetime,
-        ));
-        try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time));
-        try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time));
-
-        // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
-        // with the given handle and none of that process's children.
-        try_bool!(psapi::GetProcessMemoryInfo(
-            handle as _,
-            &mut memory_counters as *mut _ as _,
-            std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32,
-        ));
+        )
     }
+    .ok()
+    .ok()?;
+    unsafe { FileTimeToSystemTime(&user_filetime, &mut user_time) }.ok().ok()?;
+    unsafe { FileTimeToSystemTime(&kernel_filetime, &mut kernel_time) }.ok().ok()?;
+
+    // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
+    // with the given handle and none of that process's children.
+    unsafe {
+        K32GetProcessMemoryInfo(
+            handle,
+            &mut memory_counters,
+            std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
+        )
+    }
+    .ok()
+    .ok()?;
 
     // Guide on interpreting these numbers:
     // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index bb07ca1908e..cbf0f1c37a2 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1303,6 +1303,14 @@ impl<'a> Builder<'a> {
             }
         };
 
+        // By default, windows-rs depends on a native library that doesn't get copied into the
+        // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
+        // library unnecessary. This can be removed when windows-rs enables raw-dylib
+        // unconditionally.
+        if let Mode::Rustc | Mode::ToolRustc = mode {
+            rustflags.arg("--cfg=windows_raw_dylib");
+        }
+
         if use_new_symbol_mangling {
             rustflags.arg("-Csymbol-mangling-version=v0");
         } else {
diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs
index 5c0322e18a4..4fb00f65dc1 100644
--- a/src/bootstrap/job.rs
+++ b/src/bootstrap/job.rs
@@ -27,52 +27,54 @@
 //! Note that this module has a #[cfg(windows)] above it as none of this logic
 //! is required on Unix.
 
-#![allow(nonstandard_style, dead_code)]
-
 use crate::Build;
 use std::env;
+use std::ffi::c_void;
 use std::io;
 use std::mem;
-use std::ptr;
 
-use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
-use winapi::um::errhandlingapi::SetErrorMode;
-use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
-use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
-use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
-use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
-use winapi::um::winnt::{
-    JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
-    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+use windows::{
+    core::PCWSTR,
+    Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
+    Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE},
+    Win32::System::JobObjects::{
+        AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
+        SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
+        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
+    },
+    Win32::System::Threading::{
+        GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
+    },
 };
 
 pub unsafe fn setup(build: &mut Build) {
     // Enable the Windows Error Reporting dialog which msys disables,
     // so we can JIT debug rustc
-    let mode = SetErrorMode(0);
+    let mode = SetErrorMode(THREAD_ERROR_MODE::default());
+    let mode = THREAD_ERROR_MODE(mode);
     SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
 
     // Create a new job object for us to use
-    let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
-    assert!(!job.is_null(), "{}", io::Error::last_os_error());
+    let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
 
     // Indicate that when all handles to the job object are gone that all
     // process in the object should be killed. Note that this includes our
     // entire process tree by default because we've added ourselves and our
     // children will reside in the job by default.
-    let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
+    let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
     info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
     if build.config.low_priority {
         info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
-        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
+        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
     }
     let r = SetInformationJobObject(
         job,
         JobObjectExtendedLimitInformation,
-        &mut info as *mut _ as LPVOID,
-        mem::size_of_val(&info) as DWORD,
-    );
-    assert!(r != 0, "{}", io::Error::last_os_error());
+        &info as *const _ as *const c_void,
+        mem::size_of_val(&info) as u32,
+    )
+    .ok();
+    assert!(r.is_ok(), "{}", io::Error::last_os_error());
 
     // Assign our process to this job object. Note that if this fails, one very
     // likely reason is that we are ourselves already in a job object! This can
@@ -83,8 +85,8 @@ pub unsafe fn setup(build: &mut Build) {
     // Also note that nested jobs (why this might fail) are supported in recent
     // versions of Windows, but the version of Windows that our bots are running
     // at least don't support nested job objects.
-    let r = AssignProcessToJobObject(job, GetCurrentProcess());
-    if r == 0 {
+    let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
+    if r.is_err() {
         CloseHandle(job);
         return;
     }
@@ -102,31 +104,32 @@ pub unsafe fn setup(build: &mut Build) {
         Err(..) => return,
     };
 
-    let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
+    let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
+        Some(parent) => parent,
+        _ => {
+            // If we get a null parent pointer here, it is possible that either
+            // we have an invalid pid or the parent process has been closed.
+            // Since the first case rarely happens
+            // (only when wrongly setting the environmental variable),
+            // it might be better to improve the experience of the second case
+            // when users have interrupted the parent process and we haven't finish
+            // duplicating the handle yet. We just need close the job object if that occurs.
+            CloseHandle(job);
+            return;
+        }
+    };
 
-    // If we get a null parent pointer here, it is possible that either
-    // we have got an invalid pid or the parent process has been closed.
-    // Since the first case rarely happens
-    // (only when wrongly setting the environmental variable),
-    // so it might be better to improve the experience of the second case
-    // when users have interrupted the parent process and we don't finish
-    // duplicating the handle yet.
-    // We just need close the job object if that occurs.
-    if parent.is_null() {
-        CloseHandle(job);
-        return;
-    }
-
-    let mut parent_handle = ptr::null_mut();
+    let mut parent_handle = HANDLE::default();
     let r = DuplicateHandle(
         GetCurrentProcess(),
         job,
         parent,
         &mut parent_handle,
         0,
-        FALSE,
+        false,
         DUPLICATE_SAME_ACCESS,
-    );
+    )
+    .ok();
 
     // If this failed, well at least we tried! An example of DuplicateHandle
     // failing in the past has been when the wrong python2 package spawned this
@@ -134,7 +137,7 @@ pub unsafe fn setup(build: &mut Build) {
     // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
     // mode" here is that we only clean everything up when the build system
     // dies, not when the python parent does, so not too bad.
-    if r != 0 {
+    if r.is_err() {
         CloseHandle(job);
     }
 }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index f136690592d..d23c262aad2 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -144,6 +144,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     // FIXME: Used by filetime, but we should not be triggering on external dependencies.
     (Some(Mode::Rustc), "emulate_second_only_system", None),
     (Some(Mode::ToolRustc), "emulate_second_only_system", None),
+    // Needed to avoid the need to copy windows.lib into the sysroot.
+    (Some(Mode::Rustc), "windows_raw_dylib", None),
+    (Some(Mode::ToolRustc), "windows_raw_dylib", None),
 ];
 
 /// A structure representing a Rust compiler.
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 93e53d383cd..9a6aaffe22b 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -155,29 +155,30 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
     fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
         use std::ffi::OsStr;
         use std::os::windows::ffi::OsStrExt;
-        use std::ptr;
 
-        use winapi::shared::minwindef::{DWORD, WORD};
-        use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
-        use winapi::um::handleapi::CloseHandle;
-        use winapi::um::ioapiset::DeviceIoControl;
-        use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT};
-        use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT;
-        use winapi::um::winnt::{
-            FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE,
-            IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR,
+        use windows::{
+            core::PCWSTR,
+            Win32::Foundation::{CloseHandle, HANDLE},
+            Win32::Storage::FileSystem::{
+                CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS,
+                FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
+                MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING,
+            },
+            Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT,
+            Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT},
+            Win32::System::IO::DeviceIoControl,
         };
 
         #[allow(non_snake_case)]
         #[repr(C)]
         struct REPARSE_MOUNTPOINT_DATA_BUFFER {
-            ReparseTag: DWORD,
-            ReparseDataLength: DWORD,
-            Reserved: WORD,
-            ReparseTargetLength: WORD,
-            ReparseTargetMaximumLength: WORD,
-            Reserved1: WORD,
-            ReparseTarget: WCHAR,
+            ReparseTag: u32,
+            ReparseDataLength: u32,
+            Reserved: u16,
+            ReparseTargetLength: u16,
+            ReparseTargetMaximumLength: u16,
+            Reserved1: u16,
+            ReparseTarget: u16,
         }
 
         fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
@@ -193,17 +194,20 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
 
         let path = to_u16s(junction)?;
 
-        unsafe {
-            let h = CreateFileW(
-                path.as_ptr(),
-                GENERIC_WRITE,
+        let h = unsafe {
+            CreateFileW(
+                PCWSTR(path.as_ptr()),
+                FILE_ACCESS_FLAGS(GENERIC_WRITE),
                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                ptr::null_mut(),
+                None,
                 OPEN_EXISTING,
                 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
-                ptr::null_mut(),
-            );
+                HANDLE::default(),
+            )
+        }
+        .map_err(|_| io::Error::last_os_error())?;
 
+        unsafe {
             #[repr(C, align(8))]
             struct Align8<T>(T);
             let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
@@ -219,27 +223,29 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
             }
             *buf.offset(i) = 0;
             i += 1;
+
             (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
-            (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
-            (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
-            (*db).ReparseDataLength = (*db).ReparseTargetLength as DWORD + 12;
+            (*db).ReparseTargetMaximumLength = (i * 2) as u16;
+            (*db).ReparseTargetLength = ((i - 1) * 2) as u16;
+            (*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32;
 
-            let mut ret = 0;
-            let res = DeviceIoControl(
-                h as *mut _,
+            let mut ret = 0u32;
+            DeviceIoControl(
+                h,
                 FSCTL_SET_REPARSE_POINT,
-                db.cast(),
+                Some(db.cast()),
                 (*db).ReparseDataLength + 8,
-                ptr::null_mut(),
+                None,
                 0,
-                &mut ret,
-                ptr::null_mut(),
-            );
-
-            let out = if res == 0 { Err(io::Error::last_os_error()) } else { Ok(()) };
-            CloseHandle(h);
-            out
+                Some(&mut ret),
+                None,
+            )
+            .ok()
+            .map_err(|_| io::Error::last_os_error())?;
         }
+
+        unsafe { CloseHandle(h) };
+        Ok(())
     }
 }
 
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 0db043a4fca..85fd6523c82 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -26,4 +26,10 @@ libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.5"
-winapi = { version = "0.3", features = ["winerror"] }
+
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+    "Win32_Foundation",
+    "Win32_System_Diagnostics_Debug",
+]
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index a5dc6859732..725f7a1515c 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -232,7 +232,7 @@ mod imp {
     use miow::iocp::{CompletionPort, CompletionStatus};
     use miow::pipe::NamedPipe;
     use miow::Overlapped;
-    use winapi::shared::winerror::ERROR_BROKEN_PIPE;
+    use windows::Win32::Foundation::ERROR_BROKEN_PIPE;
 
     struct Pipe<'a> {
         dst: &'a mut Vec<u8>,
@@ -295,7 +295,7 @@ mod imp {
             match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
                 Ok(_) => Ok(()),
                 Err(e) => {
-                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
+                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE.0 as i32) {
                         self.done = true;
                         Ok(())
                     } else {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 4d9010d3c4b..a4003072310 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -49,8 +49,10 @@ const FAKE_SRC_BASE: &str = "fake-test-src-base";
 #[cfg(windows)]
 fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     use std::sync::Mutex;
-    use winapi::um::errhandlingapi::SetErrorMode;
-    use winapi::um::winbase::SEM_NOGPFAULTERRORBOX;
+
+    use windows::Win32::System::Diagnostics::Debug::{
+        SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE,
+    };
 
     static LOCK: Mutex<()> = Mutex::new(());
 
@@ -62,6 +64,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     // termination by design. This mode is inherited by all child processes.
     unsafe {
         let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
+        let old_mode = THREAD_ERROR_MODE(old_mode);
         SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
         let r = f();
         SetErrorMode(old_mode);
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d71fa5c8be5..a9eb6c8d03f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -260,6 +260,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "valuable",
     "version_check",
     "wasi",
+    "windows",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",