Rust for Windowsでクリップボードを取得するコードです。
- Windows 10
- Rust 1.51.0
- Rust for Windows 0.10.0
コード
build.rs
fn main() {
windows::build!(
Windows::Win32::System::DataExchange::{CloseClipboard, GetClipboardData, OpenClipboard},
Windows::Win32::System::Memory::{GlobalLock, GlobalUnlock},
);
}
main.rs
use bindings::{
Windows::Win32::System::DataExchange::*,
Windows::Win32::System::Memory::*,
};
fn clipboard() -> String {
unsafe {
OpenClipboard(None);
let data = GetClipboardData(1).0;
let global = GlobalLock(data) as _;
let c_str = std::ffi::CStr::from_ptr(global);
let text = c_str.to_str().unwrap();
GlobalUnlock(data);
CloseClipboard();
text.to_string()
}
}
fn main() {
println!("{}", clipboard());
}
ただし上のコードだと日本語とかがクリップボードのデータとして入っているとパニックを起こすから基本的には下のコードの方がいい。
build.rs
fn main() {
windows::build!(
Windows::Win32::System::DataExchange::{CloseClipboard, GetClipboardData, OpenClipboard},
Windows::Win32::System::Memory::{GlobalLock, GlobalSize, GlobalUnlock},
);
}
main.rs
use bindings::{
Windows::Win32::DataExchange::{CloseClipboard, GetClipboardData, OpenClipboard},
Windows::Win32::SystemServices::{GlobalLock, GlobalSize, GlobalUnlock},
Windows::Win32::WindowsAndMessaging::HWND,
};
use bindings::{
Windows::Win32::System::DataExchange::*,
Windows::Win32::System::Memory::*,
};
fn clipboard() -> String {
unsafe {
OpenClipboard(None);
let data = GetClipboardData(13).0;
let global = GlobalLock(data) as _;
let slice = std::slice::from_raw_parts(global, GlobalSize(data) / 2 - 1);;
let text = String::from_utf16_lossy(slice);
GlobalUnlock(data);
CloseClipboard();
text
}
}
fn main() {
println!("{}", clipboard());
}
WinRTのClipboardクラスが使えればめちゃくちゃ楽なコードになるんだけどなんか色々制限があってできなそう。
と思っていたのだが
本来なら上の記事で終わる予定だったのですがRust for WindowsでClipboardクラスを使用する方法をStack Overflowにて教えていただいたのでそちらのコードを0.10.0用に書き直したものを書き残しておきます。
(予めfuturesクレートを追加しておく)
cargo.toml
[dependencies]
bindings = { path = "bindings" }
windows="0.10.0"
+ futures = "0.3"
build.rs
fn main() {
windows::build!(
Windows::ApplicationModel::DataTransfer::{Clipboard, DataPackageView},
Windows::Foundation::IAsyncOperation,
Windows::Win32::UI::WindowsAndMessaging::{
DispatchMessageW, PeekMessageW, PM_REMOVE, PostQuitMessage, WM_QUIT,
},
);
}
main.rs
use bindings::{
Windows::ApplicationModel::DataTransfer::*,
Windows::Win32::UI::WindowsAndMessaging::*,
};
use futures::executor::LocalPool;
use futures::task::LocalSpawnExt;
async fn clipboard() -> windows::Result<()> {
let content = Clipboard::GetContent()?.GetTextAsync()?;
let text = content.await?;
println!("{}", text);
Ok(())
}
fn main() {
let mut pool = LocalPool::new();
pool.spawner()
.spawn_local(async {
clipboard().await.unwrap();
})
.unwrap();
let mut msg = MSG::default();
unsafe {
while msg.message != WM_QUIT {
if PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).into() {
DispatchMessageW(&msg);
} else if pool.try_run_one() {
PostQuitMessage(0);
}
}
}
}