1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::mem;
6 use std::ptr::null_mut;
7
8 use anyhow::Result;
9 use win_util::syscall_bail;
10 use winapi::shared::minwindef::DWORD;
11 use winapi::shared::minwindef::LPARAM;
12 use winapi::shared::minwindef::UINT;
13 use winapi::shared::minwindef::WPARAM;
14 use winapi::um::winuser::*;
15
16 /// Using `PostThreadMessageW()` requires that the thread-specific message queue must have been
17 /// created on the targeted thread. We can call `PeekMessageW()` from the targeted thread first to
18 /// ensure it:
19 /// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postthreadmessagea#remarks
20 /// It does no harm calling this function multiple times, since it won't remove any message from the
21 /// queue.
force_create_message_queue()22 pub(crate) fn force_create_message_queue() {
23 let mut message = mem::MaybeUninit::uninit();
24 // Safe because we know the lifetime of `message`, and `PeekMessageW()` has no failure mode.
25 unsafe {
26 PeekMessageW(
27 message.as_mut_ptr(),
28 null_mut(),
29 WM_USER,
30 WM_USER,
31 PM_NOREMOVE,
32 );
33 }
34 }
35
36 /// Calls `PostThreadMessageW()` internally.
37 /// # Safety
38 /// The caller must make sure the thread is still running and has created the message queue.
post_message( thread_id: DWORD, msg: UINT, w_param: WPARAM, l_param: LPARAM, ) -> Result<()>39 pub(crate) unsafe fn post_message(
40 thread_id: DWORD,
41 msg: UINT,
42 w_param: WPARAM,
43 l_param: LPARAM,
44 ) -> Result<()> {
45 if PostThreadMessageW(thread_id, msg, w_param, l_param) == 0 {
46 syscall_bail!("Failed to call PostThreadMessageW()");
47 }
48 Ok(())
49 }
50
51 /// Calls `PostThreadMessageW()` internally. This is a common pattern, where we send a pointer to
52 /// the given object as the lParam. The receiver is responsible for destructing the object.
53 /// # Safety
54 /// The caller must make sure the thread is still running and has created the message queue.
post_message_carrying_object<T>( thread_id: DWORD, msg: UINT, object: T, ) -> Result<()>55 pub(crate) unsafe fn post_message_carrying_object<T>(
56 thread_id: DWORD,
57 msg: UINT,
58 object: T,
59 ) -> Result<()> {
60 let mut boxed_object = Box::new(object);
61 post_message(
62 thread_id,
63 msg,
64 /* w_param */ 0,
65 &mut *boxed_object as *mut T as LPARAM,
66 )
67 // If successful, the receiver will be responsible for destructing the object.
68 .map(|_| std::mem::forget(boxed_object))
69 }
70