virtual_file_transfer/lib.rs
1//! Virtual file transfer through Windows drag-and-drop and
2//! the clipboard.
3//!
4//! This crate allows applications to offer data as files
5//! without first writing the contents to temporary files.
6//!
7//! File contents are provided on demand using [`FileSource`]
8//! and [`SourceReader`]. On Windows, these are exposed to
9//! receiving applications through OLE `IDataObject` and
10//! `IStream` interfaces.
11//!
12//! # Quick start
13//!
14//! ```no_run
15//! use std::io::Cursor;
16//! use virtual_file_transfer::{
17//! begin_drag, FactorySource, SourceReader, VirtualFile,
18//! };
19//!
20//! fn start_drag() -> virtual_file_transfer::Result<()> {
21//! let source = FactorySource::new(|| {
22//! Ok(SourceReader::seekable(
23//! Cursor::new(b"hello\n".to_vec())
24//! ))
25//! });
26//!
27//! let file = VirtualFile::new(
28//! "hello.txt",
29//! Box::new(source),
30//! )?;
31//!
32//! let _handle = begin_drag(vec![file])?;
33//! Ok(())
34//! }
35//! ```
36//!
37//! Call [`begin_drag`] from an appropriate Windows UI event
38//! handler. The application must provide a message loop.
39//!
40//! # Data sources
41//!
42//! A [`FileSource`] produces a fresh [`SourceReader`] for
43//! each request. Sources may read from memory, archives,
44//! generated content, or other application-defined storage.
45//!
46//! Use [`SourceReader::streaming`] for sequential data and
47//! [`SourceReader::seekable`] when seeking is available.
48//!
49//! The optional `spool` feature provides
50//! [`SourceReader::spooled`] for explicitly materializing
51//! non-seekable data into temporary storage.
52//!
53//! # Transfer operations
54//!
55//! - [`begin_drag`] starts an OLE drag-and-drop operation.
56//! - [`copy_to_clipboard`] exposes virtual files through
57//! the system clipboard.
58//! - [`TransferHandle`] provides cancellation and status
59//! information.
60//!
61//! A successful drop does not necessarily mean that an
62//! asynchronous receiver has finished reading the data.
63//! See [`TransferStatus`] for completion semantics.
64//!
65//! # Platform support
66//!
67//! Currently Windows only.
68mod cancellation;
69mod error;
70mod factory_source;
71mod file_source;
72mod source_reader;
73mod transfer;
74mod validation;
75mod virtual_file;
76
77/// Windows-specific APIs, including the lower-level OLE data-object interface.
78#[cfg(windows)]
79pub mod windows;
80
81pub use cancellation::CancellationToken;
82pub use error::{Error, FileNameErrorReason, InputError, PlatformError, PlatformErrorKind, Result};
83pub use factory_source::FactorySource;
84pub use file_source::FileSource;
85pub use source_reader::SourceReader;
86pub use transfer::{
87 NativeStatusCode, TransferEffect, TransferHandle, TransferRequest, TransferStatus,
88};
89pub use virtual_file::VirtualFile;
90
91/// Starts a Windows OLE drag-and-drop operation for the supplied virtual files.
92///
93/// This calls `DoDragDrop` on the current thread and returns when the drag
94/// operation ends. The receiver may continue fetching file contents
95/// asynchronously after this function returns.
96///
97/// Call this from a suitable Windows UI thread with a message loop. The
98/// function initializes OLE for the duration of the drag operation.
99///
100/// The request must contain at least one file and must not contain duplicate
101/// or conflicting paths. A `Vec<VirtualFile>` can be passed directly.
102///
103/// # Errors
104///
105/// Returns [`Error::InvalidInput`] for invalid transfers or
106/// [`Error::Platform`] if OLE initialization or drag-and-drop fails.
107#[cfg(windows)]
108pub fn begin_drag(request: impl Into<TransferRequest>) -> Result<TransferHandle> {
109 windows::begin_drag(request.into())
110}
111
112/// Keeps a virtual-file clipboard transfer available.
113///
114/// The session owns the resources needed to serve file
115/// contents when another application pastes them.
116///
117/// Keep this value alive while clipboard data may still
118/// be requested.
119///
120/// Dropping the session clears its clipboard contents
121/// if they are still the current clipboard contents.
122/// It does not clear data installed by another application
123/// or a newer clipboard session.
124#[cfg(windows)]
125#[must_use = "Keep this session alive while clipboard data is needed"]
126pub struct ClipboardSession {
127 inner: windows::ClipboardSession,
128}
129
130#[cfg(windows)]
131impl ClipboardSession {
132 /// Requests cancellation of reads served by this clipboard session.
133 ///
134 /// Cancellation is cooperative: an already-running blocking read is not
135 /// forcibly interrupted. Subsequent paste attempts using the same session
136 /// can also observe cancellation.
137 pub fn cancel(&self) {
138 self.inner.cancel();
139 }
140}
141
142/// Publishes virtual files through the Windows clipboard.
143///
144/// The returned [`ClipboardSession`] must remain alive while the data is
145/// available for pasting. File contents are provided lazily when the receiver
146/// requests them. A `Vec<VirtualFile>` can be passed directly.
147///
148/// # Errors
149///
150/// Returns [`Error::InvalidInput`] for an invalid transfer or
151/// [`Error::Platform`] if OLE initialization or clipboard registration fails.
152#[cfg(windows)]
153pub fn copy_to_clipboard(request: impl Into<TransferRequest>) -> Result<ClipboardSession> {
154 Ok(ClipboardSession {
155 inner: windows::copy_to_clipboard(request.into())?,
156 })
157}