在Rust语言中使用winapi SetClipboardData。

问题描述 投票:0回答:1

我试图使用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);}
        }
    }
}

注释:

问题1:

用现在的代码,它不会出错,但也不会工作,而且什么都不会进入剪贴板。

问题2:

当指针声明在循环中时,我的程序就会出错,这让我很困惑。process didn't exit successfully: exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)这让我很困惑,因为我希望我的值是在堆栈中,而不是在堆中。而且如果我不正确的操作,winapi期望数据是在堆栈中。

任何帮助将被感激。

winapi rust clipboarddata
1个回答
2
投票

所提供的代码有几个问题。最突出的一个问题是 SetClipboardData 期待 HANDLE 分配到使用 GlocalAlloc. 这也是一个严格的要求,叫 OpenClipboard 在对其进行操作之前。

一个更微妙的问题是对使用 CF_TEXT. 这种剪贴板格式希望使用ANSI(codepage)编码的文本。因为Rust内部使用Unicode,所以最好使用 CF_UNICODETEXT 代替,并转换为UTF-16。

以下是一个粗略的实现。

[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "winbase"] }
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!");
}

为了简洁,错误处理被省略了。这个例子是为了展示如何使用剪贴板的 赢驷. 这不是生产就绪的代码质量。


一个安全的实现,包括错误处理,可能看起来像下面。它使用了 伞兵 箱进行资源清理。

[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "winbase"] }
scopeguard = "1.1.0"
use scopeguard::defer;
use std::io::Error;
use std::ptr;
use winapi::shared::minwindef::FALSE;
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) -> Result<(), Error> {
    // 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>()) };
    if hglob == ptr::null_mut() {
        return Err(Error::last_os_error());
    }
    // Ensure cleanup on scope exit
    defer!(unsafe { GlobalFree(hglob) };);

    // Retrieve writeable pointer to memory
    let dst = unsafe { GlobalLock(hglob) };
    if dst == ptr::null_mut() {
        return Err(Error::last_os_error());
    }
    // 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
    let success = unsafe { OpenClipboard(ptr::null_mut()) } != FALSE;
    if !success {
        return Err(Error::last_os_error());
    }
    // Ensure cleanup on scope exit
    defer!(unsafe { CloseClipboard() };);
    // And apply data
    let success = unsafe { SetClipboardData(CF_UNICODETEXT, hglob) } != ptr::null_mut();
    if !success {
        return Err(Error::last_os_error());
    }

    Ok(())
}

fn main() {
    copy_to_clipboard("Hello, world!").expect("Failed to copy text to clipboard.");
}
© www.soinside.com 2019 - 2024. All rights reserved.