在 Rust 语言中使用 winapi SetClipboardData

Auy*_*yer 1 winapi rust clipboarddata

我正在尝试使用 Rust 中的 winapi crate 将数据设置到 Windows cipboard 中(我是 Rust 和 win32 api 的新手)。

SetClipboardData 调用的输入需要一个文件类型和一个 C 通用指针,或者*mut libc::c_void在 Rust 中。(下面链接的文档)

在最终版本中,我计划复制图像文件,但我用文本字符串测试失败,这里是它的代码:

extern crate winapi;
extern crate libc;

fn main() {
    let mut test = "test\r\n";
    let test_ptr: *mut libc::c_void = &mut test as *mut _ as *mut libc::c_void;
    loop {
        if (condition)  
        {
            // let mut test = "test\r\n";  // these commented lets are refered to issue 2
            // let test_ptr: *mut libc::c_void = &mut test as *mut _ as *mut libc::c_void; 
            unsafe {winapi::um::winuser::SetClipboardData(winapi::um::winuser::CF_TEXT, test_ptr);}
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

问题 1:

使用原样的代码,它不会出错,但也不会工作,剪贴板中没有任何内容。

问题 2:

当指针声明是在循环中,我的程序恐慌,出现错误:process didn't exit successfully: exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)。这让我感到困惑,因为我希望我的值在堆栈中,而不是堆中。如果我不理解正确性,则 winapi 期望数据在堆栈中。

任何帮助,将不胜感激。

IIn*_*ble 5

所提供的代码有几个问题。最突出的是,SetClipboardData需要HANDLE使用GlocalAlloc分配的内存。在对其执行操作之前调用OpenClipboard也是一项严格要求。

一个更微妙的问题是与CF_TEXT一起使用的字符编码要求。此剪贴板格式需要使用 ANSI(代码页)编码的文本。由于 Rust 在内部始终使用 Unicode,因此最好CF_UNICODETEXT改用并转换为 UTF-16。

下面是一个粗略的实现:

[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "winbase"] }
Run Code Online (Sandbox Code Playgroud)
[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "winbase"] }
Run Code Online (Sandbox Code Playgroud)

为简洁起见,已省略错误处理。此示例旨在展示如何使用winapi crate访问剪贴板。这不是生产就绪的代码质量。


包括错误处理在内的安全实现可能如下所示。它使用scopeguard crate 进行资源清理:

[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "winbase"] }
scopeguard = "1.1.0"
Run Code Online (Sandbox Code Playgroud)
use std::ptr;
use winapi::um::winbase::{GlobalAlloc, GlobalFree, GlobalLock, GlobalUnlock, GMEM_MOVEABLE};
use winapi::um::winuser::{CloseClipboard, OpenClipboard, SetClipboardData, CF_UNICODETEXT};

fn copy_to_clipboard(text: &str) {
    // Needs to be UTF-16 encoded
    let mut text_utf16: Vec<u16> = text.encode_utf16().collect();
    // And zero-terminated before passing it into `SetClipboardData`
    text_utf16.push(0);
    // Allocate memory
    let hglob =
        unsafe { GlobalAlloc(GMEM_MOVEABLE, text_utf16.len() * std::mem::size_of::<u16>()) };
    // Retrieve writeable pointer to memory
    let dst = unsafe { GlobalLock(hglob) };
    // Copy data
    unsafe { ptr::copy_nonoverlapping(text_utf16.as_ptr(), dst as _, text_utf16.len()) };
    // Release writeable pointer
    unsafe { GlobalUnlock(hglob) };

    // Everything is set up now, let's open the clipboard
    unsafe { OpenClipboard(ptr::null_mut()) };
    // And apply data
    unsafe { SetClipboardData(CF_UNICODETEXT, hglob) };

    // Clean up
    unsafe { GlobalFree(hglob) };
    unsafe { CloseClipboard() };
}

fn main() {
    copy_to_clipboard("Hello, world!");
}
Run Code Online (Sandbox Code Playgroud)