mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
15
libs/clipboard/Cargo.toml
Normal file
15
libs/clipboard/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "clipboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.30"
|
||||
lazy_static = "1.4"
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
16
libs/clipboard/README.md
Normal file
16
libs/clipboard/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# clipboard
|
||||
|
||||
Copy files and text through network.
|
||||
Main lowlevel logic from [FreeRDP](https://github.com/FreeRDP/FreeRDP).
|
||||
|
||||
TODO: Move this lib to a separate project.
|
||||
|
||||
## impl
|
||||
|
||||
### windows
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
43
libs/clipboard/build.rs
Normal file
43
libs/clipboard/build.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use cc;
|
||||
|
||||
fn build_c_impl() {
|
||||
let mut build = cc::Build::new();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
build.file("src/windows/wf_cliprdr.c");
|
||||
#[cfg(target_os = "linux")]
|
||||
build.file("src/X11/xf_cliprdr.c");
|
||||
#[cfg(target_os = "macos")]
|
||||
build.file("src/OSX/Clipboard.m");
|
||||
|
||||
build.flag_if_supported("-Wno-c++0x-extensions");
|
||||
build.flag_if_supported("-Wno-return-type-c-linkage");
|
||||
build.flag_if_supported("-Wno-invalid-offsetof");
|
||||
build.flag_if_supported("-Wno-unused-parameter");
|
||||
|
||||
if build.get_compiler().is_like_msvc() {
|
||||
build.define("WIN32", "");
|
||||
// build.define("_AMD64_", "");
|
||||
build.flag("-Zi");
|
||||
build.flag("-GR-");
|
||||
// build.flag("-std:c++11");
|
||||
} else {
|
||||
build.flag("-fPIC");
|
||||
// build.flag("-std=c++11");
|
||||
// build.flag("-include");
|
||||
// build.flag(&confdefs_path.to_string_lossy());
|
||||
}
|
||||
|
||||
build.compile("mycliprdr");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
|
||||
#[cfg(target_os = "linux")]
|
||||
println!("cargo:rerun-if-changed=src/X11/xf_cliprdr.c");
|
||||
#[cfg(target_os = "macos")]
|
||||
println!("cargo:rerun-if-changed=src/OSX/Clipboard.m");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
build_c_impl();
|
||||
}
|
||||
BIN
libs/clipboard/docs/assets/scene3.png
Normal file
BIN
libs/clipboard/docs/assets/scene3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
BIN
libs/clipboard/docs/assets/win_A_B.png
Normal file
BIN
libs/clipboard/docs/assets/win_A_B.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
libs/clipboard/docs/assets/win_B_A.png
Normal file
BIN
libs/clipboard/docs/assets/win_B_A.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
11
libs/clipboard/src/OSX/Clipboard.m
Normal file
11
libs/clipboard/src/OSX/Clipboard.m
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../cliprdr.h"
|
||||
|
||||
void mac_cliprdr_init(CliprdrClientContext *cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
|
||||
void mac_cliprdr_uninit(CliprdrClientContext *cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
11
libs/clipboard/src/X11/xf_cliprdr.c
Normal file
11
libs/clipboard/src/X11/xf_cliprdr.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../cliprdr.h"
|
||||
|
||||
void xf_cliprdr_init(CliprdrClientContext* cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
|
||||
void xf_cliprdr_uninit( CliprdrClientContext* cliprdr)
|
||||
{
|
||||
(void)cliprdr;
|
||||
}
|
||||
231
libs/clipboard/src/cliprdr.h
Normal file
231
libs/clipboard/src/cliprdr.h
Normal file
@@ -0,0 +1,231 @@
|
||||
#ifndef WF_CLIPRDR_H__
|
||||
#define WF_CLIPRDR_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef signed char INT8, *PINT8;
|
||||
typedef signed short INT16, *PINT16;
|
||||
typedef signed int INT32, *PINT32;
|
||||
typedef unsigned char UINT8, *PUINT8;
|
||||
typedef unsigned short UINT16, *PUINT16;
|
||||
typedef unsigned int UINT32, *PUINT32;
|
||||
typedef unsigned int UINT;
|
||||
typedef int BOOL;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* Clipboard Messages */
|
||||
#define DEFINE_CLIPRDR_HEADER_COMMON() \
|
||||
UINT32 serverConnID; \
|
||||
UINT32 remoteConnID; \
|
||||
UINT16 msgType; \
|
||||
UINT16 msgFlags; \
|
||||
UINT32 dataLen
|
||||
|
||||
struct _CLIPRDR_HEADER
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
|
||||
|
||||
struct _CLIPRDR_CAPABILITY_SET
|
||||
{
|
||||
UINT16 capabilitySetType;
|
||||
UINT16 capabilitySetLength;
|
||||
};
|
||||
typedef struct _CLIPRDR_CAPABILITY_SET CLIPRDR_CAPABILITY_SET;
|
||||
|
||||
struct _CLIPRDR_GENERAL_CAPABILITY_SET
|
||||
{
|
||||
UINT16 capabilitySetType;
|
||||
UINT16 capabilitySetLength;
|
||||
|
||||
UINT32 version;
|
||||
UINT32 generalFlags;
|
||||
};
|
||||
typedef struct _CLIPRDR_GENERAL_CAPABILITY_SET CLIPRDR_GENERAL_CAPABILITY_SET;
|
||||
|
||||
struct _CLIPRDR_CAPABILITIES
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 cCapabilitiesSets;
|
||||
CLIPRDR_CAPABILITY_SET *capabilitySets;
|
||||
};
|
||||
typedef struct _CLIPRDR_CAPABILITIES CLIPRDR_CAPABILITIES;
|
||||
|
||||
struct _CLIPRDR_MONITOR_READY
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY;
|
||||
|
||||
struct _CLIPRDR_TEMP_DIRECTORY
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
char szTempDir[520];
|
||||
};
|
||||
typedef struct _CLIPRDR_TEMP_DIRECTORY CLIPRDR_TEMP_DIRECTORY;
|
||||
|
||||
struct _CLIPRDR_FORMAT
|
||||
{
|
||||
UINT32 formatId;
|
||||
char *formatName;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT CLIPRDR_FORMAT;
|
||||
|
||||
struct _CLIPRDR_FORMAT_LIST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 numFormats;
|
||||
CLIPRDR_FORMAT *formats;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST;
|
||||
|
||||
struct _CLIPRDR_FORMAT_LIST_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE;
|
||||
|
||||
struct _CLIPRDR_LOCK_CLIPBOARD_DATA
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_LOCK_CLIPBOARD_DATA CLIPRDR_LOCK_CLIPBOARD_DATA;
|
||||
|
||||
struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA CLIPRDR_UNLOCK_CLIPBOARD_DATA;
|
||||
|
||||
struct _CLIPRDR_FORMAT_DATA_REQUEST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 requestedFormatId;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_DATA_REQUEST CLIPRDR_FORMAT_DATA_REQUEST;
|
||||
|
||||
struct _CLIPRDR_FORMAT_DATA_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
const BYTE *requestedFormatData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
|
||||
|
||||
struct _CLIPRDR_FILE_CONTENTS_REQUEST
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 streamId;
|
||||
UINT32 listIndex;
|
||||
UINT32 dwFlags;
|
||||
UINT32 nPositionLow;
|
||||
UINT32 nPositionHigh;
|
||||
UINT32 cbRequested;
|
||||
BOOL haveClipDataId;
|
||||
UINT32 clipDataId;
|
||||
};
|
||||
typedef struct _CLIPRDR_FILE_CONTENTS_REQUEST CLIPRDR_FILE_CONTENTS_REQUEST;
|
||||
|
||||
struct _CLIPRDR_FILE_CONTENTS_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
UINT32 streamId;
|
||||
UINT32 cbRequested;
|
||||
const BYTE *requestedData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE;
|
||||
|
||||
typedef struct _cliprdr_client_context CliprdrClientContext;
|
||||
|
||||
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context,
|
||||
const CLIPRDR_CAPABILITIES *capabilities);
|
||||
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context,
|
||||
const CLIPRDR_CAPABILITIES *capabilities);
|
||||
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext *context,
|
||||
const CLIPRDR_MONITOR_READY *monitorReady);
|
||||
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context,
|
||||
const CLIPRDR_TEMP_DIRECTORY *tempDirectory);
|
||||
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context,
|
||||
const CLIPRDR_FORMAT_LIST *formatList);
|
||||
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context,
|
||||
const CLIPRDR_FORMAT_LIST *formatList);
|
||||
typedef UINT (*pcCliprdrClientFormatListResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatListResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
|
||||
typedef UINT (*pcCliprdrClientLockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerLockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientUnlockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerUnlockClipboardData)(
|
||||
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientFormatDataRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
|
||||
typedef UINT (*pcCliprdrServerFormatDataRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
|
||||
typedef UINT (*pcCliprdrClientFormatDataResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatDataResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
|
||||
typedef UINT (*pcCliprdrClientFileContentsRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrServerFileContentsRequest)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrClientFileContentsResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
|
||||
typedef UINT (*pcCliprdrServerFileContentsResponse)(
|
||||
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
|
||||
|
||||
// TODO: hide more members of clipboard context
|
||||
struct _cliprdr_client_context
|
||||
{
|
||||
void *custom;
|
||||
BOOL enableFiles;
|
||||
BOOL enableOthers;
|
||||
|
||||
pcCliprdrServerCapabilities ServerCapabilities;
|
||||
pcCliprdrClientCapabilities ClientCapabilities;
|
||||
pcCliprdrMonitorReady MonitorReady;
|
||||
pcCliprdrTempDirectory TempDirectory;
|
||||
pcCliprdrClientFormatList ClientFormatList;
|
||||
pcCliprdrServerFormatList ServerFormatList;
|
||||
pcCliprdrClientFormatListResponse ClientFormatListResponse;
|
||||
pcCliprdrServerFormatListResponse ServerFormatListResponse;
|
||||
pcCliprdrClientLockClipboardData ClientLockClipboardData;
|
||||
pcCliprdrServerLockClipboardData ServerLockClipboardData;
|
||||
pcCliprdrClientUnlockClipboardData ClientUnlockClipboardData;
|
||||
pcCliprdrServerUnlockClipboardData ServerUnlockClipboardData;
|
||||
pcCliprdrClientFormatDataRequest ClientFormatDataRequest;
|
||||
pcCliprdrServerFormatDataRequest ServerFormatDataRequest;
|
||||
pcCliprdrClientFormatDataResponse ClientFormatDataResponse;
|
||||
pcCliprdrServerFormatDataResponse ServerFormatDataResponse;
|
||||
pcCliprdrClientFileContentsRequest ClientFileContentsRequest;
|
||||
pcCliprdrServerFileContentsRequest ServerFileContentsRequest;
|
||||
pcCliprdrClientFileContentsResponse ClientFileContentsResponse;
|
||||
pcCliprdrServerFileContentsResponse ServerFileContentsResponse;
|
||||
|
||||
UINT32 lastRequestedFormatId;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WF_CLIPRDR_H__
|
||||
|
||||
566
libs/clipboard/src/cliprdr.rs
Normal file
566
libs/clipboard/src/cliprdr.rs
Normal file
@@ -0,0 +1,566 @@
|
||||
#![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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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 serverConnID: UINT32,
|
||||
pub remoteConnID: 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;
|
||||
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 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 ServerCapabilities: pcCliprdrServerCapabilities,
|
||||
pub ClientCapabilities: pcCliprdrClientCapabilities,
|
||||
pub MonitorReady: pcCliprdrMonitorReady,
|
||||
pub TempDirectory: pcCliprdrTempDirectory,
|
||||
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;
|
||||
}
|
||||
|
||||
#[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,
|
||||
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<Box<Self>, CliprdrError> {
|
||||
let context = CliprdrClientContext {
|
||||
custom: 0 as *mut _,
|
||||
enableFiles: if enable_files { TRUE } else { FALSE },
|
||||
enableOthers: if enable_others { TRUE } else { FALSE },
|
||||
ServerCapabilities: None,
|
||||
ClientCapabilities: None,
|
||||
MonitorReady: None,
|
||||
TempDirectory: None,
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
548
libs/clipboard/src/lib.rs
Normal file
548
libs/clipboard/src/lib.rs
Normal file
@@ -0,0 +1,548 @@
|
||||
use cliprdr::*;
|
||||
use hbb_common::{
|
||||
log,
|
||||
message_proto::cliprdr as msg_cliprdr,
|
||||
message_proto::*,
|
||||
tokio::sync::{
|
||||
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
Mutex as TokioMutex,
|
||||
},
|
||||
ResultType,
|
||||
};
|
||||
use std::{
|
||||
boxed::Box,
|
||||
ffi::{CStr, CString},
|
||||
};
|
||||
|
||||
pub mod cliprdr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConnID {
|
||||
pub server_conn_id: u32,
|
||||
pub remote_conn_id: u32,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, Message)>, TokioMutex<UnboundedReceiver<(ConnID, Message)>>) = {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
(tx, TokioMutex::new(rx))
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_rx_client_msg<'a>() -> &'a TokioMutex<UnboundedReceiver<(ConnID, Message)>> {
|
||||
&MSG_CHANNEL_CLIENT.1
|
||||
}
|
||||
|
||||
pub fn server_msg(context: &mut Box<CliprdrClientContext>, conn_id: ConnID, msg: Cliprdr) -> u32 {
|
||||
match msg.union {
|
||||
Some(msg_cliprdr::Union::ready(_)) => {
|
||||
// proc ready
|
||||
0
|
||||
}
|
||||
Some(msg_cliprdr::Union::format_list(req)) => {
|
||||
log::debug!("server_format_list called");
|
||||
let ret = server_format_list(context, conn_id, req);
|
||||
log::debug!("server_format_list called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
Some(msg_cliprdr::Union::format_list_response(req)) => {
|
||||
log::debug!("format_list_response called");
|
||||
let ret = server_format_list_response(context, conn_id, req);
|
||||
log::debug!("server_format_list_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
Some(msg_cliprdr::Union::format_data_request(req)) => {
|
||||
log::debug!("format_data_request called");
|
||||
let ret = server_format_data_request(context, conn_id, req);
|
||||
log::debug!("server_format_data_request called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
Some(msg_cliprdr::Union::format_data_response(req)) => {
|
||||
log::debug!("format_data_response called");
|
||||
let ret = server_format_data_response(context, conn_id, req);
|
||||
log::debug!("server_format_data_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
Some(msg_cliprdr::Union::file_contents_request(req)) => {
|
||||
log::debug!("file_contents_request called");
|
||||
let ret = server_file_contents_request(context, conn_id, req);
|
||||
log::debug!("server_file_contents_request called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
Some(msg_cliprdr::Union::file_contents_response(req)) => {
|
||||
log::debug!("file_contents_response called");
|
||||
let ret = server_file_contents_response(context, conn_id, req);
|
||||
log::debug!("server_file_contents_response called, return {}", ret);
|
||||
ret
|
||||
}
|
||||
None => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn server_format_list(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
data: CliprdrServerFormatList,
|
||||
) -> u32 {
|
||||
// do not check msgFlags for now
|
||||
unsafe {
|
||||
let num_formats = data.formats.len() as UINT32;
|
||||
let mut formats = data
|
||||
.formats
|
||||
.into_iter()
|
||||
.map(|format| {
|
||||
if format.format.is_empty() {
|
||||
CLIPRDR_FORMAT {
|
||||
formatId: format.id as UINT32,
|
||||
formatName: 0 as *mut _,
|
||||
}
|
||||
} else {
|
||||
let n = match CString::new(format.format) {
|
||||
Ok(n) => n,
|
||||
Err(_) => CString::new("").unwrap(),
|
||||
};
|
||||
CLIPRDR_FORMAT {
|
||||
formatId: format.id as UINT32,
|
||||
formatName: n.into_raw(),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<CLIPRDR_FORMAT>>();
|
||||
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
|
||||
let format_list = CLIPRDR_FORMAT_LIST {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
numFormats: num_formats,
|
||||
formats: formats.as_mut_ptr(),
|
||||
};
|
||||
|
||||
let ret = ((**context).ServerFormatList.unwrap())(&mut (**context), &format_list);
|
||||
|
||||
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 Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
data: CliprdrServerFormatListResponse,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
|
||||
let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: data.msg_flags as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
};
|
||||
|
||||
let ret =
|
||||
(**context).ServerFormatListResponse.unwrap()(&mut (**context), &format_list_response);
|
||||
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
fn server_format_data_request(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
data: CliprdrServerFormatDataRequest,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
|
||||
let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
requestedFormatId: data.requested_format_id as UINT32,
|
||||
};
|
||||
let ret =
|
||||
((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
fn server_format_data_response(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
mut data: CliprdrServerFormatDataResponse,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: data.msg_flags as UINT16,
|
||||
dataLen: data.format_data.len() as UINT32,
|
||||
requestedFormatData: data.format_data.as_mut_ptr(),
|
||||
};
|
||||
let ret = ((**context).ServerFormatDataResponse.unwrap())(
|
||||
&mut (**context),
|
||||
&format_data_response,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
fn server_file_contents_request(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
data: CliprdrFileContentsRequest,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: 0 as UINT16,
|
||||
dataLen: 0 as UINT32,
|
||||
streamId: data.stream_id as UINT32,
|
||||
listIndex: data.list_index as UINT32,
|
||||
dwFlags: data.dw_flags as UINT32,
|
||||
nPositionLow: data.n_position_low as UINT32,
|
||||
nPositionHigh: data.n_position_high as UINT32,
|
||||
cbRequested: data.cb_requested as UINT32,
|
||||
haveClipDataId: if data.have_clip_data_id { TRUE } else { FALSE },
|
||||
clipDataId: data.clip_data_id as UINT32,
|
||||
};
|
||||
let ret = ((**context).ServerFileContentsRequest.unwrap())(
|
||||
&mut (**context),
|
||||
&file_contents_request,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
fn server_file_contents_response(
|
||||
context: &mut Box<CliprdrClientContext>,
|
||||
conn_id: ConnID,
|
||||
mut data: CliprdrFileContentsResponse,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let server_conn_id = if conn_id.server_conn_id != 0 {
|
||||
conn_id.server_conn_id as UINT32
|
||||
} else {
|
||||
data.server_conn_id as UINT32
|
||||
};
|
||||
let remote_conn_id = if conn_id.remote_conn_id != 0 {
|
||||
conn_id.remote_conn_id as UINT32
|
||||
} else {
|
||||
data.remote_conn_id as UINT32
|
||||
};
|
||||
let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE {
|
||||
serverConnID: server_conn_id,
|
||||
remoteConnID: remote_conn_id,
|
||||
msgType: 0 as UINT16,
|
||||
msgFlags: data.msg_flags as UINT16,
|
||||
dataLen: 4 + data.requested_data.len() as UINT32,
|
||||
streamId: data.stream_id as UINT32,
|
||||
cbRequested: data.requested_data.len() as UINT32,
|
||||
requestedData: data.requested_data.as_mut_ptr(),
|
||||
};
|
||||
let ret = ((**context).ServerFileContentsResponse.unwrap())(
|
||||
&mut (**context),
|
||||
&file_contents_response,
|
||||
);
|
||||
ret as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> ResultType<Box<CliprdrClientContext>> {
|
||||
Ok(CliprdrClientContext::create(
|
||||
enable_files,
|
||||
enable_others,
|
||||
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 client_format_list(
|
||||
_context: *mut CliprdrClientContext,
|
||||
format_list: *const CLIPRDR_FORMAT_LIST,
|
||||
) -> UINT {
|
||||
log::debug!("client_format_list called");
|
||||
|
||||
let mut data = CliprdrServerFormatList::default();
|
||||
unsafe {
|
||||
let mut i = 0u32;
|
||||
while i < (*format_list).numFormats {
|
||||
let format_data = &(*(*format_list).formats.offset(i as isize));
|
||||
if format_data.formatName.is_null() {
|
||||
data.formats.push(CliprdrFormat {
|
||||
id: format_data.formatId as i32,
|
||||
format: "".to_owned(),
|
||||
..Default::default()
|
||||
});
|
||||
} 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()
|
||||
}
|
||||
};
|
||||
data.formats.push(CliprdrFormat {
|
||||
id: format_data.formatId as i32,
|
||||
format: format_name,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
data.server_conn_id = (*format_list).serverConnID as i32;
|
||||
data.remote_conn_id = (*format_list).remoteConnID as i32;
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_format_list(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
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 mut data = CliprdrServerFormatListResponse::default();
|
||||
unsafe {
|
||||
data.server_conn_id = (*format_list_response).serverConnID as i32;
|
||||
data.remote_conn_id = (*format_list_response).remoteConnID as i32;
|
||||
data.msg_flags = (*format_list_response).msgFlags as i32;
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_format_list_response(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
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 mut data = CliprdrServerFormatDataRequest::default();
|
||||
unsafe {
|
||||
data.server_conn_id = (*format_data_request).serverConnID as i32;
|
||||
data.remote_conn_id = (*format_data_request).remoteConnID as i32;
|
||||
data.requested_format_id = (*format_data_request).requestedFormatId as i32;
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_format_data_request(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" fn client_format_data_response(
|
||||
_context: *mut CliprdrClientContext,
|
||||
format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE,
|
||||
) -> UINT {
|
||||
log::debug!("client_format_data_response called");
|
||||
|
||||
let mut data = CliprdrServerFormatDataResponse::default();
|
||||
unsafe {
|
||||
data.server_conn_id = (*format_data_response).serverConnID as i32;
|
||||
data.remote_conn_id = (*format_data_response).remoteConnID as i32;
|
||||
data.msg_flags = (*format_data_response).msgFlags as i32;
|
||||
data.format_data = std::slice::from_raw_parts(
|
||||
(*format_data_response).requestedFormatData,
|
||||
(*format_data_response).dataLen as usize,
|
||||
)
|
||||
.to_vec();
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_format_data_response(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
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 mut data = CliprdrFileContentsRequest::default();
|
||||
unsafe {
|
||||
data.server_conn_id = (*file_contents_request).serverConnID as i32;
|
||||
data.remote_conn_id = (*file_contents_request).remoteConnID as i32;
|
||||
data.stream_id = (*file_contents_request).streamId as i32;
|
||||
data.list_index = (*file_contents_request).listIndex as i32;
|
||||
data.dw_flags = (*file_contents_request).dwFlags as i32;
|
||||
data.n_position_low = (*file_contents_request).nPositionLow as i32;
|
||||
data.n_position_high = (*file_contents_request).nPositionHigh as i32;
|
||||
data.cb_requested = (*file_contents_request).cbRequested as i32;
|
||||
data.have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE;
|
||||
data.clip_data_id = (*file_contents_request).clipDataId as i32;
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_file_contents_request(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
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 mut data = CliprdrFileContentsResponse::default();
|
||||
unsafe {
|
||||
data.server_conn_id = (*file_contents_response).serverConnID as i32;
|
||||
data.remote_conn_id = (*file_contents_response).remoteConnID as i32;
|
||||
data.msg_flags = (*file_contents_response).msgFlags as i32;
|
||||
data.stream_id = (*file_contents_response).streamId as i32;
|
||||
data.requested_data = std::slice::from_raw_parts(
|
||||
(*file_contents_response).requestedData,
|
||||
(*file_contents_response).cbRequested as usize,
|
||||
)
|
||||
.to_vec();
|
||||
}
|
||||
let conn_id = ConnID {
|
||||
server_conn_id: data.server_conn_id as u32,
|
||||
remote_conn_id: data.remote_conn_id as u32,
|
||||
};
|
||||
|
||||
let mut msg = Message::new();
|
||||
let mut cliprdr = Cliprdr::new();
|
||||
cliprdr.set_file_contents_response(data);
|
||||
msg.set_cliprdr(cliprdr);
|
||||
// no need to handle result here
|
||||
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// #[test]
|
||||
// fn test_cliprdr_run() {
|
||||
// super::cliprdr_run();
|
||||
// }
|
||||
}
|
||||
2789
libs/clipboard/src/windows/wf_cliprdr.c
Normal file
2789
libs/clipboard/src/windows/wf_cliprdr.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user