在 Rust 语言中使用 winapi SetClipboardData
Working with winapi SetClipboardData in Rust language
我正在尝试使用 Rust 中的 winapi 板条箱将数据设置到 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);}
}
}
}
备注:
指针转换的灵感来自:Working with c_void in an FFI
此调用的 WinAPI 文档:nf-winuser-setclipboarddata
winapi 生锈的文档:fn.SetClipboardData
问题 1:
按原样使用代码,它不会出错,但也不会工作,并且没有任何内容进入剪贴板。
问题 2:
当指针声明在循环内时,我的程序因错误而崩溃:process didn't exit successfully: exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)
。
这让我感到困惑,因为我希望我的值在堆栈中,而不是堆中。如果我理解正确,则 winapi 期望数据在堆栈中。
如有任何帮助,我们将不胜感激。
提供的代码存在几个问题。最突出的是,SetClipboardData expects a HANDLE
to memory allocated using GlocalAlloc. It's also a strict requirement to call 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.");
}
我正在尝试使用 Rust 中的 winapi 板条箱将数据设置到 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);}
}
}
}
备注:
指针转换的灵感来自:Working with c_void in an FFI
此调用的 WinAPI 文档:nf-winuser-setclipboarddata
winapi 生锈的文档:fn.SetClipboardData
问题 1:
按原样使用代码,它不会出错,但也不会工作,并且没有任何内容进入剪贴板。
问题 2:
当指针声明在循环内时,我的程序因错误而崩溃:process didn't exit successfully: exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)
。
这让我感到困惑,因为我希望我的值在堆栈中,而不是堆中。如果我理解正确,则 winapi 期望数据在堆栈中。
如有任何帮助,我们将不胜感激。
提供的代码存在几个问题。最突出的是,SetClipboardData expects a HANDLE
to memory allocated using GlocalAlloc. It's also a strict requirement to call 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.");
}