我试图在按键时显示 MessageDialog。到目前为止,它似乎没有做任何事情。代码可以编译,但无法运行。代码验证按键是否有效,但对话框根本不会显示。我尝试使用返回的 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
与其主线程相关联。通常,对话框会查询此窗口并将其自身显示为模式。但是,在 Win32 应用程序中,系统无法假设您要使用哪个窗口。在这些情况下,您需要对 IInitializeWithWindow
进行 QI接口(interface)并使用您的窗口句柄调用初始化函数。
由于 IInitializeWithWindow 接口(interface)是纯 COM 接口(interface)而不是 WinRT 接口(interface),因此 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 窗口获取窗口句柄,您需要
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);
请注意,我不是在等待
IAsyncOperation
的结果。由 show_async 返回。原因是现在投影只支持同步等待,这会占用您的消息泵并导致窗口挂起。这意味着打印语句将在对话框返回之前运行。一旦更广泛的异步支持在投影中启动并运行,这应该会有所改善。您现在可以使用您的
initialize_with_window
对话框和选择器上的方法(例如 FileSavePicker、GraphicsCapturePicker)。
关于rust - 如何使用 winrt-rs 创建 MessageDialog?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62107050/