1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::{
ffi::OsString,
io,
os::windows::ffi::OsStringExt,
path::PathBuf,
ptr,
};
use winapi::{
um::{
shellapi::{
DragQueryFileW,
HDROP,
},
winuser::{
CF_HDROP,
GetClipboardData,
CloseClipboard,
OpenClipboard,
},
},
};
use crate::{
GlobalLockedData,
WinErrCheckable,
};
pub struct Clipboard(());
impl Clipboard {
pub fn new() -> io::Result<Clipboard> {
unsafe {
OpenClipboard(ptr::null_mut())
.if_null_get_last_error()
.map(|_| Clipboard(()))
}
}
pub fn get_file_list(&self) -> io::Result<Vec<PathBuf>> {
unsafe {
let mut clipboard_data = {
let clipboard_data = GetClipboardData(CF_HDROP).if_null_get_last_error()?;
GlobalLockedData::lock(clipboard_data)?
};
let num_files = DragQueryFileW(
clipboard_data.ptr() as HDROP,
std::u32::MAX,
ptr::null_mut(),
0,
);
let file_names: io::Result<Vec<PathBuf>> = (0..num_files)
.into_iter()
.map(|file_index| {
let required_size = 1 + DragQueryFileW(
clipboard_data.ptr() as HDROP,
file_index,
ptr::null_mut(),
0,
)
.if_null_to_error(|| io::ErrorKind::Other.into())?;
let file_str_buf = {
let mut buffer = Vec::with_capacity(required_size as usize);
DragQueryFileW(
clipboard_data.ptr() as HDROP,
file_index,
buffer.as_mut_ptr(),
required_size,
)
.if_null_to_error(|| io::ErrorKind::Other.into())?;
buffer.set_len(required_size as usize - 1);
buffer
};
let os_string = OsString::from_wide(&file_str_buf);
Ok(PathBuf::from(os_string))
})
.collect();
file_names
}
}
}
impl Drop for Clipboard {
fn drop(&mut self) {
unsafe {
CloseClipboard();
}
}
}