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

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

- Windows 10
- Rust 1.51.0
- [Rust for Windows](https://github.com/microsoft/windows-rs) 0.10.0


## コード
```rust:build.rs
fn main() {
    windows::build!(
        Windows::Win32::System::DataExchange::{CloseClipboard, GetClipboardData, OpenClipboard},
        Windows::Win32::System::Memory::{GlobalLock, GlobalUnlock},
    );
}
```
```rust: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());
}
```

ただし上のコードだと日本語とかがクリップボードのデータとして入っているとパニックを起こすから基本的には下のコードの方がいい。

```rust:build.rs
fn main() {
    windows::build!(
        Windows::Win32::System::DataExchange::{CloseClipboard, GetClipboardData, OpenClipboard},
        Windows::Win32::System::Memory::{GlobalLock, GlobalSize, GlobalUnlock},
    );
}
```
```rust: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クラス](https://docs.microsoft.com/ja-jp/uwp/api/windows.applicationmodel.datatransfer.clipboard)が使えればめちゃくちゃ楽なコードになるんだけどなんか色々制限があってできなそう。
## と思っていたのだが
本来なら上の記事で終わる予定だったのですがRust for WindowsでClipboardクラスを使用する方法を[Stack Overflow](https://ja.stackoverflow.com/questions/75019/rust-winrt%E3%81%A7%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84/75051#75051)にて教えていただいたのでそちらのコードを0.10.0用に書き直したものを書き残しておきます。

（予めfuturesクレートを追加しておく）

```diff_toml:cargo.toml
[dependencies]
bindings = { path = "bindings" }
windows="0.10.0"
+ futures = "0.3"
```
```rust: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,
        },
    );
}
```
```rust: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);
            }
        }
    }
}
```