diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index bc20ecfc5..27c5f7382 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -2,7 +2,7 @@ name = "clipboard" version = "0.1.0" edition = "2021" -build= "build.rs" +build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/libs/clipboard/docs/assets/scene3.png b/libs/clipboard/docs/assets/scene3.png index a65a7ac06..748369878 100644 Binary files a/libs/clipboard/docs/assets/scene3.png and b/libs/clipboard/docs/assets/scene3.png differ diff --git a/libs/clipboard/docs/assets/win_A_B.png b/libs/clipboard/docs/assets/win_A_B.png index b65e571e7..87fe702dd 100644 Binary files a/libs/clipboard/docs/assets/win_A_B.png and b/libs/clipboard/docs/assets/win_A_B.png differ diff --git a/libs/clipboard/docs/assets/win_B_A.png b/libs/clipboard/docs/assets/win_B_A.png index 4484b21ac..e4c9f3246 100644 Binary files a/libs/clipboard/docs/assets/win_B_A.png and b/libs/clipboard/docs/assets/win_B_A.png differ diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs deleted file mode 100644 index c787d8ef6..000000000 --- a/libs/clipboard/src/cliprdr.rs +++ /dev/null @@ -1,573 +0,0 @@ -#![allow(dead_code)] -#![allow(non_camel_case_types)] -#![allow(unused_variables)] -#![allow(non_snake_case)] -#![allow(deref_nullptr)] - -use std::{boxed::Box, result::Result}; -use thiserror::Error; - -pub type size_t = ::std::os::raw::c_ulonglong; -pub type __vcrt_bool = bool; -pub type wchar_t = ::std::os::raw::c_ushort; - -pub type POINTER_64_INT = ::std::os::raw::c_ulonglong; -pub type INT8 = ::std::os::raw::c_schar; -pub type PINT8 = *mut ::std::os::raw::c_schar; -pub type INT16 = ::std::os::raw::c_short; -pub type PINT16 = *mut ::std::os::raw::c_short; -pub type INT32 = ::std::os::raw::c_int; -pub type PINT32 = *mut ::std::os::raw::c_int; -pub type INT64 = ::std::os::raw::c_longlong; -pub type PINT64 = *mut ::std::os::raw::c_longlong; -pub type UINT8 = ::std::os::raw::c_uchar; -pub type PUINT8 = *mut ::std::os::raw::c_uchar; -pub type UINT16 = ::std::os::raw::c_ushort; -pub type PUINT16 = *mut ::std::os::raw::c_ushort; -pub type UINT32 = ::std::os::raw::c_uint; -pub type PUINT32 = *mut ::std::os::raw::c_uint; -pub type UINT64 = ::std::os::raw::c_ulonglong; -pub type PUINT64 = *mut ::std::os::raw::c_ulonglong; -pub type LONG32 = ::std::os::raw::c_int; -pub type PLONG32 = *mut ::std::os::raw::c_int; -pub type ULONG32 = ::std::os::raw::c_uint; -pub type PULONG32 = *mut ::std::os::raw::c_uint; -pub type DWORD32 = ::std::os::raw::c_uint; -pub type PDWORD32 = *mut ::std::os::raw::c_uint; -pub type INT_PTR = ::std::os::raw::c_longlong; -pub type PINT_PTR = *mut ::std::os::raw::c_longlong; -pub type UINT_PTR = ::std::os::raw::c_ulonglong; -pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong; -pub type LONG_PTR = ::std::os::raw::c_longlong; -pub type PLONG_PTR = *mut ::std::os::raw::c_longlong; -pub type ULONG_PTR = ::std::os::raw::c_ulonglong; -pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong; -pub type SHANDLE_PTR = ::std::os::raw::c_longlong; -pub type HANDLE_PTR = ::std::os::raw::c_ulonglong; -pub type UHALF_PTR = ::std::os::raw::c_uint; -pub type PUHALF_PTR = *mut ::std::os::raw::c_uint; -pub type HALF_PTR = ::std::os::raw::c_int; -pub type PHALF_PTR = *mut ::std::os::raw::c_int; -pub type SIZE_T = ULONG_PTR; -pub type PSIZE_T = *mut ULONG_PTR; -pub type SSIZE_T = LONG_PTR; -pub type PSSIZE_T = *mut LONG_PTR; -pub type DWORD_PTR = ULONG_PTR; -pub type PDWORD_PTR = *mut ULONG_PTR; -pub type LONG64 = ::std::os::raw::c_longlong; -pub type PLONG64 = *mut ::std::os::raw::c_longlong; -pub type ULONG64 = ::std::os::raw::c_ulonglong; -pub type PULONG64 = *mut ::std::os::raw::c_ulonglong; -pub type DWORD64 = ::std::os::raw::c_ulonglong; -pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong; -pub type KAFFINITY = ULONG_PTR; -pub type PKAFFINITY = *mut KAFFINITY; -pub type PVOID = *mut ::std::os::raw::c_void; -pub type CHAR = ::std::os::raw::c_char; -pub type SHORT = ::std::os::raw::c_short; -pub type LONG = ::std::os::raw::c_long; -pub type WCHAR = wchar_t; -pub type PWCHAR = *mut WCHAR; -pub type LPWCH = *mut WCHAR; -pub type PWCH = *mut WCHAR; -pub type LPCWCH = *const WCHAR; -pub type PCWCH = *const WCHAR; -pub type NWPSTR = *mut WCHAR; -pub type LPWSTR = *mut WCHAR; -pub type PWSTR = *mut WCHAR; -pub type PZPWSTR = *mut PWSTR; -pub type PCZPWSTR = *const PWSTR; -pub type LPUWSTR = *mut WCHAR; -pub type PUWSTR = *mut WCHAR; -pub type LPCWSTR = *const WCHAR; -pub type PCWSTR = *const WCHAR; -pub type PZPCWSTR = *mut PCWSTR; -pub type PCZPCWSTR = *const PCWSTR; -pub type LPCUWSTR = *const WCHAR; -pub type PCUWSTR = *const WCHAR; -pub type PZZWSTR = *mut WCHAR; -pub type PCZZWSTR = *const WCHAR; -pub type PUZZWSTR = *mut WCHAR; -pub type PCUZZWSTR = *const WCHAR; -pub type PNZWCH = *mut WCHAR; -pub type PCNZWCH = *const WCHAR; -pub type PUNZWCH = *mut WCHAR; -pub type PCUNZWCH = *const WCHAR; -pub type PCHAR = *mut CHAR; -pub type LPCH = *mut CHAR; -pub type PCH = *mut CHAR; -pub type LPCCH = *const CHAR; -pub type PCCH = *const CHAR; -pub type NPSTR = *mut CHAR; -pub type LPSTR = *mut CHAR; -pub type PSTR = *mut CHAR; -pub type PZPSTR = *mut PSTR; -pub type PCZPSTR = *const PSTR; -pub type LPCSTR = *const CHAR; -pub type PCSTR = *const CHAR; -pub type PZPCSTR = *mut PCSTR; -pub type PCZPCSTR = *const PCSTR; -pub type PZZSTR = *mut CHAR; -pub type PCZZSTR = *const CHAR; -pub type PNZCH = *mut CHAR; -pub type PCNZCH = *const CHAR; -pub type TCHAR = ::std::os::raw::c_char; -pub type PTCHAR = *mut ::std::os::raw::c_char; -pub type TBYTE = ::std::os::raw::c_uchar; -pub type PTBYTE = *mut ::std::os::raw::c_uchar; -pub type LPTCH = LPCH; -pub type PTCH = LPCH; -pub type LPCTCH = LPCCH; -pub type PCTCH = LPCCH; -pub type PTSTR = LPSTR; -pub type LPTSTR = LPSTR; -pub type PUTSTR = LPSTR; -pub type LPUTSTR = LPSTR; -pub type PCTSTR = LPCSTR; -pub type LPCTSTR = LPCSTR; -pub type PCUTSTR = LPCSTR; -pub type LPCUTSTR = LPCSTR; -pub type PZZTSTR = PZZSTR; -pub type PUZZTSTR = PZZSTR; -pub type PCZZTSTR = PCZZSTR; -pub type PCUZZTSTR = PCZZSTR; -pub type PZPTSTR = PZPSTR; -pub type PNZTCH = PNZCH; -pub type PUNZTCH = PNZCH; -pub type PCNZTCH = PCNZCH; -pub type PCUNZTCH = PCNZCH; -pub type PSHORT = *mut SHORT; -pub type PLONG = *mut LONG; -pub type ULONG = ::std::os::raw::c_ulong; -pub type PULONG = *mut ULONG; -pub type USHORT = ::std::os::raw::c_ushort; -pub type PUSHORT = *mut USHORT; -pub type UCHAR = ::std::os::raw::c_uchar; -pub type PUCHAR = *mut UCHAR; -pub type PSZ = *mut ::std::os::raw::c_char; -pub type DWORD = ::std::os::raw::c_ulong; -pub type BOOL = ::std::os::raw::c_int; -pub type BYTE = ::std::os::raw::c_uchar; -pub type WORD = ::std::os::raw::c_ushort; -pub type FLOAT = f32; -pub type PFLOAT = *mut FLOAT; -pub type PBOOL = *mut BOOL; -pub type LPBOOL = *mut BOOL; -pub type PBYTE = *mut BYTE; -pub type LPBYTE = *mut BYTE; -pub type PINT = *mut ::std::os::raw::c_int; -pub type LPINT = *mut ::std::os::raw::c_int; -pub type PWORD = *mut WORD; -pub type LPWORD = *mut WORD; -pub type LPLONG = *mut ::std::os::raw::c_long; -pub type PDWORD = *mut DWORD; -pub type LPDWORD = *mut DWORD; -pub type LPVOID = *mut ::std::os::raw::c_void; -pub type LPCVOID = *const ::std::os::raw::c_void; -pub type INT = ::std::os::raw::c_int; -pub type UINT = ::std::os::raw::c_uint; -pub type PUINT = *mut ::std::os::raw::c_uint; -pub type va_list = *mut ::std::os::raw::c_char; - -pub const TRUE: ::std::os::raw::c_int = 1; -pub const FALSE: ::std::os::raw::c_int = 0; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_HEADER { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, -} -pub type CLIPRDR_HEADER = _CLIPRDR_HEADER; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_CAPABILITY_SET { - pub capabilitySetType: UINT16, - pub capabilitySetLength: UINT16, -} -pub type CLIPRDR_CAPABILITY_SET = _CLIPRDR_CAPABILITY_SET; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_GENERAL_CAPABILITY_SET { - pub capabilitySetType: UINT16, - pub capabilitySetLength: UINT16, - pub version: UINT32, - pub generalFlags: UINT32, -} -pub type CLIPRDR_GENERAL_CAPABILITY_SET = _CLIPRDR_GENERAL_CAPABILITY_SET; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_CAPABILITIES { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub cCapabilitiesSets: UINT32, - pub capabilitySets: *mut CLIPRDR_CAPABILITY_SET, -} -pub type CLIPRDR_CAPABILITIES = _CLIPRDR_CAPABILITIES; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_MONITOR_READY { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, -} -pub type CLIPRDR_MONITOR_READY = _CLIPRDR_MONITOR_READY; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_TEMP_DIRECTORY { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub szTempDir: [::std::os::raw::c_char; 520usize], -} -pub type CLIPRDR_TEMP_DIRECTORY = _CLIPRDR_TEMP_DIRECTORY; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FORMAT { - pub formatId: UINT32, - pub formatName: *mut ::std::os::raw::c_char, -} -pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FORMAT_LIST { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub numFormats: UINT32, - pub formats: *mut CLIPRDR_FORMAT, -} -pub type CLIPRDR_FORMAT_LIST = _CLIPRDR_FORMAT_LIST; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FORMAT_LIST_RESPONSE { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, -} -pub type CLIPRDR_FORMAT_LIST_RESPONSE = _CLIPRDR_FORMAT_LIST_RESPONSE; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_LOCK_CLIPBOARD_DATA { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub clipDataId: UINT32, -} -pub type CLIPRDR_LOCK_CLIPBOARD_DATA = _CLIPRDR_LOCK_CLIPBOARD_DATA; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub clipDataId: UINT32, -} -pub type CLIPRDR_UNLOCK_CLIPBOARD_DATA = _CLIPRDR_UNLOCK_CLIPBOARD_DATA; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FORMAT_DATA_REQUEST { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub requestedFormatId: UINT32, -} -pub type CLIPRDR_FORMAT_DATA_REQUEST = _CLIPRDR_FORMAT_DATA_REQUEST; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FORMAT_DATA_RESPONSE { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub requestedFormatData: *const BYTE, -} -pub type CLIPRDR_FORMAT_DATA_RESPONSE = _CLIPRDR_FORMAT_DATA_RESPONSE; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FILE_CONTENTS_REQUEST { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub streamId: UINT32, - pub listIndex: UINT32, - pub dwFlags: UINT32, - pub nPositionLow: UINT32, - pub nPositionHigh: UINT32, - pub cbRequested: UINT32, - pub haveClipDataId: BOOL, - pub clipDataId: UINT32, -} -pub type CLIPRDR_FILE_CONTENTS_REQUEST = _CLIPRDR_FILE_CONTENTS_REQUEST; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE { - pub connID: UINT32, - pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, - pub streamId: UINT32, - pub cbRequested: UINT32, - pub requestedData: *const BYTE, -} -pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE; -pub type CliprdrClientContext = _cliprdr_client_context; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _NOTIFICATION_MESSAGE { - pub r#type: UINT32, // 0 - info, 1 - warning, 2 - error - pub msg: *const BYTE, - pub details: *const BYTE, -} -pub type NOTIFICATION_MESSAGE = _NOTIFICATION_MESSAGE; -pub type pcCliprdrServerCapabilities = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - capabilities: *const CLIPRDR_CAPABILITIES, - ) -> UINT, ->; -pub type pcCliprdrClientCapabilities = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - capabilities: *const CLIPRDR_CAPABILITIES, - ) -> UINT, ->; -pub type pcCliprdrMonitorReady = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - monitorReady: *const CLIPRDR_MONITOR_READY, - ) -> UINT, ->; -pub type pcCliprdrTempDirectory = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - tempDirectory: *const CLIPRDR_TEMP_DIRECTORY, - ) -> UINT, ->; -pub type pcNotifyClipboardMsg = - ::std::option::Option UINT>; -pub type pcCliprdrClientFormatList = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatList: *const CLIPRDR_FORMAT_LIST, - ) -> UINT, ->; -pub type pcCliprdrServerFormatList = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatList: *const CLIPRDR_FORMAT_LIST, - ) -> UINT, ->; -pub type pcCliprdrClientFormatListResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE, - ) -> UINT, ->; -pub type pcCliprdrServerFormatListResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE, - ) -> UINT, ->; -pub type pcCliprdrClientLockClipboardData = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA, - ) -> UINT, ->; -pub type pcCliprdrServerLockClipboardData = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA, - ) -> UINT, ->; -pub type pcCliprdrClientUnlockClipboardData = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA, - ) -> UINT, ->; -pub type pcCliprdrServerUnlockClipboardData = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA, - ) -> UINT, ->; -pub type pcCliprdrClientFormatDataRequest = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST, - ) -> UINT, ->; -pub type pcCliprdrServerFormatDataRequest = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST, - ) -> UINT, ->; -pub type pcCliprdrClientFormatDataResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE, - ) -> UINT, ->; -pub type pcCliprdrServerFormatDataResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE, - ) -> UINT, ->; -pub type pcCliprdrClientFileContentsRequest = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST, - ) -> UINT, ->; -pub type pcCliprdrServerFileContentsRequest = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST, - ) -> UINT, ->; -pub type pcCliprdrClientFileContentsResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, - ) -> UINT, ->; -pub type pcCliprdrServerFileContentsResponse = ::std::option::Option< - unsafe extern "C" fn( - context: *mut CliprdrClientContext, - fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, - ) -> UINT, ->; - -// TODO: hide more members of clipboard context -#[repr(C)] -#[derive(Debug, Clone)] -pub struct _cliprdr_client_context { - pub Custom: *mut ::std::os::raw::c_void, - pub EnableFiles: BOOL, - pub EnableOthers: BOOL, - pub IsStopped: BOOL, - pub ResponseWaitTimeoutSecs: UINT32, - pub ServerCapabilities: pcCliprdrServerCapabilities, - pub ClientCapabilities: pcCliprdrClientCapabilities, - pub MonitorReady: pcCliprdrMonitorReady, - pub TempDirectory: pcCliprdrTempDirectory, - pub NotifyClipboardMsg: pcNotifyClipboardMsg, - pub ClientFormatList: pcCliprdrClientFormatList, - pub ServerFormatList: pcCliprdrServerFormatList, - pub ClientFormatListResponse: pcCliprdrClientFormatListResponse, - pub ServerFormatListResponse: pcCliprdrServerFormatListResponse, - pub ClientLockClipboardData: pcCliprdrClientLockClipboardData, - pub ServerLockClipboardData: pcCliprdrServerLockClipboardData, - pub ClientUnlockClipboardData: pcCliprdrClientUnlockClipboardData, - pub ServerUnlockClipboardData: pcCliprdrServerUnlockClipboardData, - pub ClientFormatDataRequest: pcCliprdrClientFormatDataRequest, - pub ServerFormatDataRequest: pcCliprdrServerFormatDataRequest, - pub ClientFormatDataResponse: pcCliprdrClientFormatDataResponse, - pub ServerFormatDataResponse: pcCliprdrServerFormatDataResponse, - pub ClientFileContentsRequest: pcCliprdrClientFileContentsRequest, - pub ServerFileContentsRequest: pcCliprdrServerFileContentsRequest, - pub ClientFileContentsResponse: pcCliprdrClientFileContentsResponse, - pub ServerFileContentsResponse: pcCliprdrServerFileContentsResponse, - pub LastRequestedFormatId: UINT32, -} - -// #[link(name = "user32")] -// #[link(name = "ole32")] -extern "C" { - pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL; - pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL; - pub(crate) fn empty_cliprdr(context: *mut CliprdrClientContext, connID: UINT32) -> BOOL; -} - -#[derive(Error, Debug)] -pub enum CliprdrError { - #[error("invalid cliprdr name")] - CliprdrName, - #[error("failed to init cliprdr")] - CliprdrInit, - #[error("unknown cliprdr error")] - Unknown, -} - -impl CliprdrClientContext { - pub fn create( - enable_files: bool, - enable_others: bool, - response_wait_timeout_secs: u32, - notify_callback: pcNotifyClipboardMsg, - client_format_list: pcCliprdrClientFormatList, - client_format_list_response: pcCliprdrClientFormatListResponse, - client_format_data_request: pcCliprdrClientFormatDataRequest, - client_format_data_response: pcCliprdrClientFormatDataResponse, - client_file_contents_request: pcCliprdrClientFileContentsRequest, - client_file_contents_response: pcCliprdrClientFileContentsResponse, - ) -> Result, CliprdrError> { - let context = CliprdrClientContext { - Custom: 0 as *mut _, - EnableFiles: if enable_files { TRUE } else { FALSE }, - EnableOthers: if enable_others { TRUE } else { FALSE }, - IsStopped: FALSE, - ResponseWaitTimeoutSecs: response_wait_timeout_secs, - ServerCapabilities: None, - ClientCapabilities: None, - MonitorReady: None, - TempDirectory: None, - NotifyClipboardMsg: notify_callback, - ClientFormatList: client_format_list, - ServerFormatList: None, - ClientFormatListResponse: client_format_list_response, - ServerFormatListResponse: None, - ClientLockClipboardData: None, - ServerLockClipboardData: None, - ClientUnlockClipboardData: None, - ServerUnlockClipboardData: None, - ClientFormatDataRequest: client_format_data_request, - ServerFormatDataRequest: None, - ClientFormatDataResponse: client_format_data_response, - ServerFormatDataResponse: None, - ClientFileContentsRequest: client_file_contents_request, - ServerFileContentsRequest: None, - ClientFileContentsResponse: client_file_contents_response, - ServerFileContentsResponse: None, - LastRequestedFormatId: 0, - }; - let mut context = Box::new(context); - unsafe { - if FALSE == init_cliprdr(&mut (*context)) { - println!("Failed to init cliprdr"); - Err(CliprdrError::CliprdrInit) - } else { - Ok(context) - } - } - } -} - -impl Drop for CliprdrClientContext { - fn drop(&mut self) { - unsafe { - if FALSE == uninit_cliprdr(&mut *self) { - println!("Failed to uninit cliprdr"); - } else { - println!("Succeeded to uninit cliprdr"); - } - } - } -} diff --git a/libs/clipboard/src/context_send.rs b/libs/clipboard/src/context_send.rs index 76f8e4d7a..66c0d37fb 100644 --- a/libs/clipboard/src/context_send.rs +++ b/libs/clipboard/src/context_send.rs @@ -1,34 +1,32 @@ -use crate::cliprdr::*; -use hbb_common::log; +use hbb_common::{log, ResultType}; use std::sync::Mutex; +use crate::CliprdrServiceContext; + const CLIPBOARD_RESPONSE_WAIT_TIMEOUT_SECS: u32 = 30; lazy_static::lazy_static! { - static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(0)}; + static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(None)}; } pub struct ContextSend { - addr: Mutex, + addr: Mutex>>, } impl ContextSend { #[inline] pub fn is_enabled() -> bool { - *CONTEXT_SEND.addr.lock().unwrap() != 0 + CONTEXT_SEND.addr.lock().unwrap().is_some() } pub fn set_is_stopped() { - let _res = Self::proc(|c| { - c.IsStopped = TRUE; - 0 - }); + let _res = Self::proc(|c| c.set_is_stopped().map_err(|e| e.into())); } pub fn enable(enabled: bool) { let mut lock = CONTEXT_SEND.addr.lock().unwrap(); if enabled { - if *lock == 0 { + if lock.is_none() { match crate::create_cliprdr_context( true, false, @@ -36,7 +34,7 @@ impl ContextSend { ) { Ok(context) => { log::info!("clipboard context for file transfer created."); - *lock = Box::into_raw(context) as _; + *lock = Some(context) } Err(err) => { log::error!( @@ -47,27 +45,20 @@ impl ContextSend { } } } else { - if *lock != 0 { - unsafe { - let _ = Box::from_raw(*lock as *mut CliprdrClientContext); - } + if let Some(_clp) = lock.take() { + *lock = None; log::info!("clipboard context for file transfer destroyed."); - *lock = 0; } } } - pub fn proc) -> u32>(f: F) -> u32 { - let lock = CONTEXT_SEND.addr.lock().unwrap(); - if *lock != 0 { - unsafe { - let mut context = Box::from_raw(*lock as *mut CliprdrClientContext); - let code = f(&mut context); - std::mem::forget(context); - code - } - } else { - 0 + pub fn proc) -> ResultType<()>>( + f: F, + ) -> ResultType<()> { + let mut lock = CONTEXT_SEND.addr.lock().unwrap(); + match lock.as_mut() { + Some(context) => f(context), + None => Ok(()), } } } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 84179621d..5679393c5 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -1,4 +1,8 @@ -use cliprdr::*; +use std::{ + ffi::{CStr, CString}, + sync::{Arc, Mutex, RwLock}, +}; + use hbb_common::{ allow_err, lazy_static, log, tokio::sync::{ @@ -8,19 +12,47 @@ use hbb_common::{ ResultType, SessionID, }; use serde_derive::{Deserialize, Serialize}; -use std::{ - boxed::Box, - ffi::{CStr, CString}, - sync::{Arc, Mutex, RwLock}, -}; +use thiserror::Error; -pub mod cliprdr; pub mod context_send; +pub mod platform; pub use context_send::*; const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001; const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002; +pub(crate) use platform::create_cliprdr_context; + +/// Ability to handle Clipboard File from remote rustdesk client +/// +/// # Note +/// There actually should be 2 parts to implement a useable clipboard file service, +/// but this only contains the RPC server part. +/// The local listener and transport part is too platform specific to wrap up in typeclasses. +pub trait CliprdrServiceContext: Send + Sync { + /// set to be stopped + fn set_is_stopped(&mut self) -> Result<(), CliprdrError>; + /// clear the content on clipboard + fn empty_clipboard(&mut self, conn_id: i32) -> bool; + + /// run as a server for clipboard RPC + fn server_clip_file(&mut self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError>; +} + +#[derive(Error, Debug)] +pub enum CliprdrError { + #[error("invalid cliprdr name")] + CliprdrName, + #[error("failed to init cliprdr")] + CliprdrInit, + #[error("cliprdr out of memory")] + CliprdrOutOfMemory, + #[error("cliprdr internal error")] + ClipboardInternalError, + #[error("unknown cliprdr error")] + Unknown(u32), +} + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "t", content = "c")] pub enum ClipboardFile { @@ -164,554 +196,6 @@ fn send_data(conn_id: i32, data: ClipboardFile) { } } -pub fn empty_clipboard(context: &mut Box, conn_id: i32) -> bool { - unsafe { TRUE == cliprdr::empty_cliprdr(&mut (**context), conn_id as u32) } -} - -pub fn server_clip_file( - context: &mut Box, - conn_id: i32, - msg: ClipboardFile, -) -> u32 { - let mut ret = 0; - match msg { - ClipboardFile::NotifyCallback { .. } => { - // unreachable - } - ClipboardFile::MonitorReady => { - log::debug!("server_monitor_ready called"); - ret = server_monitor_ready(context, conn_id); - log::debug!("server_monitor_ready called, return {}", ret); - } - ClipboardFile::FormatList { format_list } => { - log::debug!("server_format_list called"); - ret = server_format_list(context, conn_id, format_list); - log::debug!("server_format_list called, return {}", ret); - } - ClipboardFile::FormatListResponse { msg_flags } => { - log::debug!("format_list_response called"); - ret = server_format_list_response(context, conn_id, msg_flags); - log::debug!("server_format_list_response called, return {}", ret); - } - ClipboardFile::FormatDataRequest { - requested_format_id, - } => { - log::debug!("format_data_request called"); - ret = server_format_data_request(context, conn_id, requested_format_id); - log::debug!("server_format_data_request called, return {}", ret); - } - ClipboardFile::FormatDataResponse { - msg_flags, - format_data, - } => { - log::debug!("format_data_response called"); - ret = server_format_data_response(context, conn_id, msg_flags, format_data); - log::debug!("server_format_data_response called, return {}", ret); - } - ClipboardFile::FileContentsRequest { - stream_id, - list_index, - dw_flags, - n_position_low, - n_position_high, - cb_requested, - have_clip_data_id, - clip_data_id, - } => { - log::debug!("file_contents_request called"); - ret = server_file_contents_request( - context, - conn_id, - stream_id, - list_index, - dw_flags, - n_position_low, - n_position_high, - cb_requested, - have_clip_data_id, - clip_data_id, - ); - log::debug!("server_file_contents_request called, return {}", ret); - } - ClipboardFile::FileContentsResponse { - msg_flags, - stream_id, - requested_data, - } => { - log::debug!("file_contents_response called"); - ret = server_file_contents_response( - context, - conn_id, - msg_flags, - stream_id, - requested_data, - ); - log::debug!("server_file_contents_response called, return {}", ret); - } - } - ret -} - -pub fn server_monitor_ready(context: &mut Box, conn_id: i32) -> u32 { - unsafe { - let monitor_ready = CLIPRDR_MONITOR_READY { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: 0 as UINT16, - dataLen: 0 as UINT32, - }; - if let Some(f) = (**context).MonitorReady { - let ret = f(&mut (**context), &monitor_ready); - ret as u32 - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn server_format_list( - context: &mut Box, - conn_id: i32, - format_list: Vec<(i32, String)>, -) -> u32 { - unsafe { - let num_formats = format_list.len() as UINT32; - let mut formats = format_list - .into_iter() - .map(|format| { - if format.1.is_empty() { - CLIPRDR_FORMAT { - formatId: format.0 as UINT32, - formatName: 0 as *mut _, - } - } else { - let n = match CString::new(format.1) { - Ok(n) => n, - Err(_) => CString::new("").unwrap(), - }; - CLIPRDR_FORMAT { - formatId: format.0 as UINT32, - formatName: n.into_raw(), - } - } - }) - .collect::>(); - - let format_list = CLIPRDR_FORMAT_LIST { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: 0 as UINT16, - dataLen: 0 as UINT32, - numFormats: num_formats, - formats: formats.as_mut_ptr(), - }; - - let ret = if let Some(f) = (**context).ServerFormatList { - f(&mut (**context), &format_list) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - }; - - for f in formats { - if !f.formatName.is_null() { - // retake pointer to free memory - let _ = CString::from_raw(f.formatName); - } - } - - ret as u32 - } -} - -pub fn server_format_list_response( - context: &mut Box, - conn_id: i32, - msg_flags: i32, -) -> u32 { - unsafe { - let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: msg_flags as UINT16, - dataLen: 0 as UINT32, - }; - - if let Some(f) = (**context).ServerFormatListResponse { - f(&mut (**context), &format_list_response) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn server_format_data_request( - context: &mut Box, - conn_id: i32, - requested_format_id: i32, -) -> u32 { - unsafe { - let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: 0 as UINT16, - dataLen: 0 as UINT32, - requestedFormatId: requested_format_id as UINT32, - }; - if let Some(f) = (**context).ServerFormatDataRequest { - f(&mut (**context), &format_data_request) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn server_format_data_response( - context: &mut Box, - conn_id: i32, - msg_flags: i32, - mut format_data: Vec, -) -> u32 { - unsafe { - let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: msg_flags as UINT16, - dataLen: format_data.len() as UINT32, - requestedFormatData: format_data.as_mut_ptr(), - }; - if let Some(f) = (**context).ServerFormatDataResponse { - f(&mut (**context), &format_data_response) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn server_file_contents_request( - context: &mut Box, - conn_id: i32, - stream_id: i32, - list_index: i32, - dw_flags: i32, - n_position_low: i32, - n_position_high: i32, - cb_requested: i32, - have_clip_data_id: bool, - clip_data_id: i32, -) -> u32 { - unsafe { - let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: 0 as UINT16, - dataLen: 0 as UINT32, - streamId: stream_id as UINT32, - listIndex: list_index as UINT32, - dwFlags: dw_flags as UINT32, - nPositionLow: n_position_low as UINT32, - nPositionHigh: n_position_high as UINT32, - cbRequested: cb_requested as UINT32, - haveClipDataId: if have_clip_data_id { TRUE } else { FALSE }, - clipDataId: clip_data_id as UINT32, - }; - if let Some(f) = (**context).ServerFileContentsRequest { - f(&mut (**context), &file_contents_request) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn server_file_contents_response( - context: &mut Box, - conn_id: i32, - msg_flags: i32, - stream_id: i32, - mut requested_data: Vec, -) -> u32 { - unsafe { - let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE { - connID: conn_id as UINT32, - msgType: 0 as UINT16, - msgFlags: msg_flags as UINT16, - dataLen: 4 + requested_data.len() as UINT32, - streamId: stream_id as UINT32, - cbRequested: requested_data.len() as UINT32, - requestedData: requested_data.as_mut_ptr(), - }; - if let Some(f) = (**context).ServerFileContentsResponse { - f(&mut (**context), &file_contents_response) - } else { - ERR_CODE_SERVER_FUNCTION_NONE - } - } -} - -pub fn create_cliprdr_context( - enable_files: bool, - enable_others: bool, - response_wait_timeout_secs: u32, -) -> ResultType> { - Ok(CliprdrClientContext::create( - enable_files, - enable_others, - response_wait_timeout_secs, - Some(notify_callback), - Some(client_format_list), - Some(client_format_list_response), - Some(client_format_data_request), - Some(client_format_data_response), - Some(client_file_contents_request), - Some(client_file_contents_response), - )?) -} - -extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE) -> UINT { - log::debug!("notify_callback called"); - let data = unsafe { - let msg = &*msg; - let details = if msg.details.is_null() { - Ok("") - } else { - CStr::from_ptr(msg.details as _).to_str() - }; - match (CStr::from_ptr(msg.msg as _).to_str(), details) { - (Ok(m), Ok(d)) => { - let msgtype = format!( - "custom-{}-nocancel-nook-hasclose", - if msg.r#type == 0 { - "info" - } else if msg.r#type == 1 { - "warn" - } else { - "error" - } - ); - let title = "Clipboard"; - let text = if d.is_empty() { - m.to_string() - } else { - format!("{} {}", m, d) - }; - ClipboardFile::NotifyCallback { - r#type: msgtype, - title: title.to_string(), - text, - } - } - _ => { - log::error!("notify_callback: failed to convert msg"); - return ERR_CODE_INVALID_PARAMETER; - } - } - }; - // no need to handle result here - send_data(conn_id as _, data); - - 0 -} - -extern "C" fn client_format_list( - _context: *mut CliprdrClientContext, - clip_format_list: *const CLIPRDR_FORMAT_LIST, -) -> UINT { - log::debug!("client_format_list called"); - - let conn_id; - let mut format_list: Vec<(i32, String)> = Vec::new(); - unsafe { - let mut i = 0u32; - while i < (*clip_format_list).numFormats { - let format_data = &(*(*clip_format_list).formats.offset(i as isize)); - if format_data.formatName.is_null() { - format_list.push((format_data.formatId as i32, "".to_owned())); - } else { - let format_name = CStr::from_ptr(format_data.formatName).to_str(); - let format_name = match format_name { - Ok(n) => n.to_owned(), - Err(_) => { - log::warn!("failed to get format name"); - "".to_owned() - } - }; - format_list.push((format_data.formatId as i32, format_name)); - } - // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); - i += 1; - } - conn_id = (*clip_format_list).connID as i32; - } - let data = ClipboardFile::FormatList { format_list }; - // no need to handle result here - if conn_id == 0 { - // msg_channel is used for debug, VEC_MSG_CHANNEL cannot be inspected by the debugger. - let msg_channel = VEC_MSG_CHANNEL.read().unwrap(); - msg_channel - .iter() - .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); - } else { - send_data(conn_id, data); - } - - 0 -} - -extern "C" fn client_format_list_response( - _context: *mut CliprdrClientContext, - format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE, -) -> UINT { - log::debug!("client_format_list_response called"); - - let conn_id; - let msg_flags; - unsafe { - conn_id = (*format_list_response).connID as i32; - msg_flags = (*format_list_response).msgFlags as i32; - } - let data = ClipboardFile::FormatListResponse { msg_flags }; - send_data(conn_id, data); - - 0 -} - -extern "C" fn client_format_data_request( - _context: *mut CliprdrClientContext, - format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST, -) -> UINT { - log::debug!("client_format_data_request called"); - - let conn_id; - let requested_format_id; - unsafe { - conn_id = (*format_data_request).connID as i32; - requested_format_id = (*format_data_request).requestedFormatId as i32; - } - let data = ClipboardFile::FormatDataRequest { - requested_format_id, - }; - // no need to handle result here - send_data(conn_id, data); - - 0 -} - -extern "C" fn client_format_data_response( - _context: *mut CliprdrClientContext, - format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE, -) -> UINT { - log::debug!("cconn_idlient_format_data_response called"); - - let conn_id; - let msg_flags; - let format_data; - unsafe { - conn_id = (*format_data_response).connID as i32; - msg_flags = (*format_data_response).msgFlags as i32; - if (*format_data_response).requestedFormatData.is_null() { - format_data = Vec::new(); - } else { - format_data = std::slice::from_raw_parts( - (*format_data_response).requestedFormatData, - (*format_data_response).dataLen as usize, - ) - .to_vec(); - } - } - let data = ClipboardFile::FormatDataResponse { - msg_flags, - format_data, - }; - send_data(conn_id, data); - - 0 -} - -extern "C" fn client_file_contents_request( - _context: *mut CliprdrClientContext, - file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST, -) -> UINT { - log::debug!("client_file_contents_request called"); - - // TODO: support huge file? - // if (!cliprdr->hasHugeFileSupport) - // { - // if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) > - // UINT32_MAX) - // return ERROR_INVALID_PARAMETER; - // if (fileContentsRequest->nPositionHigh != 0) - // return ERROR_INVALID_PARAMETER; - // } - - let conn_id; - let stream_id; - let list_index; - let dw_flags; - let n_position_low; - let n_position_high; - let cb_requested; - let have_clip_data_id; - let clip_data_id; - unsafe { - conn_id = (*file_contents_request).connID as i32; - stream_id = (*file_contents_request).streamId as i32; - list_index = (*file_contents_request).listIndex as i32; - dw_flags = (*file_contents_request).dwFlags as i32; - n_position_low = (*file_contents_request).nPositionLow as i32; - n_position_high = (*file_contents_request).nPositionHigh as i32; - cb_requested = (*file_contents_request).cbRequested as i32; - have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; - clip_data_id = (*file_contents_request).clipDataId as i32; - } - - let data = ClipboardFile::FileContentsRequest { - stream_id, - list_index, - dw_flags, - n_position_low, - n_position_high, - cb_requested, - have_clip_data_id, - clip_data_id, - }; - send_data(conn_id, data); - - 0 -} - -extern "C" fn client_file_contents_response( - _context: *mut CliprdrClientContext, - file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE, -) -> UINT { - log::debug!("client_file_contents_response called"); - - let conn_id; - let msg_flags; - let stream_id; - let requested_data; - unsafe { - conn_id = (*file_contents_response).connID as i32; - msg_flags = (*file_contents_response).msgFlags as i32; - stream_id = (*file_contents_response).streamId as i32; - if (*file_contents_response).requestedData.is_null() { - requested_data = Vec::new(); - } else { - requested_data = std::slice::from_raw_parts( - (*file_contents_response).requestedData, - (*file_contents_response).cbRequested as usize, - ) - .to_vec(); - } - } - let data = ClipboardFile::FileContentsResponse { - msg_flags, - stream_id, - requested_data, - }; - send_data(conn_id, data); - - 0 -} - #[cfg(test)] mod tests { // #[test] diff --git a/libs/clipboard/src/platform/mod.rs b/libs/clipboard/src/platform/mod.rs new file mode 100644 index 000000000..1bca4493c --- /dev/null +++ b/libs/clipboard/src/platform/mod.rs @@ -0,0 +1,10 @@ +#[cfg(target_os = "windows")] +pub mod windows; +#[cfg(target_os = "windows")] +pub fn create_cliprdr_context( + enable_files: bool, + enable_others: bool, + response_wait_timeout_secs: u32, +) -> crate::ResultType> { + windows::create_cliprdr_context(enable_files, enable_others, response_wait_timeout_secs) +} diff --git a/libs/clipboard/src/platform/windows.rs b/libs/clipboard/src/platform/windows.rs new file mode 100644 index 000000000..1ab1aa839 --- /dev/null +++ b/libs/clipboard/src/platform/windows.rs @@ -0,0 +1,1214 @@ +//! windows implementation +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(unused_variables)] +#![allow(non_snake_case)] +#![allow(deref_nullptr)] + +use std::{boxed::Box, result::Result}; + +use crate::{ + allow_err, log, send_data, CStr, CString, ClipboardFile, CliprdrError, CliprdrServiceContext, + ResultType, ERR_CODE_INVALID_PARAMETER, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL, +}; + +// only used error code will be recorded here +/// success +const CHANNEL_RC_OK: u32 = 0; +/// error code from WinError.h +/// success +const ERROR_SUCCESS: u32 = 0; +/// allocation failure +const CHANNEL_RC_NO_MEMORY: u32 = 12; +/// error code from WinError.h +/// used by FreeRDP to represent errors. +const ERROR_INTERNAL_ERROR: u32 = 0x54F; + +pub type size_t = ::std::os::raw::c_ulonglong; +pub type __vcrt_bool = bool; +pub type wchar_t = ::std::os::raw::c_ushort; + +pub type POINTER_64_INT = ::std::os::raw::c_ulonglong; +pub type INT8 = ::std::os::raw::c_schar; +pub type PINT8 = *mut ::std::os::raw::c_schar; +pub type INT16 = ::std::os::raw::c_short; +pub type PINT16 = *mut ::std::os::raw::c_short; +pub type INT32 = ::std::os::raw::c_int; +pub type PINT32 = *mut ::std::os::raw::c_int; +pub type INT64 = ::std::os::raw::c_longlong; +pub type PINT64 = *mut ::std::os::raw::c_longlong; +pub type UINT8 = ::std::os::raw::c_uchar; +pub type PUINT8 = *mut ::std::os::raw::c_uchar; +pub type UINT16 = ::std::os::raw::c_ushort; +pub type PUINT16 = *mut ::std::os::raw::c_ushort; +pub type UINT32 = ::std::os::raw::c_uint; +pub type PUINT32 = *mut ::std::os::raw::c_uint; +pub type UINT64 = ::std::os::raw::c_ulonglong; +pub type PUINT64 = *mut ::std::os::raw::c_ulonglong; +pub type LONG32 = ::std::os::raw::c_int; +pub type PLONG32 = *mut ::std::os::raw::c_int; +pub type ULONG32 = ::std::os::raw::c_uint; +pub type PULONG32 = *mut ::std::os::raw::c_uint; +pub type DWORD32 = ::std::os::raw::c_uint; +pub type PDWORD32 = *mut ::std::os::raw::c_uint; +pub type INT_PTR = ::std::os::raw::c_longlong; +pub type PINT_PTR = *mut ::std::os::raw::c_longlong; +pub type UINT_PTR = ::std::os::raw::c_ulonglong; +pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong; +pub type LONG_PTR = ::std::os::raw::c_longlong; +pub type PLONG_PTR = *mut ::std::os::raw::c_longlong; +pub type ULONG_PTR = ::std::os::raw::c_ulonglong; +pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong; +pub type SHANDLE_PTR = ::std::os::raw::c_longlong; +pub type HANDLE_PTR = ::std::os::raw::c_ulonglong; +pub type UHALF_PTR = ::std::os::raw::c_uint; +pub type PUHALF_PTR = *mut ::std::os::raw::c_uint; +pub type HALF_PTR = ::std::os::raw::c_int; +pub type PHALF_PTR = *mut ::std::os::raw::c_int; +pub type SIZE_T = ULONG_PTR; +pub type PSIZE_T = *mut ULONG_PTR; +pub type SSIZE_T = LONG_PTR; +pub type PSSIZE_T = *mut LONG_PTR; +pub type DWORD_PTR = ULONG_PTR; +pub type PDWORD_PTR = *mut ULONG_PTR; +pub type LONG64 = ::std::os::raw::c_longlong; +pub type PLONG64 = *mut ::std::os::raw::c_longlong; +pub type ULONG64 = ::std::os::raw::c_ulonglong; +pub type PULONG64 = *mut ::std::os::raw::c_ulonglong; +pub type DWORD64 = ::std::os::raw::c_ulonglong; +pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong; +pub type KAFFINITY = ULONG_PTR; +pub type PKAFFINITY = *mut KAFFINITY; +pub type PVOID = *mut ::std::os::raw::c_void; +pub type CHAR = ::std::os::raw::c_char; +pub type SHORT = ::std::os::raw::c_short; +pub type LONG = ::std::os::raw::c_long; +pub type WCHAR = wchar_t; +pub type PWCHAR = *mut WCHAR; +pub type LPWCH = *mut WCHAR; +pub type PWCH = *mut WCHAR; +pub type LPCWCH = *const WCHAR; +pub type PCWCH = *const WCHAR; +pub type NWPSTR = *mut WCHAR; +pub type LPWSTR = *mut WCHAR; +pub type PWSTR = *mut WCHAR; +pub type PZPWSTR = *mut PWSTR; +pub type PCZPWSTR = *const PWSTR; +pub type LPUWSTR = *mut WCHAR; +pub type PUWSTR = *mut WCHAR; +pub type LPCWSTR = *const WCHAR; +pub type PCWSTR = *const WCHAR; +pub type PZPCWSTR = *mut PCWSTR; +pub type PCZPCWSTR = *const PCWSTR; +pub type LPCUWSTR = *const WCHAR; +pub type PCUWSTR = *const WCHAR; +pub type PZZWSTR = *mut WCHAR; +pub type PCZZWSTR = *const WCHAR; +pub type PUZZWSTR = *mut WCHAR; +pub type PCUZZWSTR = *const WCHAR; +pub type PNZWCH = *mut WCHAR; +pub type PCNZWCH = *const WCHAR; +pub type PUNZWCH = *mut WCHAR; +pub type PCUNZWCH = *const WCHAR; +pub type PCHAR = *mut CHAR; +pub type LPCH = *mut CHAR; +pub type PCH = *mut CHAR; +pub type LPCCH = *const CHAR; +pub type PCCH = *const CHAR; +pub type NPSTR = *mut CHAR; +pub type LPSTR = *mut CHAR; +pub type PSTR = *mut CHAR; +pub type PZPSTR = *mut PSTR; +pub type PCZPSTR = *const PSTR; +pub type LPCSTR = *const CHAR; +pub type PCSTR = *const CHAR; +pub type PZPCSTR = *mut PCSTR; +pub type PCZPCSTR = *const PCSTR; +pub type PZZSTR = *mut CHAR; +pub type PCZZSTR = *const CHAR; +pub type PNZCH = *mut CHAR; +pub type PCNZCH = *const CHAR; +pub type TCHAR = ::std::os::raw::c_char; +pub type PTCHAR = *mut ::std::os::raw::c_char; +pub type TBYTE = ::std::os::raw::c_uchar; +pub type PTBYTE = *mut ::std::os::raw::c_uchar; +pub type LPTCH = LPCH; +pub type PTCH = LPCH; +pub type LPCTCH = LPCCH; +pub type PCTCH = LPCCH; +pub type PTSTR = LPSTR; +pub type LPTSTR = LPSTR; +pub type PUTSTR = LPSTR; +pub type LPUTSTR = LPSTR; +pub type PCTSTR = LPCSTR; +pub type LPCTSTR = LPCSTR; +pub type PCUTSTR = LPCSTR; +pub type LPCUTSTR = LPCSTR; +pub type PZZTSTR = PZZSTR; +pub type PUZZTSTR = PZZSTR; +pub type PCZZTSTR = PCZZSTR; +pub type PCUZZTSTR = PCZZSTR; +pub type PZPTSTR = PZPSTR; +pub type PNZTCH = PNZCH; +pub type PUNZTCH = PNZCH; +pub type PCNZTCH = PCNZCH; +pub type PCUNZTCH = PCNZCH; +pub type PSHORT = *mut SHORT; +pub type PLONG = *mut LONG; +pub type ULONG = ::std::os::raw::c_ulong; +pub type PULONG = *mut ULONG; +pub type USHORT = ::std::os::raw::c_ushort; +pub type PUSHORT = *mut USHORT; +pub type UCHAR = ::std::os::raw::c_uchar; +pub type PUCHAR = *mut UCHAR; +pub type PSZ = *mut ::std::os::raw::c_char; +pub type DWORD = ::std::os::raw::c_ulong; +pub type BOOL = ::std::os::raw::c_int; +pub type BYTE = ::std::os::raw::c_uchar; +pub type WORD = ::std::os::raw::c_ushort; +pub type FLOAT = f32; +pub type PFLOAT = *mut FLOAT; +pub type PBOOL = *mut BOOL; +pub type LPBOOL = *mut BOOL; +pub type PBYTE = *mut BYTE; +pub type LPBYTE = *mut BYTE; +pub type PINT = *mut ::std::os::raw::c_int; +pub type LPINT = *mut ::std::os::raw::c_int; +pub type PWORD = *mut WORD; +pub type LPWORD = *mut WORD; +pub type LPLONG = *mut ::std::os::raw::c_long; +pub type PDWORD = *mut DWORD; +pub type LPDWORD = *mut DWORD; +pub type LPVOID = *mut ::std::os::raw::c_void; +pub type LPCVOID = *const ::std::os::raw::c_void; +pub type INT = ::std::os::raw::c_int; +pub type UINT = ::std::os::raw::c_uint; +pub type PUINT = *mut ::std::os::raw::c_uint; +pub type va_list = *mut ::std::os::raw::c_char; + +pub const TRUE: ::std::os::raw::c_int = 1; +pub const FALSE: ::std::os::raw::c_int = 0; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_HEADER { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, +} +pub type CLIPRDR_HEADER = _CLIPRDR_HEADER; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_CAPABILITY_SET { + pub capabilitySetType: UINT16, + pub capabilitySetLength: UINT16, +} +pub type CLIPRDR_CAPABILITY_SET = _CLIPRDR_CAPABILITY_SET; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_GENERAL_CAPABILITY_SET { + pub capabilitySetType: UINT16, + pub capabilitySetLength: UINT16, + pub version: UINT32, + pub generalFlags: UINT32, +} +pub type CLIPRDR_GENERAL_CAPABILITY_SET = _CLIPRDR_GENERAL_CAPABILITY_SET; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_CAPABILITIES { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub cCapabilitiesSets: UINT32, + pub capabilitySets: *mut CLIPRDR_CAPABILITY_SET, +} +pub type CLIPRDR_CAPABILITIES = _CLIPRDR_CAPABILITIES; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_MONITOR_READY { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, +} +pub type CLIPRDR_MONITOR_READY = _CLIPRDR_MONITOR_READY; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_TEMP_DIRECTORY { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub szTempDir: [::std::os::raw::c_char; 520usize], +} +pub type CLIPRDR_TEMP_DIRECTORY = _CLIPRDR_TEMP_DIRECTORY; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FORMAT { + pub formatId: UINT32, + pub formatName: *mut ::std::os::raw::c_char, +} +pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FORMAT_LIST { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub numFormats: UINT32, + pub formats: *mut CLIPRDR_FORMAT, +} +pub type CLIPRDR_FORMAT_LIST = _CLIPRDR_FORMAT_LIST; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FORMAT_LIST_RESPONSE { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, +} +pub type CLIPRDR_FORMAT_LIST_RESPONSE = _CLIPRDR_FORMAT_LIST_RESPONSE; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_LOCK_CLIPBOARD_DATA { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub clipDataId: UINT32, +} +pub type CLIPRDR_LOCK_CLIPBOARD_DATA = _CLIPRDR_LOCK_CLIPBOARD_DATA; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub clipDataId: UINT32, +} +pub type CLIPRDR_UNLOCK_CLIPBOARD_DATA = _CLIPRDR_UNLOCK_CLIPBOARD_DATA; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FORMAT_DATA_REQUEST { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub requestedFormatId: UINT32, +} +pub type CLIPRDR_FORMAT_DATA_REQUEST = _CLIPRDR_FORMAT_DATA_REQUEST; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FORMAT_DATA_RESPONSE { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub requestedFormatData: *const BYTE, +} +pub type CLIPRDR_FORMAT_DATA_RESPONSE = _CLIPRDR_FORMAT_DATA_RESPONSE; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FILE_CONTENTS_REQUEST { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub streamId: UINT32, + pub listIndex: UINT32, + pub dwFlags: UINT32, + pub nPositionLow: UINT32, + pub nPositionHigh: UINT32, + pub cbRequested: UINT32, + pub haveClipDataId: BOOL, + pub clipDataId: UINT32, +} +pub type CLIPRDR_FILE_CONTENTS_REQUEST = _CLIPRDR_FILE_CONTENTS_REQUEST; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE { + pub connID: UINT32, + pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, + pub streamId: UINT32, + pub cbRequested: UINT32, + pub requestedData: *const BYTE, +} +pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE; +pub type CliprdrClientContext = _cliprdr_client_context; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _NOTIFICATION_MESSAGE { + pub r#type: UINT32, // 0 - info, 1 - warning, 2 - error + pub msg: *const BYTE, + pub details: *const BYTE, +} +pub type NOTIFICATION_MESSAGE = _NOTIFICATION_MESSAGE; +pub type pcCliprdrServerCapabilities = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + capabilities: *const CLIPRDR_CAPABILITIES, + ) -> UINT, +>; +pub type pcCliprdrClientCapabilities = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + capabilities: *const CLIPRDR_CAPABILITIES, + ) -> UINT, +>; +pub type pcCliprdrMonitorReady = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + monitorReady: *const CLIPRDR_MONITOR_READY, + ) -> UINT, +>; +pub type pcCliprdrTempDirectory = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + tempDirectory: *const CLIPRDR_TEMP_DIRECTORY, + ) -> UINT, +>; +pub type pcNotifyClipboardMsg = ::std::option::Option< + unsafe extern "C" fn(connID: UINT32, msg: *const NOTIFICATION_MESSAGE) -> UINT, +>; +pub type pcCliprdrClientFormatList = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatList: *const CLIPRDR_FORMAT_LIST, + ) -> UINT, +>; +pub type pcCliprdrServerFormatList = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatList: *const CLIPRDR_FORMAT_LIST, + ) -> UINT, +>; +pub type pcCliprdrClientFormatListResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE, + ) -> UINT, +>; +pub type pcCliprdrServerFormatListResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE, + ) -> UINT, +>; +pub type pcCliprdrClientLockClipboardData = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA, + ) -> UINT, +>; +pub type pcCliprdrServerLockClipboardData = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA, + ) -> UINT, +>; +pub type pcCliprdrClientUnlockClipboardData = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA, + ) -> UINT, +>; +pub type pcCliprdrServerUnlockClipboardData = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA, + ) -> UINT, +>; +pub type pcCliprdrClientFormatDataRequest = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST, + ) -> UINT, +>; +pub type pcCliprdrServerFormatDataRequest = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST, + ) -> UINT, +>; +pub type pcCliprdrClientFormatDataResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE, + ) -> UINT, +>; +pub type pcCliprdrServerFormatDataResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE, + ) -> UINT, +>; +pub type pcCliprdrClientFileContentsRequest = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST, + ) -> UINT, +>; +pub type pcCliprdrServerFileContentsRequest = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST, + ) -> UINT, +>; +pub type pcCliprdrClientFileContentsResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, + ) -> UINT, +>; +pub type pcCliprdrServerFileContentsResponse = ::std::option::Option< + unsafe extern "C" fn( + context: *mut CliprdrClientContext, + fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, + ) -> UINT, +>; + +// TODO: hide more members of clipboard context +#[repr(C)] +#[derive(Debug, Clone)] +pub struct _cliprdr_client_context { + pub Custom: *mut ::std::os::raw::c_void, + pub EnableFiles: BOOL, + pub EnableOthers: BOOL, + pub IsStopped: BOOL, + pub ResponseWaitTimeoutSecs: UINT32, + pub ServerCapabilities: pcCliprdrServerCapabilities, + pub ClientCapabilities: pcCliprdrClientCapabilities, + pub MonitorReady: pcCliprdrMonitorReady, + pub TempDirectory: pcCliprdrTempDirectory, + pub NotifyClipboardMsg: pcNotifyClipboardMsg, + pub ClientFormatList: pcCliprdrClientFormatList, + pub ServerFormatList: pcCliprdrServerFormatList, + pub ClientFormatListResponse: pcCliprdrClientFormatListResponse, + pub ServerFormatListResponse: pcCliprdrServerFormatListResponse, + pub ClientLockClipboardData: pcCliprdrClientLockClipboardData, + pub ServerLockClipboardData: pcCliprdrServerLockClipboardData, + pub ClientUnlockClipboardData: pcCliprdrClientUnlockClipboardData, + pub ServerUnlockClipboardData: pcCliprdrServerUnlockClipboardData, + pub ClientFormatDataRequest: pcCliprdrClientFormatDataRequest, + pub ServerFormatDataRequest: pcCliprdrServerFormatDataRequest, + pub ClientFormatDataResponse: pcCliprdrClientFormatDataResponse, + pub ServerFormatDataResponse: pcCliprdrServerFormatDataResponse, + pub ClientFileContentsRequest: pcCliprdrClientFileContentsRequest, + pub ServerFileContentsRequest: pcCliprdrServerFileContentsRequest, + pub ClientFileContentsResponse: pcCliprdrClientFileContentsResponse, + pub ServerFileContentsResponse: pcCliprdrServerFileContentsResponse, + pub LastRequestedFormatId: UINT32, +} + +// #[link(name = "user32")] +// #[link(name = "ole32")] +extern "C" { + pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL; + pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL; + pub(crate) fn empty_cliprdr(context: *mut CliprdrClientContext, connID: UINT32) -> BOOL; +} + +unsafe impl Send for CliprdrClientContext {} + +unsafe impl Sync for CliprdrClientContext {} + +impl CliprdrClientContext { + pub fn create( + enable_files: bool, + enable_others: bool, + response_wait_timeout_secs: u32, + notify_callback: pcNotifyClipboardMsg, + client_format_list: pcCliprdrClientFormatList, + client_format_list_response: pcCliprdrClientFormatListResponse, + client_format_data_request: pcCliprdrClientFormatDataRequest, + client_format_data_response: pcCliprdrClientFormatDataResponse, + client_file_contents_request: pcCliprdrClientFileContentsRequest, + client_file_contents_response: pcCliprdrClientFileContentsResponse, + ) -> Result, CliprdrError> { + let context = CliprdrClientContext { + Custom: 0 as *mut _, + EnableFiles: if enable_files { TRUE } else { FALSE }, + EnableOthers: if enable_others { TRUE } else { FALSE }, + IsStopped: FALSE, + ResponseWaitTimeoutSecs: response_wait_timeout_secs, + ServerCapabilities: None, + ClientCapabilities: None, + MonitorReady: None, + TempDirectory: None, + NotifyClipboardMsg: notify_callback, + ClientFormatList: client_format_list, + ServerFormatList: None, + ClientFormatListResponse: client_format_list_response, + ServerFormatListResponse: None, + ClientLockClipboardData: None, + ServerLockClipboardData: None, + ClientUnlockClipboardData: None, + ServerUnlockClipboardData: None, + ClientFormatDataRequest: client_format_data_request, + ServerFormatDataRequest: None, + ClientFormatDataResponse: client_format_data_response, + ServerFormatDataResponse: None, + ClientFileContentsRequest: client_file_contents_request, + ServerFileContentsRequest: None, + ClientFileContentsResponse: client_file_contents_response, + ServerFileContentsResponse: None, + LastRequestedFormatId: 0, + }; + let mut context = Box::new(context); + unsafe { + if FALSE == init_cliprdr(&mut (*context)) { + println!("Failed to init cliprdr"); + Err(CliprdrError::CliprdrInit) + } else { + Ok(context) + } + } + } +} + +impl Drop for CliprdrClientContext { + fn drop(&mut self) { + unsafe { + if FALSE == uninit_cliprdr(&mut *self) { + println!("Failed to uninit cliprdr"); + } else { + println!("Succeeded to uninit cliprdr"); + } + } + } +} + +impl CliprdrServiceContext for CliprdrClientContext { + fn set_is_stopped(&mut self) -> Result<(), CliprdrError> { + self.IsStopped = TRUE; + Ok(()) + } + + fn empty_clipboard(&mut self, conn_id: i32) -> bool { + empty_clipboard(self, conn_id) + } + + fn server_clip_file(&mut self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError> { + let ret = server_clip_file(self, conn_id, msg); + ret_to_result(ret) + } +} + +fn ret_to_result(ret: u32) -> Result<(), CliprdrError> { + match ret { + #[allow(unreachable_patterns)] + // CHANNEL_RC_OK is unreachable, but ignore it + ERROR_SUCCESS | CHANNEL_RC_OK => Ok(()), + CHANNEL_RC_NO_MEMORY => Err(CliprdrError::CliprdrOutOfMemory), + ERROR_INTERNAL_ERROR => Err(CliprdrError::ClipboardInternalError), + e => Err(CliprdrError::Unknown(e)), + } +} + +fn empty_clipboard(context: &mut CliprdrClientContext, conn_id: i32) -> bool { + unsafe { TRUE == empty_cliprdr(context, conn_id as u32) } +} + +fn server_clip_file(context: &mut CliprdrClientContext, conn_id: i32, msg: ClipboardFile) -> u32 { + let mut ret = 0; + match msg { + ClipboardFile::NotifyCallback { .. } => { + // unreachable + } + ClipboardFile::MonitorReady => { + log::debug!("server_monitor_ready called"); + ret = server_monitor_ready(context, conn_id); + log::debug!( + "server_monitor_ready called, conn_id {}, return {}", + conn_id, + ret + ); + } + ClipboardFile::FormatList { format_list } => { + log::debug!( + "server_format_list called, conn_id {}, format_list: {:?}", + conn_id, + &format_list + ); + ret = server_format_list(context, conn_id, format_list); + log::debug!( + "server_format_list called, conn_id {}, return {}", + conn_id, + ret + ); + } + ClipboardFile::FormatListResponse { msg_flags } => { + log::debug!("server_format_list_response called"); + ret = server_format_list_response(context, conn_id, msg_flags); + log::debug!( + "server_format_list_response called, conn_id {}, msg_flags {}, return {}", + conn_id, + msg_flags, + ret + ); + } + ClipboardFile::FormatDataRequest { + requested_format_id, + } => { + log::debug!("server_format_data_request called"); + ret = server_format_data_request(context, conn_id, requested_format_id); + log::debug!( + "server_format_data_request called, conn_id {}, requested_format_id {}, return {}", + conn_id, + requested_format_id, + ret + ); + } + ClipboardFile::FormatDataResponse { + msg_flags, + format_data, + } => { + log::debug!("server_format_data_response called"); + ret = server_format_data_response(context, conn_id, msg_flags, format_data); + log::debug!( + "server_format_data_response called, conn_id {}, msg_flags: {}, return {}", + conn_id, + msg_flags, + ret + ); + } + ClipboardFile::FileContentsRequest { + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + } => { + log::debug!("server_file_contents_request called"); + ret = server_file_contents_request( + context, + conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ); + log::debug!("server_file_contents_request called, conn_id {}, stream_id: {}, list_index {}, dw_flags {}, n_position_low {}, n_position_high {}, cb_requested {}, have_clip_data_id {}, clip_data_id {}, return {}", conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ret + ); + } + ClipboardFile::FileContentsResponse { + msg_flags, + stream_id, + requested_data, + } => { + log::debug!("server_file_contents_response called"); + ret = server_file_contents_response( + context, + conn_id, + msg_flags, + stream_id, + requested_data, + ); + log::debug!("server_file_contents_response called, conn_id {}, msg_flags {}, stream_id {}, return {}", + conn_id, + msg_flags, + stream_id, + ret + ); + } + } + ret +} + +fn server_monitor_ready(context: &mut CliprdrClientContext, conn_id: i32) -> u32 { + unsafe { + let monitor_ready = CLIPRDR_MONITOR_READY { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + }; + if let Some(f) = context.MonitorReady { + let ret = f(context, &monitor_ready); + ret as u32 + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +fn server_format_list( + context: &mut CliprdrClientContext, + conn_id: i32, + format_list: Vec<(i32, String)>, +) -> u32 { + unsafe { + let num_formats = format_list.len() as UINT32; + let mut formats = format_list + .into_iter() + .map(|format| { + if format.1.is_empty() { + CLIPRDR_FORMAT { + formatId: format.0 as UINT32, + formatName: 0 as *mut _, + } + } else { + let n = match CString::new(format.1) { + Ok(n) => n, + Err(_) => CString::new("").unwrap(), + }; + CLIPRDR_FORMAT { + formatId: format.0 as UINT32, + formatName: n.into_raw(), + } + } + }) + .collect::>(); + + let format_list = CLIPRDR_FORMAT_LIST { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + numFormats: num_formats, + formats: formats.as_mut_ptr(), + }; + + let ret = if let Some(f) = context.ServerFormatList { + f(context, &format_list) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + }; + + for f in formats { + if !f.formatName.is_null() { + // retake pointer to free memory + let _ = CString::from_raw(f.formatName); + } + } + + ret as u32 + } +} + +fn server_format_list_response( + context: &mut CliprdrClientContext, + conn_id: i32, + msg_flags: i32, +) -> u32 { + unsafe { + let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: msg_flags as UINT16, + dataLen: 0 as UINT32, + }; + + if let Some(f) = context.ServerFormatListResponse { + f(context, &format_list_response) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +fn server_format_data_request( + context: &mut CliprdrClientContext, + conn_id: i32, + requested_format_id: i32, +) -> u32 { + unsafe { + let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + requestedFormatId: requested_format_id as UINT32, + }; + if let Some(f) = context.ServerFormatDataRequest { + f(context, &format_data_request) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +fn server_format_data_response( + context: &mut CliprdrClientContext, + conn_id: i32, + msg_flags: i32, + mut format_data: Vec, +) -> u32 { + unsafe { + let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: msg_flags as UINT16, + dataLen: format_data.len() as UINT32, + requestedFormatData: format_data.as_mut_ptr(), + }; + if let Some(f) = context.ServerFormatDataResponse { + f(context, &format_data_response) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +fn server_file_contents_request( + context: &mut CliprdrClientContext, + conn_id: i32, + stream_id: i32, + list_index: i32, + dw_flags: i32, + n_position_low: i32, + n_position_high: i32, + cb_requested: i32, + have_clip_data_id: bool, + clip_data_id: i32, +) -> u32 { + unsafe { + let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + streamId: stream_id as UINT32, + listIndex: list_index as UINT32, + dwFlags: dw_flags as UINT32, + nPositionLow: n_position_low as UINT32, + nPositionHigh: n_position_high as UINT32, + cbRequested: cb_requested as UINT32, + haveClipDataId: if have_clip_data_id { TRUE } else { FALSE }, + clipDataId: clip_data_id as UINT32, + }; + if let Some(f) = context.ServerFileContentsRequest { + f(context, &file_contents_request) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +fn server_file_contents_response( + context: &mut CliprdrClientContext, + conn_id: i32, + msg_flags: i32, + stream_id: i32, + mut requested_data: Vec, +) -> u32 { + unsafe { + let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: msg_flags as UINT16, + dataLen: 4 + requested_data.len() as UINT32, + streamId: stream_id as UINT32, + cbRequested: requested_data.len() as UINT32, + requestedData: requested_data.as_mut_ptr(), + }; + if let Some(f) = context.ServerFileContentsResponse { + f(context, &file_contents_response) + } else { + ERR_CODE_SERVER_FUNCTION_NONE + } + } +} + +pub(super) fn create_cliprdr_context( + enable_files: bool, + enable_others: bool, + response_wait_timeout_secs: u32, +) -> ResultType> { + let boxed = CliprdrClientContext::create( + enable_files, + enable_others, + response_wait_timeout_secs, + Some(notify_callback), + Some(client_format_list), + Some(client_format_list_response), + Some(client_format_data_request), + Some(client_format_data_response), + Some(client_file_contents_request), + Some(client_file_contents_response), + )? as Box; + + Ok(boxed) +} + +extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE) -> UINT { + log::debug!("notify_callback called"); + let data = unsafe { + let msg = &*msg; + let details = if msg.details.is_null() { + Ok("") + } else { + CStr::from_ptr(msg.details as _).to_str() + }; + match (CStr::from_ptr(msg.msg as _).to_str(), details) { + (Ok(m), Ok(d)) => { + let msgtype = format!( + "custom-{}-nocancel-nook-hasclose", + if msg.r#type == 0 { + "info" + } else if msg.r#type == 1 { + "warn" + } else { + "error" + } + ); + let title = "Clipboard"; + let text = if d.is_empty() { + m.to_string() + } else { + format!("{} {}", m, d) + }; + ClipboardFile::NotifyCallback { + r#type: msgtype, + title: title.to_string(), + text, + } + } + _ => { + log::error!("notify_callback: failed to convert msg"); + return ERR_CODE_INVALID_PARAMETER; + } + } + }; + // no need to handle result here + send_data(conn_id as _, data); + + 0 +} + +extern "C" fn client_format_list( + _context: *mut CliprdrClientContext, + clip_format_list: *const CLIPRDR_FORMAT_LIST, +) -> UINT { + let conn_id; + let mut format_list: Vec<(i32, String)> = Vec::new(); + unsafe { + let mut i = 0u32; + while i < (*clip_format_list).numFormats { + let format_data = &(*(*clip_format_list).formats.offset(i as isize)); + if format_data.formatName.is_null() { + format_list.push((format_data.formatId as i32, "".to_owned())); + } else { + let format_name = CStr::from_ptr(format_data.formatName).to_str(); + let format_name = match format_name { + Ok(n) => n.to_owned(), + Err(_) => { + log::warn!("failed to get format name"); + "".to_owned() + } + }; + format_list.push((format_data.formatId as i32, format_name)); + } + // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); + i += 1; + } + conn_id = (*clip_format_list).connID as i32; + } + log::debug!( + "client_format_list called, client id: {}, format_list: {:?}", + conn_id, + &format_list + ); + let data = ClipboardFile::FormatList { format_list }; + // no need to handle result here + if conn_id == 0 { + // msg_channel is used for debug, VEC_MSG_CHANNEL cannot be inspected by the debugger. + let msg_channel = VEC_MSG_CHANNEL.read().unwrap(); + msg_channel + .iter() + .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); + } else { + send_data(conn_id, data); + } + + 0 +} + +extern "C" fn client_format_list_response( + _context: *mut CliprdrClientContext, + format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE, +) -> UINT { + let conn_id; + let msg_flags; + unsafe { + conn_id = (*format_list_response).connID as i32; + msg_flags = (*format_list_response).msgFlags as i32; + } + log::debug!( + "client_format_list_response called, client id: {}, msg_flags: {}", + conn_id, + msg_flags + ); + let data = ClipboardFile::FormatListResponse { msg_flags }; + send_data(conn_id, data); + + 0 +} + +extern "C" fn client_format_data_request( + _context: *mut CliprdrClientContext, + format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST, +) -> UINT { + let conn_id; + let requested_format_id; + unsafe { + conn_id = (*format_data_request).connID as i32; + requested_format_id = (*format_data_request).requestedFormatId as i32; + } + let data = ClipboardFile::FormatDataRequest { + requested_format_id, + }; + log::debug!( + "client_format_data_request called, conn_id: {}, requested_format_id: {}", + conn_id, + requested_format_id + ); + // no need to handle result here + send_data(conn_id, data); + + 0 +} + +extern "C" fn client_format_data_response( + _context: *mut CliprdrClientContext, + format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE, +) -> UINT { + let conn_id; + let msg_flags; + let format_data; + unsafe { + conn_id = (*format_data_response).connID as i32; + msg_flags = (*format_data_response).msgFlags as i32; + if (*format_data_response).requestedFormatData.is_null() { + format_data = Vec::new(); + } else { + format_data = std::slice::from_raw_parts( + (*format_data_response).requestedFormatData, + (*format_data_response).dataLen as usize, + ) + .to_vec(); + } + } + log::debug!( + "client_format_data_response called, client id: {}, msg_flags: {}", + conn_id, + msg_flags + ); + let data = ClipboardFile::FormatDataResponse { + msg_flags, + format_data, + }; + send_data(conn_id, data); + + 0 +} + +extern "C" fn client_file_contents_request( + _context: *mut CliprdrClientContext, + file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST, +) -> UINT { + // TODO: support huge file? + // if (!cliprdr->hasHugeFileSupport) + // { + // if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) > + // UINT32_MAX) + // return ERROR_INVALID_PARAMETER; + // if (fileContentsRequest->nPositionHigh != 0) + // return ERROR_INVALID_PARAMETER; + // } + + let conn_id; + let stream_id; + let list_index; + let dw_flags; + let n_position_low; + let n_position_high; + let cb_requested; + let have_clip_data_id; + let clip_data_id; + unsafe { + conn_id = (*file_contents_request).connID as i32; + stream_id = (*file_contents_request).streamId as i32; + list_index = (*file_contents_request).listIndex as i32; + dw_flags = (*file_contents_request).dwFlags as i32; + n_position_low = (*file_contents_request).nPositionLow as i32; + n_position_high = (*file_contents_request).nPositionHigh as i32; + cb_requested = (*file_contents_request).cbRequested as i32; + have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; + clip_data_id = (*file_contents_request).clipDataId as i32; + } + let data = ClipboardFile::FileContentsRequest { + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + }; + log::debug!("client_file_contents_request called, data: {:?}", &data); + send_data(conn_id, data); + + 0 +} + +extern "C" fn client_file_contents_response( + _context: *mut CliprdrClientContext, + file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE, +) -> UINT { + let conn_id; + let msg_flags; + let stream_id; + let requested_data; + unsafe { + conn_id = (*file_contents_response).connID as i32; + msg_flags = (*file_contents_response).msgFlags as i32; + stream_id = (*file_contents_response).streamId as i32; + if (*file_contents_response).requestedData.is_null() { + requested_data = Vec::new(); + } else { + requested_data = std::slice::from_raw_parts( + (*file_contents_response).requestedData, + (*file_contents_response).cbRequested as usize, + ) + .to_vec(); + } + } + let data = ClipboardFile::FileContentsResponse { + msg_flags, + stream_id, + requested_data, + }; + log::debug!( + "client_file_contents_response called, conn_id: {}, msg_flags: {}, stream_id: {}", + conn_id, + msg_flags, + stream_id + ); + send_data(conn_id, data); + + 0 +} diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 801fa71f3..c8f2038a1 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -1367,6 +1367,11 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) if (!clipboard) return ERROR_INTERNAL_ERROR; + if (!IsClipboardFormatAvailable(CF_HDROP)) + { + return ERROR_SUCCESS; + } + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); /* Ignore if other app is holding clipboard */ @@ -1392,21 +1397,11 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) } index = 0; - - if (IsClipboardFormatAvailable(CF_HDROP)) - { - UINT fsid = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); - UINT fcid = RegisterClipboardFormat(CFSTR_FILECONTENTS); - - formats[index++].formatId = fsid; - formats[index++].formatId = fcid; - } - else - { - while (formatId = EnumClipboardFormats(formatId) && index < numFormats) - formats[index++].formatId = formatId; - } - + // IsClipboardFormatAvailable(CF_HDROP) is checked above + UINT fsid = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); + UINT fcid = RegisterClipboardFormat(CFSTR_FILECONTENTS); + formats[index++].formatId = fsid; + formats[index++].formatId = fcid; numFormats = index; if (!CloseClipboard()) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index ff1387dd0..ab47f5698 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -6,7 +6,7 @@ use std::sync::{ }; #[cfg(windows)] -use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend}; +use clipboard::ContextSend; use crossbeam_queue::ArrayQueue; use hbb_common::config::{PeerConfig, TransferSerde}; use hbb_common::fs::{ @@ -27,7 +27,7 @@ use hbb_common::tokio::{ sync::mpsc, time::{self, Duration, Instant, Interval}, }; -use hbb_common::{allow_err, fs, get_time, log, message_proto::*, Stream}; +use hbb_common::{allow_err, fs, get_time, log, message_proto::*, ResultType, Stream}; use scrap::CodecFormat; use crate::client::{ @@ -281,9 +281,9 @@ impl Remote { #[cfg(windows)] { let conn_id = self.client_conn_id; - ContextSend::proc(|context: &mut Box| -> u32 { - empty_clipboard(context, conn_id); - 0 + let _ = ContextSend::proc(|context| -> ResultType<()> { + context.empty_clipboard(conn_id); + Ok(()) }); } } @@ -1578,8 +1578,10 @@ impl Remote { "Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, file_transfer_enabled); if !stop { - ContextSend::proc(|context: &mut Box| -> u32 { - clipboard::server_clip_file(context, self.client_conn_id, clip) + let _ = ContextSend::proc(|context| -> ResultType<()> { + context + .server_clip_file(self.client_conn_id, clip) + .map_err(|e| e.into()) }); } } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index e5a5c8e3b..2acf76eff 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -16,7 +16,7 @@ use crate::ipc::Connection; #[cfg(not(any(target_os = "ios")))] use crate::ipc::{self, Data}; #[cfg(windows)] -use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend}; +use clipboard::ContextSend; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::tokio::sync::mpsc::unbounded_channel; #[cfg(windows)] @@ -34,6 +34,7 @@ use hbb_common::{ sync::mpsc::{self, UnboundedSender}, task::spawn_blocking, }, + ResultType, }; use serde_derive::Serialize; @@ -175,9 +176,9 @@ impl ConnectionManager { #[cfg(windows)] { - ContextSend::proc(|context: &mut Box| -> u32 { - empty_clipboard(context, id); - 0 + let _ = ContextSend::proc(|context| -> ResultType<()> { + context.empty_clipboard(id); + Ok(()) }); } @@ -414,8 +415,9 @@ impl IpcTaskRunner { ContextSend::set_is_stopped(); } else { let conn_id = self.conn_id; - ContextSend::proc(|context: &mut Box| -> u32 { - clipboard::server_clip_file(context, conn_id, _clip) + let _ = ContextSend::proc(|context| -> ResultType<()> { + context.server_clip_file(conn_id, _clip) + .map_err(|e| e.into()) }); } }