• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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