extern crate user32;
extern crate kernel32;
use winapi::minwindef::{HGLOBAL, UINT};
use winapi::winnt::HANDLE;
use winapi::basetsd::SIZE_T;
use kernel32::{GlobalFree, GlobalAlloc, GlobalLock, GlobalUnlock, GetLastError};
use user32::{RegisterClipboardFormatW, CountClipboardFormats, IsClipboardFormatAvailable, GetClipboardFormatNameW, EnumClipboardFormats, GetClipboardSequenceNumber, SetClipboardData, EmptyClipboard, OpenClipboard, GetClipboardData, CloseClipboard};
use std;
use std::os::windows::ffi::OsStrExt;
use super::WindowsError;
macro_rules! return_err {
() => { return Err(WindowsError(unsafe { GetLastError() })); }
}
#[inline(always)]
unsafe fn rust_strlen8(buff_p: *const u8) -> usize {
let mut idx: isize = 0;
while *buff_p.offset(idx) != 0 { idx += 1; }
idx as usize
}
#[inline(always)]
unsafe fn rust_strlen16(buff_p: *const u16) -> usize {
let mut idx: isize = 0;
while *buff_p.offset(idx) != 0 { idx += 1; }
idx as usize
}
#[inline]
pub fn get_clipboard_seq_num() -> Option<u32> {
let result: u32 = unsafe { GetClipboardSequenceNumber() };
if result == 0 { return None; }
Some(result)
}
#[inline]
pub fn open_clipboard() -> Result<(), WindowsError> {
unsafe {
if OpenClipboard(std::ptr::null_mut()) == 0 {
return Err(WindowsError(GetLastError()));
}
}
Ok(())
}
#[inline]
pub fn close_clipboard() -> Result<(), WindowsError> {
unsafe {
if CloseClipboard() == 0 {
return Err(WindowsError(GetLastError()));
}
}
Ok(())
}
#[inline]
pub fn empty_clipboard() -> Result<(), WindowsError> {
unsafe {
if EmptyClipboard() == 0 {
return Err(WindowsError(GetLastError()));
}
}
Ok(())
}
pub fn set_clipboard<T: ?Sized + AsRef<std::ffi::OsStr>>(text: &T) -> Result<(), WindowsError> {
let format: UINT = 13; let ghnd: UINT = 66;
let text = text.as_ref();
unsafe {
let utf16_buff: Vec<u16> = text.encode_wide().collect();
let len: usize = (utf16_buff.len()+1) * 2;
let handler: HGLOBAL = GlobalAlloc(ghnd, len as SIZE_T);
if handler.is_null() {
return Err(WindowsError(GetLastError()));
}
else {
let lock = GlobalLock(handler) as *mut u16;
let len: usize = (len - 1) / 2;
std::ptr::copy_nonoverlapping(utf16_buff.as_ptr(), lock, len);
let len: isize = len as isize;
*lock.offset(len) = 0;
GlobalUnlock(handler);
EmptyClipboard();
if SetClipboardData(format, handler).is_null() {
let result = Err(WindowsError(GetLastError()));
GlobalFree(handler);
return result;
}
}
}
Ok(())
}
pub fn set_clipboard_raw(data: &[u8], format: u32) -> Result<(), WindowsError> {
let ghnd: UINT = 66;
unsafe {
let len: usize = data.len() + 1;
let handler: HGLOBAL = GlobalAlloc(ghnd, len as SIZE_T);
if handler.is_null() {
return Err(WindowsError(GetLastError()));
}
else {
let lock = GlobalLock(handler) as *mut u8;
std::ptr::copy_nonoverlapping(data.as_ptr(), lock, len - 1);
let len: isize = len as isize;
*lock.offset(len) = 0;
GlobalUnlock(handler);
EmptyClipboard();
if SetClipboardData(format, handler).is_null() {
let result = Err(WindowsError(GetLastError()));
GlobalFree(handler);
return result;
}
}
}
Ok(())
}
#[inline(always)]
pub fn get_clipboard_string() -> Result<String, WindowsError> {
let result: Result<String, WindowsError>;
unsafe {
let text_handler: HANDLE = GetClipboardData(13 as u32);
if text_handler.is_null() {
result = Err(WindowsError(GetLastError()));
}
else {
let text_p = GlobalLock(text_handler) as *const u16;
let len: usize = rust_strlen16(text_p);
let text_s = std::slice::from_raw_parts(text_p, len);
result = Ok(String::from_utf16_lossy(text_s));
GlobalUnlock(text_handler);
}
}
result
}
pub fn get_clipboard(format: u32) -> Result<Vec<u8>, WindowsError> {
let result: Result<Vec<u8>, WindowsError>;
unsafe {
let text_handler: HANDLE = GetClipboardData(format as UINT);
if text_handler.is_null() {
result = Err(WindowsError(GetLastError()));
}
else {
let text_p = GlobalLock(text_handler) as *const u8;
let len: usize = rust_strlen8(text_p);
let text_vec: Vec<u8> = std::slice::from_raw_parts(text_p, len).to_vec();
println!("get_clipboard: text_vec={:?}", &text_vec);
result = Ok(text_vec);
GlobalUnlock(text_handler);
}
}
result
}
pub fn get_clipboard_formats() -> Result<Vec<u32>, WindowsError> {
let mut result: Vec<u32> = vec![];
unsafe {
let mut clip_format: u32 = EnumClipboardFormats(0);
while clip_format != 0 {
result.push(clip_format);
clip_format = EnumClipboardFormats(clip_format);
}
let error = GetLastError();
if error != 0 {
return Err(WindowsError(error));
}
}
Ok(result)
}
pub fn get_format_name(format: u32) -> Option<String> {
let format_buff: [u16; 30] = [0; 30];
unsafe {
let buff_p = format_buff.as_ptr() as *mut u16;
if GetClipboardFormatNameW(format, buff_p, 30) == 0 {
return None;
}
}
Some(String::from_utf16_lossy(&format_buff))
}
#[inline]
pub fn is_format_avail(format: u32) -> bool {
unsafe { IsClipboardFormatAvailable(format) != 0 }
}
pub fn count_formats() -> Result<i32, WindowsError> {
let result = unsafe { CountClipboardFormats() };
if result == 0 { return_err!() }
Ok(result)
}
pub fn register_format<T: ?Sized + AsRef<std::ffi::OsStr>>(text: &T) -> Result<u32, WindowsError> {
let mut utf16_buff: Vec<u16> = text.as_ref().encode_wide().collect();
utf16_buff.push(0);
let result = unsafe { RegisterClipboardFormatW(utf16_buff.as_ptr()) };
if result == 0 { return_err!() }
Ok(result)
}