winapi - 使用Rust语言使用winapi SetClipboardData

标签 winapi rust clipboarddata

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

SetClipboardData调用的输入需要文件类型,C通用指针或Rust中的*mut libc::c_void
(以下链接的文档)

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

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);}
        }
    }
}

笔记:
  • 指针转换是通过以下方式实现的:Working with c_void in an FFI
  • 此调用的WinAPI文档:nf-winuser-setclipboarddata
  • rust 中的
  • winapi文档:fn.SetClipboardData

  • 问题1:

    照原样编写代码,它不会出错,但是也无法正常工作,剪贴板中什么也没有。

    问题2:

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

    任何帮助,将不胜感激。

    最佳答案

    所提供的代码存在多个问题。最突出的是,SetClipboardData希望将HANDLE分配给使用GlocalAlloc分配的内存。严格要求在执行操作之前调用OpenClipboard

    一个更微妙的问题是与CF_TEXT一起使用的字符编码要求。此剪贴板格式需要使用ANSI(代码页)编码的文本。由于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!");
    }
    

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

    包括错误处理在内的安全实现可能如下所示。它使用scopeguard条板箱进行资源清理:
    [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.");
    }
    

    关于winapi - 使用Rust语言使用winapi SetClipboardData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61981453/

    相关文章:

    c++ - Win32 中的多个 WndProc 函数

    c++ - 如何从powerbuilder11.5调用win32 dll?

    c++ - WinApi中的GetClientRect和GetWindowRect有什么区别?

    regex - 使用 Rust 的正则表达式箱时如何转义转义的正则表达式字符?

    C++ (VC) 文本输出用 0d 0d 0a 而不是 0d 0a 换行 - 如何修复?

    python 3.6 窗口 : retrieving the clipboard CF_HTML format

    c++ - Windows api获取客户端dc位图大小

    module - 如何从特定模块创建所有装饰函数的向量?

    recursion - 如何使用 Read::take 递归地读取具有通用 Read 特征的树结构?

    javascript - 无法使用 JavaScript 复制剪贴板数据