如何使用 winrt-rs 创建 MessageDialog?
How can I create a MessageDialog using winrt-rs?
我试图在按键时显示一个消息对话框。到目前为止,它似乎没有做任何事情。该代码确实可以编译,但无法运行。代码验证按键是否有效,但对话框根本不会显示。我尝试使用返回的 IAsyncOperation 并使用 'get()' 但这似乎完全冻结了应用程序。我错过了什么?
//#![windows_subsystem = "windows"]
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use winrt::*;
import!(
dependencies
os
modules
"windows.data.xml.dom"
"windows.foundation"
"windows.ui"
"windows.ui.popups"
);
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::Resized (_size),
..
} => (),
Event::WindowEvent {
event: WindowEvent::KeyboardInput {input,..},
..
} if input.state == winit::event::ElementState::Pressed => {
use windows::ui::popups::MessageDialog;
let mymsg = MessageDialog::create("Test").unwrap().show_async();
println!("KeyState-{}",input.scancode);
},
_ => (),
}
});
}
这突出了在 Win32 应用程序中使用某些 WinRT API 的差异之一。在 UWP 应用程序中,您的应用程序有一个与其主线程关联的 CoreWindow
。通常,对话框会查询此 window 并将其自身显示为模态。但是,在 Win32 应用程序中,系统无法假设 window 您想要使用什么。在这些情况下,您需要对 IInitializeWithWindow
接口进行 QI,并使用 window 句柄调用初始化函数。
由于 IInitializeWithWindow 接口是纯 COM 接口而不是 WinRT 接口,因此 winrt-rs 没有它的投影。相反,您需要自己定义它(确保您获得正确的 GUID!):
#[repr(C)]
pub struct abi_IInitializeWithWindow {
__base: [usize; 3],
initialize: extern "system" fn(
winrt::NonNullRawComPtr<InitializeWithWindowInterop>,
*mut c_void,
) -> winrt::ErrorCode,
}
unsafe impl winrt::ComInterface for InitializeWithWindowInterop {
type VTable = abi_IInitializeWithWindow;
fn iid() -> winrt::Guid {
winrt::Guid::from_values(1047057597, 28981, 19728, [128, 24, 159, 182, 217, 243, 63, 161])
}
}
#[repr(transparent)]
#[derive(Default, Clone)]
pub struct InitializeWithWindowInterop {
ptr: winrt::ComPtr<InitializeWithWindowInterop>,
}
impl InitializeWithWindowInterop {
pub fn initialize(
&self,
window: *mut c_void,
) -> winrt::Result<()> {
match self.ptr.abi() {
None => panic!("The `this` pointer was null when calling method"),
Some(this) => unsafe {
(this.vtable().initialize)(
this,
window,
)
.ok()?;
Ok(())
},
}
}
}
要从您的 winit Window 获取 window 句柄,您需要 raw-window-handle
箱子。从那里你可以为任何实现 HasRawWindowHandle
:
的东西创建一个辅助特征
trait InitializeWithWindow {
fn initialize_with_window<O: RuntimeType + ComInterface>(&self, object: &O) -> winrt::Result<()>;
}
impl<T> InitializeWithWindow for T
where
T: HasRawWindowHandle,
{
fn initialize_with_window<O: RuntimeType + ComInterface>(
&self,
object: &O,
) -> winrt::Result<()> {
// Get the window handle
let window_handle = self.raw_window_handle();
let window_handle = match window_handle {
raw_window_handle::RawWindowHandle::Windows(window_handle) => window_handle.hwnd,
_ => panic!("Unsupported platform!"),
};
let init: InitializeWithWindowInterop = object.try_into()?;
init.initialize(window_handle)?;
Ok(())
}
}
现在在您的事件循环中,您可以使用以下方式调用它:
let dialog = MessageDialog::create("Test").unwrap();
window.initialize_with_window(&dialog).unwrap();
dialog.show_async().unwrap();
println!("KeyState-{}",input.scancode);
请注意,我不是在等待 show_async 返回的 IAsyncOperation
的结果。原因是因为投影现在只支持同步等待,这会占用您的消息泵并导致 window 挂起。这意味着打印语句将 运行 在对话框 returns 之前。一旦更广泛的异步支持启动并且 运行ning 在投影中,这应该会有所改善。
您现在可以在对话框和选取器(例如 FileSavePicker、GraphicsCapturePicker)上使用 initialize_with_window
方法。
我试图在按键时显示一个消息对话框。到目前为止,它似乎没有做任何事情。该代码确实可以编译,但无法运行。代码验证按键是否有效,但对话框根本不会显示。我尝试使用返回的 IAsyncOperation 并使用 'get()' 但这似乎完全冻结了应用程序。我错过了什么?
//#![windows_subsystem = "windows"]
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use winrt::*;
import!(
dependencies
os
modules
"windows.data.xml.dom"
"windows.foundation"
"windows.ui"
"windows.ui.popups"
);
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::Resized (_size),
..
} => (),
Event::WindowEvent {
event: WindowEvent::KeyboardInput {input,..},
..
} if input.state == winit::event::ElementState::Pressed => {
use windows::ui::popups::MessageDialog;
let mymsg = MessageDialog::create("Test").unwrap().show_async();
println!("KeyState-{}",input.scancode);
},
_ => (),
}
});
}
这突出了在 Win32 应用程序中使用某些 WinRT API 的差异之一。在 UWP 应用程序中,您的应用程序有一个与其主线程关联的 CoreWindow
。通常,对话框会查询此 window 并将其自身显示为模态。但是,在 Win32 应用程序中,系统无法假设 window 您想要使用什么。在这些情况下,您需要对 IInitializeWithWindow
接口进行 QI,并使用 window 句柄调用初始化函数。
由于 IInitializeWithWindow 接口是纯 COM 接口而不是 WinRT 接口,因此 winrt-rs 没有它的投影。相反,您需要自己定义它(确保您获得正确的 GUID!):
#[repr(C)]
pub struct abi_IInitializeWithWindow {
__base: [usize; 3],
initialize: extern "system" fn(
winrt::NonNullRawComPtr<InitializeWithWindowInterop>,
*mut c_void,
) -> winrt::ErrorCode,
}
unsafe impl winrt::ComInterface for InitializeWithWindowInterop {
type VTable = abi_IInitializeWithWindow;
fn iid() -> winrt::Guid {
winrt::Guid::from_values(1047057597, 28981, 19728, [128, 24, 159, 182, 217, 243, 63, 161])
}
}
#[repr(transparent)]
#[derive(Default, Clone)]
pub struct InitializeWithWindowInterop {
ptr: winrt::ComPtr<InitializeWithWindowInterop>,
}
impl InitializeWithWindowInterop {
pub fn initialize(
&self,
window: *mut c_void,
) -> winrt::Result<()> {
match self.ptr.abi() {
None => panic!("The `this` pointer was null when calling method"),
Some(this) => unsafe {
(this.vtable().initialize)(
this,
window,
)
.ok()?;
Ok(())
},
}
}
}
要从您的 winit Window 获取 window 句柄,您需要 raw-window-handle
箱子。从那里你可以为任何实现 HasRawWindowHandle
:
trait InitializeWithWindow {
fn initialize_with_window<O: RuntimeType + ComInterface>(&self, object: &O) -> winrt::Result<()>;
}
impl<T> InitializeWithWindow for T
where
T: HasRawWindowHandle,
{
fn initialize_with_window<O: RuntimeType + ComInterface>(
&self,
object: &O,
) -> winrt::Result<()> {
// Get the window handle
let window_handle = self.raw_window_handle();
let window_handle = match window_handle {
raw_window_handle::RawWindowHandle::Windows(window_handle) => window_handle.hwnd,
_ => panic!("Unsupported platform!"),
};
let init: InitializeWithWindowInterop = object.try_into()?;
init.initialize(window_handle)?;
Ok(())
}
}
现在在您的事件循环中,您可以使用以下方式调用它:
let dialog = MessageDialog::create("Test").unwrap();
window.initialize_with_window(&dialog).unwrap();
dialog.show_async().unwrap();
println!("KeyState-{}",input.scancode);
请注意,我不是在等待 show_async 返回的 IAsyncOperation
的结果。原因是因为投影现在只支持同步等待,这会占用您的消息泵并导致 window 挂起。这意味着打印语句将 运行 在对话框 returns 之前。一旦更广泛的异步支持启动并且 运行ning 在投影中,这应该会有所改善。
您现在可以在对话框和选取器(例如 FileSavePicker、GraphicsCapturePicker)上使用 initialize_with_window
方法。