1use std::ffi::OsString;
4use std::io;
5use std::os::windows::ffi::OsStringExt;
6use std::path::PathBuf;
7
8use windows::Win32::Foundation::HGLOBAL;
9use windows::Win32::System::DataExchange::{
10 CloseClipboard,
11 GetClipboardData,
12 OpenClipboard,
13};
14use windows::Win32::System::Ole::CF_HDROP;
15use windows::Win32::UI::Shell::{
16 DragQueryFileW,
17 HDROP,
18};
19
20use crate::internal::{
21 GlobalLockedData,
22 ReturnValue,
23};
24
25pub fn get_file_list() -> io::Result<Vec<PathBuf>> {
29 let f = || {
30 let mut clipboard_data = {
31 let clipboard_data = unsafe { GetClipboardData(CF_HDROP.0.into()) }?;
32 GlobalLockedData::lock(HGLOBAL(clipboard_data.0))?
33 };
34
35 let num_files = unsafe { DragQueryFileW(HDROP(clipboard_data.ptr()), u32::MAX, None) };
36 let file_names: io::Result<Vec<PathBuf>> = (0..num_files)
37 .map(|file_index| {
38 let required_size =
39 unsafe { 1 + DragQueryFileW(HDROP(clipboard_data.ptr()), file_index, None) }
40 .if_null_to_error(|| io::ErrorKind::Other.into())?;
41 let file_str_buf = {
42 let mut buffer = vec![0; required_size as usize];
43 unsafe {
44 DragQueryFileW(
45 HDROP(clipboard_data.ptr()),
46 file_index,
47 Some(buffer.as_mut_slice()),
48 )
49 }
50 .if_null_to_error(|| io::ErrorKind::Other.into())?;
51 buffer.truncate(buffer.len() - 1);
53 buffer
54 };
55 let os_string = OsString::from_wide(&file_str_buf);
56 Ok(PathBuf::from(os_string))
57 })
58 .collect();
59 file_names
60 };
61 with_open_clipboard_do(f)
62}
63
64fn with_open_clipboard_do<F, R>(f: F) -> io::Result<R>
65where
66 F: FnOnce() -> io::Result<R>,
67{
68 unsafe {
69 OpenClipboard(None)?;
70 }
71 let result = f();
72 unsafe {
73 CloseClipboard()?;
74 }
75 result
76}
77
78#[cfg(test)]
79mod tests {
80 use std::time::Duration;
81
82 use super::*;
83
84 #[test]
85 fn open_clipboard() -> io::Result<()> {
86 with_open_clipboard_do(|| {
87 std::thread::sleep(Duration::from_millis(0));
88 Ok(())
89 })
90 }
91}