nt_user_call/
functions.rs

1//! Provides abstractions for all entries in the `apfnSimpleCall` table.
2//!
3//! Depending on the operating system the program is running on, the syscalls are invoked differently:
4//! - On Windows 11 or newer, the function is loaded from `win32u.dll`.
5//! - On older operating systems the function is invoked via the `NtUserCall*` family of syscalls, loaded from `win32u.dll`.
6//! - On Windows 7 to 8.1, `NtUserCall*` syscalls are not exported, and the syscalls are invoked directly via inline assembly.
7//!
8//! Function resolution happens the first time the function is called.
9//!
10//! Errors:
11//! - [`UserCallError::OsNotSupported`]: The crate does not contain table entry indices.
12//! - [`UserCallError::LibraryNotFound`]: A required DLL has not been loaded.
13//! - [`UserCallError::CallNotFound`]: The function cannot be invoked on the current operating system.
14
15use std::ffi::c_void;
16use std::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
17
18use windows::Win32::Devices::Display::HDEV;
19use windows::Win32::Graphics::Gdi::HMONITOR;
20use windows::Win32::UI::Input::KeyboardAndMouse::HKL;
21use windows::Win32::UI::WindowsAndMessaging::MESSAGEBOX_STYLE;
22use windows::{
23    core::{w, PCSTR},
24    Win32::{
25        Foundation::{
26            BOOL, HANDLE, HWND, LPARAM, LRESULT, NTSTATUS, POINT, UNICODE_STRING, WPARAM,
27        },
28        Graphics::Gdi::{HDC, HRGN},
29        System::{
30            LibraryLoader::{GetModuleHandleW, GetProcAddress},
31            StationsAndDesktops::HDESK,
32        },
33        UI::WindowsAndMessaging::{GET_CLASS_LONG_INDEX, HDWP, HICON, HMENU, SYSTEM_METRICS_INDEX},
34    },
35};
36
37use crate::{
38    error::UserCallError,
39    indices::get_index,
40    version::{get_os_version, has_dedicated_syscalls, OsVersion},
41};
42trait IntoCallParam {
43    fn into_call_param(self) -> usize;
44}
45
46macro_rules! into_call_param_self_as {
47    ($($type:ty),+) => {
48        $(
49        impl IntoCallParam for $type {
50            fn into_call_param(self) -> usize {
51                self as _
52            }
53        }
54    )+
55    };
56}
57
58macro_rules! into_call_param_self_0_as {
59    ($($type:ty),+) => {
60        $(
61        impl IntoCallParam for $type {
62            fn into_call_param(self) -> usize {
63                self.0 as _
64            }
65        }
66    )+
67    };
68}
69
70macro_rules! into_call_param_transmute {
71    ($($type:ty),+) => {
72        $(
73        impl IntoCallParam for $type {
74            fn into_call_param(self) -> usize {
75                // SAFETY: Self is layout-compatible with `usize`.
76                unsafe {
77                    std::mem::transmute(self)
78                }
79            }
80        }
81    )+
82    };
83}
84
85impl<T> IntoCallParam for *const T {
86    fn into_call_param(self) -> usize {
87        self as _
88    }
89}
90
91impl<T> IntoCallParam for *mut T {
92    fn into_call_param(self) -> usize {
93        self as _
94    }
95}
96
97into_call_param_self_as!(i16, i32, u32, usize);
98into_call_param_self_0_as!(
99    BOOL,
100    GET_CLASS_LONG_INDEX,
101    LRESULT,
102    LPARAM,
103    MESSAGEBOX_STYLE,
104    SYSTEM_METRICS_INDEX,
105    WPARAM
106);
107into_call_param_transmute!(HANDLE, HDC, HDESK, HDEV, HRGN, HWND);
108
109trait FromCallReturn {
110    fn from_call_return(value: usize) -> Self;
111}
112
113macro_rules! from_call_return_as {
114    ($($type:ty),+) => {
115        $(
116        impl FromCallReturn for $type {
117            fn from_call_return(value: usize) -> Self {
118                value as _
119            }
120        }
121    )+
122    };
123}
124
125macro_rules! from_call_return_self {
126    ($($type:ty),+) => {
127        $(
128        impl FromCallReturn for $type {
129            fn from_call_return(value: usize) -> Self {
130                Self(value as _)
131            }
132        }
133    )+
134    };
135}
136
137impl FromCallReturn for () {
138    fn from_call_return(_value: usize) -> Self {}
139}
140
141impl<T> FromCallReturn for *const T {
142    fn from_call_return(value: usize) -> Self {
143        value as _
144    }
145}
146
147impl<T> FromCallReturn for *mut T {
148    fn from_call_return(value: usize) -> Self {
149        value as _
150    }
151}
152
153from_call_return_as!(i32, u32, usize);
154from_call_return_self!(
155    BOOL, HANDLE, HDESK, HDWP, HICON, HKL, HMENU, HMONITOR, HWND, LPARAM, LRESULT, NTSTATUS
156);
157
158macro_rules! nt_user_call_fn_body {
159    ( $syscall:ident $call:ident ) => {{
160        user_call::$syscall($call)
161    }};
162
163    ( $syscall:ident $call:ident $($paramname:ident)* ) => {{
164        user_call::$syscall($(IntoCallParam::into_call_param($paramname)),*, $call)
165    }};
166}
167
168macro_rules! nt_user_call_fn {
169    (
170        #[doc = $doc:literal] $syscall:ident $call:ident $vis:vis fn $name:ident ($($paramname:ident: $paramtype:ty),*) -> $rettype:ty
171    ) => {
172        paste::paste! {
173            #[doc = $doc]
174            #[allow(clippy::empty_docs, clippy::missing_safety_doc)]
175            #[expect(non_snake_case)]
176            $vis unsafe fn [< NtUser $name >] ($($paramname: $paramtype),*) -> Result<$rettype, UserCallError> {
177                if has_dedicated_syscalls() {
178                    // Starting with Windows 11, NtUserCall* has been replaced with dedicated syscalls in win32u.
179                    crate::macros::load_runtime_fn_body!(["win32u"] $name($($paramname: $paramtype),*) -> $rettype)
180                } else {
181                    static CALL_ATOMIC: AtomicU32 = AtomicU32::new(u16::MAX as u32 + 1);
182
183                    let call_index = match CALL_ATOMIC.load(Ordering::Relaxed) {
184                        index@..=0xFFFFu32 => index,
185                        u32::MAX => return Err(UserCallError::CallNotFound),
186                        _ => match get_index(NtUserCall::$name) {
187                            Some(index) => {
188                                CALL_ATOMIC.store(index as _, Ordering::SeqCst);
189                                index as _
190                            },
191                            None => {
192                                CALL_ATOMIC.store(u32::MAX, Ordering::SeqCst);
193                                return Err(UserCallError::CallNotFound);
194                            }
195                        }
196                    };
197
198                    let $call = call_index;
199
200                    nt_user_call_fn_body!($syscall $call $($paramname)*).map(FromCallReturn::from_call_return)
201                }
202            }
203        }
204    };
205}
206
207macro_rules! nt_user_call {
208    ( #![doc = $enumdoc:literal] $(#[doc = $doc:literal] $syscall:ident $vis:vis fn $name:ident ($($funcdef:tt)*) -> $rettype:ty;)+ ) => {
209        #[doc = $enumdoc]
210        #[allow(non_camel_case_types)]
211        #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
212        pub enum NtUserCall {
213            $($name),+
214        }
215
216        $(nt_user_call_fn! { #[doc = $doc] $syscall CALL $vis fn $name ($($funcdef)*) -> $rettype })+
217    };
218}
219
220nt_user_call! {
221    #![doc = r#"
222    The sum of all functions accessible via the `NtUserCall*` family of system calls in all supported operating systems.
223    The variants will be mapped to the respective function indices in [`crate::indices`] at runtime.
224    "#]
225
226    // NoParam
227    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createmenu>"]
228    NtUserCallNoParam pub fn CreateMenu() -> HMENU;
229
230    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createpopupmenu>"]
231    NtUserCallNoParam pub fn CreatePopupMenu() -> HMENU;
232
233    #[doc = ""]
234    NtUserCallNoParam pub fn AllowForegroundActivation() -> ();
235
236    #[doc = ""]
237    NtUserCallNoParam pub fn CancelQueueEventCompletionPacket() -> ();
238
239    #[doc = ""]
240    NtUserCallNoParam pub fn ClearWakeMask() -> ();
241
242    #[doc = ""]
243    NtUserCallNoParam pub fn CreateSystemThreads() -> ();
244
245    #[doc = ""]
246    NtUserCallNoParam pub fn DesktopHasWatermarkText() -> BOOL;
247
248    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-destroycaret>"]
249    NtUserCallNoParam pub fn DestroyCaret() -> BOOL;
250
251    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting>"]
252    NtUserCallNoParam pub fn DisableProcessWindowsGhosting() -> ();
253
254    #[doc = ""]
255    NtUserCallNoParam pub fn DrainThreadCoreMessagingCompletions() -> BOOL;
256
257    #[doc = ""]
258    NtUserCallNoParam pub fn GetDeviceChangeInfo() -> u32;
259
260    #[doc = ""]
261    NtUserCallNoParam pub fn GetIMEShowStatus() -> BOOL;
262
263    #[doc = ""]
264    NtUserCallNoParam pub fn GetInputDesktop() -> HDESK;
265
266    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessagepos>"]
267    NtUserCallNoParam pub fn GetMessagePos() -> u32;
268
269    #[doc = ""]
270    NtUserCallNoParam pub fn GetQueueIocp() -> HANDLE;
271
272    #[doc = ""]
273    NtUserCallNoParam pub fn GetUnpredictedMessagePos() -> u32;
274
275    #[doc = ""]
276    NtUserCallNoParam pub fn HandleSystemThreadCreationFailure() -> BOOL;
277
278    #[doc = ""]
279    NtUserCallNoParam pub fn HideCursorNoCapture() -> ();
280
281    #[doc = ""]
282    NtUserCallNoParam pub fn IsQueueAttached() -> BOOL;
283
284    #[doc = ""]
285    NtUserCallNoParam pub fn LoadCursorsAndIcons() -> BOOL;
286
287    #[doc = ""]
288    NtUserCallNoParam pub fn LoadUserApiHook() -> ();
289
290    #[doc = ""]
291    NtUserCallNoParam pub fn PrepareForLogoff() -> BOOL;
292
293    #[doc = ""]
294    NtUserCallNoParam pub fn ReassociateQueueEventCompletionPacket() -> BOOL;
295
296    #[doc = ""]
297    NtUserCallNoParam pub fn ReleaseCapture() -> BOOL;
298
299    #[doc = ""]
300    NtUserCallNoParam pub fn RemoveQueueCompletion() -> BOOL;
301
302    #[doc = ""]
303    NtUserCallNoParam pub fn ResetDblClk() -> BOOL;
304
305    #[doc = ""]
306    NtUserCallNoParam pub fn ZapActiveAndFocus() -> BOOL;
307
308    #[doc = ""]
309    NtUserCallNoParam pub fn RemoteConsoleShadowStop() -> ();
310
311    #[doc = ""]
312    NtUserCallNoParam pub fn RemoteDisconnect() -> ();
313
314    #[doc = ""]
315    NtUserCallNoParam pub fn RemoteLogoff() -> NTSTATUS;
316
317    #[doc = "Always returns STATUS_NOT_SUPPORTED."]
318    NtUserCallNoParam pub fn RemoteNtSecurity() -> NTSTATUS;
319
320    #[doc = "Always returns STATUS_NOT_SUPPORTED."]
321    NtUserCallNoParam pub fn EditionPostKeyboardInputMessage() -> NTSTATUS;
322
323    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
324    NtUserCallNoParam pub fn RemoteShadowSetup() -> NTSTATUS;
325
326    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
327    NtUserCallNoParam pub fn RemoteShadowStop() -> NTSTATUS;
328
329    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
330    NtUserCallNoParam pub fn RemotePassthruEnable() -> NTSTATUS;
331
332    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
333    NtUserCallNoParam pub fn RemotePassthruDisable() -> NTSTATUS;
334
335    #[doc = ""]
336    NtUserCallNoParam pub fn RemoteConnectState() -> usize;
337
338    #[doc = ""]
339    NtUserCallNoParam pub fn TraceLoggingSendMixedModeTelemetry() -> BOOL;
340
341    #[doc = ""]
342    NtUserCallNoParam pub fn UpdatePerUserImmEnabling() -> BOOL;
343
344    #[doc = ""]
345    NtUserCallNoParam pub fn UserPowerCalloutWorker() -> BOOL;
346
347    #[doc = "May only be called by CSRSS, returns STATUS_UNSUPPORTED otherwise."]
348    NtUserCallNoParam pub fn WakeRITForShutdown() -> NTSTATUS;
349
350    #[doc = ""]
351    NtUserCallNoParam pub fn DoInitMessagePumpHook() -> BOOL;
352
353    #[doc = ""]
354    NtUserCallNoParam pub fn DoUninitMessagePumpHook() -> BOOL;
355
356    #[doc = ""]
357    NtUserCallNoParam pub fn EnableMiPShellThread() -> BOOL;
358
359    #[doc = ""]
360    NtUserCallNoParam pub fn IsMiPShellThreadEnabled() -> BOOL;
361
362    #[doc = ""]
363    NtUserCallNoParam pub fn EnableMouseInPointerForThread() -> BOOL;
364
365    #[doc = ""]
366    NtUserCallNoParam pub fn DeferredDesktopRotation() -> i32;
367
368    #[doc = ""]
369    NtUserCallNoParam pub fn EnablePerMonitorMenuScaling() -> BOOL;
370
371    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-begindeferwindowpos>"]
372    NtUserCallOneParam pub fn BeginDeferWindowPos(nNumWindows: i32) -> HDWP;
373
374    #[doc = ""]
375    NtUserCallOneParam pub fn GetSendMessageReceiver(dwThreadId: u32) -> HWND;
376
377    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-windowfromdc>"]
378    NtUserCallOneParam pub fn WindowFromDC(hdc: HDC) -> HWND;
379
380    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-allowsetforegroundwindow>"]
381    NtUserCallOneParam pub fn AllowSetForegroundWindow(dwProcessId: u32) -> u32;
382
383    #[doc = ""]
384    NtUserCallOneParam pub fn CreateEmptyCursorObject(param: BOOL) -> u32;
385
386    #[doc = ""]
387    NtUserCallOneParam pub fn CsDdeUninitialize(dde_object: usize) -> BOOL;
388
389    #[doc = "NOP"]
390    NtUserCallOneParam pub fn DirectedYield(param: usize) -> usize;
391
392    #[doc = ""]
393    NtUserCallOneParam pub fn KbdNlsFuncTypeDummy(param: usize) -> u32;
394
395    #[doc = ""]
396    NtUserCallOneParam pub fn EditionGetExecutionEvironment(param: usize) -> BOOL;
397
398    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumclipboardformats>"]
399    NtUserCallOneParam pub fn EnumClipboardFormats(format: u32) -> u32;
400
401    #[doc = ""]
402    NtUserCallOneParam pub fn GetInputEvent(wake_mask_and_flags: u32) -> HANDLE;
403
404    #[doc = ""]
405    NtUserCallOneParam pub fn GetKeyboardLayout(dwThread: u32) -> HKL;
406
407    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardtype>"]
408    NtUserCallOneParam pub fn GetKeyboardType(nTypeFlag: i32) -> i32;
409
410    #[doc = ""]
411    NtUserCallOneParam pub fn GetProcessDefaultLayout(pdwDefaultLayout: *mut u32) -> BOOL;
412
413    #[doc = ""]
414    NtUserCallOneParam pub fn GetQueueStatus(flags: u32) -> u32;
415
416    #[doc = ""]
417    NtUserCallOneParam pub fn GetWinStationInfo(ptr: *mut c_void) -> BOOL;
418
419    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-locksetforegroundwindow>"]
420    NtUserCallOneParam pub fn LockSetForegroundWindow(uLockCode: u32) -> BOOL;
421
422    #[doc = ""]
423    NtUserCallOneParam pub fn LW_LoadFonts(unknown: i32) -> BOOL;
424
425    #[doc = ""]
426    NtUserCallOneParam pub fn MapDesktopObject(handle: *mut c_void) -> *mut c_void;
427
428    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebeep>"]
429    NtUserCallOneParam pub fn MessageBeep(uType: MESSAGEBOX_STYLE) -> BOOL;
430
431    #[doc = ""]
432    NtUserCallOneParam pub fn PlayEventSound(unknown: u32) -> BOOL;
433
434    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postquitmessage>"]
435    NtUserCallOneParam pub fn PostQuitMessage(nExitCode: i32) -> ();
436
437    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-realizepalette>"]
438    NtUserCallOneParam pub fn RealizePalette(hdc: HDC) -> u32;
439
440    #[doc = ""]
441    NtUserCallOneParam pub fn RegisterLPK(unknown: u32) -> BOOL;
442
443    #[doc = ""]
444    NtUserCallOneParam pub fn RegisterSystemThread(unknown_flags: u32) -> BOOL;
445
446    #[doc = ""]
447    NtUserCallOneParam pub fn RemoteReconnect(unknown: *mut c_void) -> NTSTATUS;
448
449    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
450    NtUserCallOneParam pub fn RemoteThinwireStats(stats: *mut c_void) -> NTSTATUS;
451
452    #[doc = ""]
453    NtUserCallOneParam pub fn ReleaseDC(hdc: HDC) -> BOOL;
454
455    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
456    NtUserCallOneParam pub fn RemoteNotify(unknown: *const u32) -> NTSTATUS;
457
458    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-replymessage>"]
459    NtUserCallOneParam pub fn ReplyMessage(lResult: LRESULT) -> BOOL;
460
461    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcaretblinktime>"]
462    NtUserCallOneParam pub fn SetCaretBlinkTime(uMSeconds: u32) -> BOOL;
463
464    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdoubleclicktime>"]
465    NtUserCallOneParam pub fn SetDoubleClickTime(unnamedParam1: u32) -> BOOL;
466
467    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setmessageextrainfo>"]
468    NtUserCallOneParam pub fn SetMessageExtraInfo(lParam: LPARAM) -> LPARAM;
469
470    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdefaultlayout>"]
471    NtUserCallOneParam pub fn SetProcessDefaultLayout(dwDefaultLayout: u32) -> BOOL;
472
473    #[doc = "May only be called by winlogon, returns FALSE otherwise."]
474    NtUserCallOneParam pub fn SetWatermarkStrings(param: *const UNICODE_STRING) -> BOOL;
475
476    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showcursor>"]
477    NtUserCallOneParam pub fn ShowCursor(bShow: BOOL) -> i32;
478
479    #[doc = ""]
480    NtUserCallOneParam pub fn ShowStartGlass(param: u32) -> BOOL;
481
482    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-swapmousebutton>"]
483    NtUserCallOneParam pub fn SwapMouseButton(fSwap: BOOL) -> BOOL;
484
485    #[doc = ""]
486    NtUserCallOneParam pub fn WOWModuleUnload(param: i16) -> BOOL;
487
488    #[doc = "May only be called by winlogon."]
489    NtUserCallOneParam pub fn DwmLockScreenUpdates(lock: BOOL) -> i32;
490
491    #[doc = "May only be called by dwm, returns FALSE otherwise."]
492    NtUserCallOneParam pub fn EnableSessionForMMCSS(enable: BOOL) -> BOOL;
493
494    #[doc = ""]
495    NtUserCallOneParam pub fn SetWaitForQueueAttach(wait: BOOL) -> BOOL;
496
497    #[doc = ""]
498    NtUserCallOneParam pub fn ThreadMessageQueueAttached(thread_id: u32) -> BOOL;
499
500    #[doc = "May only be called by the immersive broker, otherwise returns 0 with GetLastError() == ERROR_ACCESS_DENIED."]
501    NtUserCallOneParam pub fn PostUIActions(wparam: WPARAM) -> LRESULT;
502
503    #[doc = ""]
504    NtUserCallOneParam pub fn EnsureDpiDepSysMetCacheForPlateau(dpi: u32) -> BOOL;
505
506    #[doc = ""]
507    NtUserCallOneParam pub fn ForceEnableNumpadTranslation(param: u32) -> u32;
508
509    #[doc = ""]
510    NtUserCallOneParam pub fn SetTSFEventState(state: u32) -> BOOL;
511
512    #[doc = ""]
513    NtUserCallOneParam pub fn SetShellChangeNotifyHWND(hwnd: HWND) -> BOOL;
514
515    #[doc = ""]
516    NtUserCallHwnd pub fn DeregisterShellHookWindow(hwnd: HWND) -> BOOL;
517
518    #[doc = ""]
519    NtUserCallHwnd pub fn DWP_GetEnabledPopup(hwnd: HWND) -> usize;
520
521    #[doc = ""]
522    NtUserCallHwnd pub fn DWP_GetEnabledPopupOffset(hwnd: HWND) -> usize;
523
524    #[doc = ""]
525    NtUserCallHwnd pub fn GetModernAppWindow(hwnd: HWND) -> HWND;
526
527    #[doc = ""]
528    NtUserCallHwnd pub fn GetWindowContextHelpId(hwnd: HWND) -> ();
529
530    #[doc = ""]
531    NtUserCallHwnd pub fn RegisterShellHookWindow(hwnd: HWND) -> ();
532
533    #[doc = ""]
534    NtUserCallHwnd pub fn SetMsgBox(hwnd: HWND) -> BOOL;
535
536    #[doc = ""]
537    NtUserCallHwndSafe pub fn InitThreadCoreMessagingIocp(hwnd: HWND) -> HANDLE;
538
539    #[doc = ""]
540    NtUserCallHwndSafe pub fn ScheduleDispatchNotification(hwnd: HWND) -> i32;
541
542    #[doc = ""]
543    NtUserCallHwndSafe pub fn SetProgmanWindow(hwnd: HWND) -> BOOL;
544
545    #[doc = ""]
546    NtUserCallHwndOpt pub fn SetTaskmanWindow(hwnd: HWND) -> BOOL;
547
548    #[doc = "See <https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclasslongptrw>. `index` may be GCLP_HCURSOR or GCLP_HICON."]
549    NtUserCallHwndParam pub fn GetClassIcoCur(hwnd: HWND, index: GET_CLASS_LONG_INDEX) -> HICON;
550
551    #[doc = ""]
552    NtUserCallHwndParam pub fn ClearWindowState(hwnd: HWND, state: u32) -> BOOL;
553
554    #[doc = ""]
555    NtUserCallHwndParam pub fn KillSystemTimer(hwnd: HWND, timer_id: usize) -> BOOL;
556
557    #[doc = ""]
558    NtUserCallHwndParam pub fn NotifyOverlayWindow(hwnd: HWND, param: BOOL) -> BOOL;
559
560    #[doc = "May only be called by the immersive broker, otherwise returns FALSE with GetLastError() == ERROR_ACCESS_DENIED."]
561    NtUserCallHwndParam pub fn RegisterKeyboardCorrectionCallout(hwnd: HWND, param: u32) -> BOOL;
562
563    #[doc = ""]
564    NtUserCallHwndParam pub fn SetDialogPointer(hwnd: HWND, param: u32) -> BOOL;
565
566    #[doc = ""]
567    NtUserCallHwndParam pub fn SetVisible(hwnd: HWND, param: u32) -> BOOL;
568
569    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowcontexthelpid>"]
570    NtUserCallHwndParam pub fn SetWindowContextHelpId(hwnd: HWND, help_context_identifier: u32) -> BOOL;
571
572    #[doc = ""]
573    NtUserCallHwndParam pub fn SetWindowState(hwnd: HWND, state: u32) -> BOOL;
574
575    #[doc = ""]
576    NtUserCallHwndParam pub fn RegisterWindowArrangementCallout(hwnd: HWND, param: u32) -> BOOL;
577
578    #[doc = "May only be called by the immersive broker, otherwise returns 0 with GetLastError() == ERROR_ACCESS_DENIED."]
579    NtUserCallHwndParam pub fn EnableModernAppWindowKeyboardIntercept(hwnd: HWND, param: u32) -> BOOL;
580
581    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-arrangeiconicwindows>"]
582    NtUserCallHwndLock pub fn ArrangeIconicWindows(hwnd: HWND) -> u32;
583
584    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawmenubar>"]
585    NtUserCallHwndLock pub fn DrawMenuBar(hwnd: HWND) -> BOOL;
586
587    #[doc = ""]
588    NtUserCallHwndLock pub fn CheckImeShowStatusInThread(hwnd: HWND) -> BOOL;
589
590    #[doc = ""]
591    NtUserCallHwndLock pub fn GetSysMenuHandle(hwnd: HWND) -> HMENU;
592
593    #[doc = ""]
594    NtUserCallHwndLock pub fn GetSysMenuOffset(hwnd: HWND) -> usize;
595
596    #[doc = "Equivalent to `SetWindowPos(hwnd, HWND::default(), 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)`"]
597    NtUserCallHwndLock pub fn RedrawFrame(hwnd: HWND) -> BOOL;
598
599    #[doc = "Redraws and calls WH_SYSMSGFILTER hooks if a tray window"]
600    NtUserCallHwndLock pub fn RedrawFrameAndHook(hwnd: HWND) -> BOOL;
601
602    #[doc = ""]
603    NtUserCallHwndLock pub fn SetDialogSystemMenu(hwnd: HWND) -> BOOL;
604
605    #[doc = ""]
606    NtUserCallHwndLock pub fn StubSetForegroundWindow(hwnd: HWND) -> BOOL;
607
608    #[doc = ""]
609    NtUserCallHwndLock pub fn SetSysMenu(hwnd: HWND) -> BOOL;
610
611    #[doc = ""]
612    NtUserCallHwndLock pub fn UpdateClientRect(hwnd: HWND) -> BOOL;
613
614    #[doc = ""]
615    NtUserCallHwndLock pub fn UpdateWindow(hwnd: HWND) -> BOOL;
616
617    #[doc = "Needs IAM access."]
618    NtUserCallHwndLock pub fn SetActiveImmersiveWindow(hwnd: HWND) -> BOOL;
619
620    #[doc = ""]
621    NtUserCallHwndLock pub fn SetCancelRotationDelayHintWindow(hwnd: HWND) -> BOOL;
622
623    #[doc = "Needs IAM access."]
624    NtUserCallHwndLock pub fn GetWindowTrackInfoAsync(hwnd: HWND) -> BOOL;
625
626    #[doc = ""]
627    NtUserCallHwndParamLock pub fn BroadcastImeShowStatusChange(hwnd: HWND, status: BOOL) -> BOOL;
628
629    #[doc = ""]
630    NtUserCallHwndParamLock pub fn SetModernAppWindow(hwnd: HWND, modern: HWND) -> BOOL;
631
632    #[doc = ""]
633    NtUserCallHwndParamLock pub fn RedrawTitle(hwnd: HWND, param: u32) -> BOOL;
634
635    #[doc = ""]
636    NtUserCallHwndParamLock pub fn ShowOwnedPopups(hwnd: HWND, show: BOOL) -> BOOL;
637
638    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-switchtothiswindow>"]
639    NtUserCallHwndParamLock pub fn SwitchToThisWindow(hwnd: HWND, unknown: BOOL) -> ();
640
641    #[doc = ""]
642    NtUserCallHwndParamLock pub fn UpdateWindows(first_hwnd: HWND, region: HRGN) -> BOOL;
643
644    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-validatergn>"]
645    NtUserCallHwndParamLock pub fn ValidateRgn(hwnd: HWND, hrgn: HRGN) -> BOOL;
646
647    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow>"]
648    NtUserCallHwndParamLock pub fn MonitorFromWindow(hwnd: HWND, dwFlags: u32) -> HMONITOR;
649
650    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow>"]
651    NtUserCallHwndParamLockSafe pub fn EnableWindow(hwnd: HWND, fEnable: BOOL) -> BOOL;
652
653    #[doc = ""]
654    NtUserCallTwoParam pub fn ChangeWindowMessageFilter(message: u32, dwFlag: u32) -> BOOL;
655
656    #[doc = "1 = regular, 2 = logical pos from dpi awareness context"]
657    NtUserCallTwoParam pub fn GetCursorPos(point: *mut POINT, which: u32) -> BOOL;
658
659    #[doc = ""]
660    NtUserCallTwoParam pub fn GetHDevName(hdev: HDEV, buffer: *mut [u8; 64]) -> BOOL;
661
662    #[doc = ""]
663    NtUserCallTwoParam pub fn InitAnsiOem(param1: *mut c_void, param2: *mut c_void) -> BOOL;
664
665    #[doc = ""]
666    NtUserCallTwoParam pub fn NlsKbdSendIMENotification(param1: u32, param2: u32) -> ();
667
668    #[doc = "May only be called by DWM, returns FALSE with GetLastError() == ERROR_ACCESS_DENIED otherwise."]
669    NtUserCallTwoParam pub fn RegisterGhostWindow(hwnd: HWND, ghost: HWND) -> BOOL;
670
671    #[doc = ""]
672    NtUserCallTwoParam pub fn RegisterLogonProcess(process_id: u32, param2: usize) -> BOOL;
673
674    #[doc = ""]
675    NtUserCallTwoParam pub fn RegisterSiblingFrostWindow(hwnd: HWND, frost: HWND) -> BOOL;
676
677    #[doc = ""]
678    NtUserCallTwoParam pub fn RegisterUserHungAppHandlers(unknown: usize, event: HANDLE) -> BOOL;
679
680    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
681    NtUserCallTwoParam pub fn RemoteShadowCleanup(buffer: *const c_void, size: usize) -> NTSTATUS;
682
683    #[doc = "May only be called by CSRSS, returns STATUS_ACCESS_DENIED otherwise."]
684    NtUserCallTwoParam pub fn RemoteShadowStart(buffer: *const c_void, size: usize) -> NTSTATUS;
685
686    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcaretpos>"]
687    NtUserCallTwoParam pub fn SetCaretPos(x: i32, y: i32) -> BOOL;
688
689    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursorpos>"]
690    NtUserCallTwoParam pub fn SetCursorPos(x: i32, y: i32) -> BOOL;
691
692    #[doc = "<https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setphysicalcursorpos>"]
693    NtUserCallTwoParam pub fn SetPhysicalCursorPos(x: i32, y: i32) -> BOOL;
694
695    #[doc = ""]
696    NtUserCallTwoParam pub fn SetThreadQueueMergeSetting(thread_id: u32, setting: BOOL) -> BOOL;
697
698    #[doc = ""]
699    NtUserCallTwoParam pub fn UnhookWindowsHook(hook: i32, param: i32) -> BOOL;
700
701    #[doc = ""]
702    NtUserCallTwoParam pub fn WOWCleanup(param1: usize, param2: u32) -> BOOL;
703
704    #[doc = ""]
705    NtUserCallTwoParam pub fn EnableShellWindowManagementBehavior(mask: u32, behavior: u32) -> BOOL;
706
707    #[doc = ""]
708    NtUserCallTwoParam pub fn CitSetInfo(which: u32, info: *mut c_void) -> NTSTATUS;
709
710    #[doc = ""]
711    NtUserCallTwoParam pub fn ScaleSystemMetricForDPIWithoutCache(metric: SYSTEM_METRICS_INDEX, dpi: u32) -> i32;
712}
713
714macro_rules! nt_user_call_syscall_fn {
715        (($paramname:ident: $paramtype:ty) -> $rettype:ty) => {
716            unsafe extern "system" fn syscall<const SYSCALL_NR: usize>(
717                $paramname: $paramtype
718            ) -> $rettype {
719                use std::arch::asm;
720                let result;
721
722                asm!(
723                    "mov eax, {syscall_nr}",
724                    "syscall",
725                    in("r10") $paramname,
726                    lateout("rax") result,
727                    syscall_nr = const(SYSCALL_NR),
728                    options(nostack),
729                    );
730
731                result
732            }
733        };
734
735        (($paramname:ident: $paramtype:ty, $param2name:ident: $param2type:ty) -> $rettype:ty) => {
736            unsafe extern "system" fn syscall<const SYSCALL_NR: usize>(
737                $paramname: $paramtype,
738                $param2name: $param2type,
739            ) -> $rettype {
740                use std::arch::asm;
741                let result;
742
743                asm!(
744                    "mov eax, {syscall_nr}",
745                    "syscall",
746                    in("r10") $paramname,
747                    in("rdx") $param2name,
748                    lateout("rax") result,
749                    syscall_nr = const(SYSCALL_NR),
750                    options(nostack),
751                    );
752
753                result
754            }
755        };
756
757        (($paramname:ident: $paramtype:ty, $param2name:ident: $param2type:ty, $param3name:ident: $param3type:ty) -> $rettype:ty) => {
758            unsafe extern "system" fn syscall<const SYSCALL_NR: usize>(
759                $paramname: $paramtype,
760                $param2name: $param2type,
761                $param3name: $param3type,
762            ) -> $rettype {
763                use std::arch::asm;
764                let result;
765
766                asm!(
767                    "mov eax, {syscall_nr}",
768                    "syscall",
769                    in("r10") $paramname,
770                    in("rdx") $param2name,
771                    in("r8") $param3name,
772                    lateout("rax") result,
773                    syscall_nr = const(SYSCALL_NR),
774                    options(nostack),
775                    );
776
777                result
778            }
779        };
780    }
781
782macro_rules! nt_user_call_alternate {
783        ($name:ident => => $rettype:ty => $($paramname:ident: $paramtype:ty),*) => {{
784            _ = FUNCTION.compare_exchange(
785                std::ptr::null_mut(),
786                UserCallError::CallNotFound as _,
787                Ordering::SeqCst,
788                Ordering::Relaxed,
789            );
790            return Err(UserCallError::CallNotFound);
791        }};
792
793        ($name:ident => $($(#[$cfg:meta])? $os:ident = $syscall_nr:literal),+ => $rettype:ty => $($paramname:ident: $paramtype:ty),*) => {{
794            println!(concat!("Function ", stringify!($name), " direct syscall"));
795
796            nt_user_call_syscall_fn!(($($paramname: $paramtype),+) -> $rettype);
797
798            let syscall: unsafe extern "system" fn($($paramtype),*) -> $rettype = match get_os_version() {
799                $(
800                    $(#[$cfg])?
801                    Ok(OsVersion::$os) => syscall::<$syscall_nr>,
802                )+
803                Ok(_) => {
804                    _ = FUNCTION.compare_exchange(
805                        std::ptr::null_mut(),
806                        UserCallError::OsNotSupported as usize as _,
807                        Ordering::SeqCst,
808                        Ordering::Relaxed,
809                    );
810
811                    return Err(UserCallError::OsNotSupported);
812                },
813                Err(err) => {
814                    _ = FUNCTION.compare_exchange(
815                        std::ptr::null_mut(),
816                        err as usize as _,
817                        Ordering::SeqCst,
818                        Ordering::Relaxed,
819                    );
820
821                    return Err(err);
822                },
823            };
824
825            syscall as _
826        }};
827    }
828
829macro_rules! nt_user_call_syscall {
830        (
831            $vis:vis fn $name:ident  ($($paramname:ident: $paramtype:ty),*) -> $rettype:ty $(=> $($(#[$cfg:meta])? $os:ident = $syscall_nr:literal),+)?
832        ) => {
833            #[expect(non_snake_case, clippy::missing_safety_doc)]
834            $vis unsafe fn $name($($paramname: $paramtype),*) -> Result<$rettype, UserCallError> {
835                type Function = unsafe extern "system" fn($($paramtype),*) -> $rettype;
836
837                static FUNCTION: AtomicPtr<c_void> = AtomicPtr::new(std::ptr::null_mut());
838
839                let mut ptr = FUNCTION.load(Ordering::Relaxed);
840
841                if ptr.is_null() {
842                    // SAFETY:
843                    let library = match unsafe { GetModuleHandleW(w!("win32u")).or_else(|_| GetModuleHandleW(w!("user32")))  } {
844                        Ok(library) => library,
845                        Err(_) => {
846                            _ = FUNCTION.compare_exchange(std::ptr::null_mut(), 0x1 as _, Ordering::AcqRel, Ordering::Acquire);
847                            return Err(UserCallError::LibraryNotFound);
848                        }
849                    };
850
851                    // SAFETY: GetProcAddress returns a valid function pointer if the function exists.
852                    ptr = match unsafe { GetProcAddress(library, PCSTR(concat!(stringify!($name), "\u{0}").as_ptr()))  } {
853                        // SAFETY: All syscall signatures are set in stone and will not change.
854                        Some(f) => f as _,
855                        None => {
856                            nt_user_call_alternate!($name =>  $($($(#[$cfg])? $os = $syscall_nr),+)? => $rettype => $($paramname: $paramtype),*)
857                        }
858                    };
859
860                    ptr = FUNCTION.compare_exchange(std::ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire).map_or_else(|p| p, |_| ptr);
861                }
862
863                if (ptr as usize) < u16::MAX as usize {
864                    println!("{:?}", ptr as usize);
865                    return Err(UserCallError::try_from(ptr as usize).unwrap());
866                }
867
868                // SAFETY: The function pointer has been validated and matches the syscall signature.
869                let function: Function = unsafe {
870                    std::mem::transmute(ptr)
871                };
872
873                // SAFETY: `function` is a valid function.
874                Ok(unsafe { function($($paramname),*) })
875            }
876        };
877    }
878
879/// Direct access to the underlying NtUserCall* syscalls.
880///
881/// <div class="warning">Those syscalls were removed in Windows 11. This module does not provide a reverse mapping to the dedicated syscalls.</div>
882pub mod user_call {
883    use super::{
884        c_void, get_os_version, w, AtomicPtr, GetModuleHandleW, GetProcAddress, Ordering,
885        OsVersion, UserCallError, PCSTR,
886    };
887
888    nt_user_call_syscall!(pub fn NtUserCallNoParam(call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4101, Win8 = 4102, Win81 = 4103);
889    nt_user_call_syscall!(pub fn NtUserCallOneParam(param: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4098, Win8 = 4099, Win81 = 4100);
890    nt_user_call_syscall!(pub fn NtUserCallHwnd(hwnd: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4364, Win8 = 4364, Win81 = 4365);
891    nt_user_call_syscall!(pub fn NtUserCallHwndSafe(hwnd: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4364, Win8 = 4364, Win81 = 4365);
892    nt_user_call_syscall!(pub fn NtUserCallHwndOpt(hwnd: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4743, Win8 = 4836, Win81 = 4869);
893    nt_user_call_syscall!(pub fn NtUserCallHwndParam(hwnd: usize, param: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4254, Win8 = 4254, Win81 = 4255);
894    nt_user_call_syscall!(pub fn NtUserCallHwndLock(hwnd: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4129, Win8 = 4130, Win81 = 4131);
895    nt_user_call_syscall!(pub fn NtUserCallHwndParamLock(hwnd: usize, param: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4135, Win8 = 4136, Win81 = 4137);
896    nt_user_call_syscall!(pub fn NtUserCallHwndParamLockSafe(hwnd: usize, param: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4135, Win8 = 4136, Win81 = 4137);
897    nt_user_call_syscall!(pub fn NtUserCallTwoParam(param1: usize, param2: usize, call: u32) -> usize => #[cfg(any(target_vendor = "win7", feature = "all_os_versions"))] Win7 = 4138, Win8 = 4138, Win81 = 4139);
898}