6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Rust for Windows(Rust/WinRT)] クリップボードのデータを取得

Last updated at Posted at 2021-04-03

Rust for Windowsでクリップボードを取得するコードです。

コード

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);
            }
        }
    }
}
6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?