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.