
In this article, we will learn how to interact with the Windows clipboard using the Windows API (WinAPI) in Rust. The clipboard is a temporary storage area for data that the user wants to copy from one place to another. It allows users to perform copy-paste operations across different applications. We will cover the following topics:
First, you need to have Rust installed on your system. You can follow the official installation guide here.
Next, create a new Rust project:
$ cargo new winapi_clipboard
$ cd winapi_clipboard
To access WinAPI functions in Rust, we will use the winapi crate. Add the following dependencies to your Cargo.toml file:
[dependencies]
winapi = { version = "0.3", features = ["winuser"] }
The winuser feature enables the necessary clipboard functions.
Let’s create a new module named clipboard in src/lib.rs:
mod clipboard {
use winapi::um::winuser::{
CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, SetClipboardData,
CF_TEXT,
};
use winapi::ctypes::c_void;
use winapi::shared::minwindef::{HGLOBAL, UINT};
use winapi::shared::ntdef::NULL;
use std::ptr::{null_mut, null};
use std::ffi::CString;
// WinAPI clipboard functions
}
Now, let’s implement the clipboard functions:
To interact with the clipboard, we need to open it first. We can do this using the OpenClipboard function:
fn open_clipboard() -> Result<(), &'static str> {
let result = unsafe { OpenClipboard(null_mut()) };
if result == 0 {
Err("Failed to open the clipboard")
} else {
Ok(())
}
}
After we are done interacting with the clipboard, we need to close it using the CloseClipboard function:
fn close_clipboard() {
unsafe {
CloseClipboard();
}
}
To read text from the clipboard, we’ll use the GetClipboardData function:
fn get_clipboard_text() -> Result<String, &'static str> {
let clipboard_data = unsafe { GetClipboardData(CF_TEXT) as *mut u8 };
if clipboard_data.is_null() {
return Err("Failed to get clipboard data");
}
let mut text = String::new();
let mut index = 0;
loop {
let ch = unsafe { *clipboard_data.offset(index) } as char;
if ch == '\0' {
break;
}
text.push(ch);
index += 1;
}
Ok(text)
}
To write text to the clipboard, we’ll use the EmptyClipboard and SetClipboardData functions:
fn set_clipboard_text(text: &str) -> Result<(), &'static str> {
let text_len = text.len() + 1;
let text_cstring = CString::new(text).unwrap();
let h_mem = unsafe { GlobalAlloc(GMEM_MOVEABLE, text_len) } as *mut c_void;
if h_mem.is_null() {
return Err("Failed to allocate memory for clipboard data");
}
let h_mem_text = unsafe { GlobalLock(h_mem) as *mut u8 };
for (i, ch) in text_cstring.as_bytes_with_nul().iter().enumerate() {
unsafe {
*h_mem_text.offset(i as isize) = *ch;
}
}
unsafe {
GlobalUnlock(h_mem);
EmptyClipboard();
if SetClipboardData(CF_TEXT, h_mem as HGLOBAL) == NULL {
GlobalFree(h_mem);
return Err("Failed to set clipboard data");
}
}
Ok(())
}
Now, let’s create an example application that reads and writes text to the clipboard:
fn main() {
let example_text = "Hello, clipboard!";
println!("Writing to clipboard: {}", example_text);
clipboard::open_clipboard().unwrap();
clipboard::set_clipboard_text(example_text).unwrap();
clipboard::close_clipboard();
println!("Reading from clipboard:");
clipboard::open_clipboard().unwrap();
let clipboard_text = clipboard::get_clipboard_text().unwrap();
clipboard::close_clipboard();
println!("Clipboard content: {}", clipboard_text);
}
Compile and run the example:
$ cargo build --release
$ target/release/winapi_clipboard
You should see the following output:
Writing to clipboard: Hello, clipboard!
Reading from clipboard:
Clipboard content: Hello, clipboard!
In this article, we’ve learned how to interact with the Windows clipboard using WinAPI in Rust. We covered setting up the Rust environment, accessing WinAPI functions, and implementing clipboard functions for reading and writing text data. This example can serve as a starting point for more advanced clipboard manipulation in your Rust applications.