mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'master' into dev
This commit is contained in:
@@ -18,7 +18,7 @@ fn build_c_impl() {
|
||||
if build.get_compiler().is_like_msvc() {
|
||||
build.define("WIN32", "");
|
||||
// build.define("_AMD64_", "");
|
||||
build.flag("-Zi");
|
||||
build.flag("-Z7");
|
||||
build.flag("-GR-");
|
||||
// build.flag("-std:c++11");
|
||||
} else {
|
||||
|
||||
@@ -8,8 +8,8 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use directories_next::ProjectDirs;
|
||||
use rand::Rng;
|
||||
use serde as de;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sodiumoxide::crypto::sign;
|
||||
|
||||
@@ -80,6 +80,26 @@ pub const RS_PUB_KEY: &'static str = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmB
|
||||
pub const RENDEZVOUS_PORT: i32 = 21116;
|
||||
pub const RELAY_PORT: i32 = 21117;
|
||||
|
||||
macro_rules! serde_field_string {
|
||||
($default_func:ident, $de_func:ident, $default_expr:expr) => {
|
||||
fn $default_func() -> String {
|
||||
$default_expr
|
||||
}
|
||||
|
||||
fn $de_func<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
let s: &str = de::Deserialize::deserialize(deserializer)?;
|
||||
Ok(if s.is_empty() {
|
||||
Self::$default_func()
|
||||
} else {
|
||||
s.to_owned()
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum NetworkType {
|
||||
Direct,
|
||||
@@ -142,9 +162,20 @@ pub struct PeerConfig {
|
||||
pub size_ft: Size,
|
||||
#[serde(default)]
|
||||
pub size_pf: Size,
|
||||
#[serde(default)]
|
||||
pub view_style: String, // original (default), scale
|
||||
#[serde(default)]
|
||||
#[serde(
|
||||
default = "PeerConfig::default_view_style",
|
||||
deserialize_with = "PeerConfig::deserialize_view_style"
|
||||
)]
|
||||
pub view_style: String,
|
||||
#[serde(
|
||||
default = "PeerConfig::default_scroll_style",
|
||||
deserialize_with = "PeerConfig::deserialize_scroll_style"
|
||||
)]
|
||||
pub scroll_style: String,
|
||||
#[serde(
|
||||
default = "PeerConfig::default_image_quality",
|
||||
deserialize_with = "PeerConfig::deserialize_image_quality"
|
||||
)]
|
||||
pub image_quality: String,
|
||||
#[serde(default)]
|
||||
pub custom_image_quality: Vec<i32>,
|
||||
@@ -167,9 +198,15 @@ pub struct PeerConfig {
|
||||
#[serde(default)]
|
||||
pub show_quality_monitor: bool,
|
||||
|
||||
// the other scalar value must before this
|
||||
#[serde(default)]
|
||||
// The other scalar value must before this
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "PeerConfig::deserialize_options"
|
||||
)]
|
||||
pub options: HashMap<String, String>,
|
||||
// Various data for flutter ui
|
||||
#[serde(default)]
|
||||
pub ui_flutter: HashMap<String, String>,
|
||||
#[serde(default)]
|
||||
pub info: PeerInfoSerde,
|
||||
#[serde(default)]
|
||||
@@ -372,12 +409,15 @@ impl Config {
|
||||
pub fn get_home() -> PathBuf {
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
return Self::path(APP_HOME_DIR.read().unwrap().as_str());
|
||||
if let Some(path) = dirs_next::home_dir() {
|
||||
patch(path)
|
||||
} else if let Ok(path) = std::env::current_dir() {
|
||||
path
|
||||
} else {
|
||||
std::env::temp_dir()
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
if let Some(path) = dirs_next::home_dir() {
|
||||
patch(path)
|
||||
} else if let Ok(path) = std::env::current_dir() {
|
||||
path
|
||||
} else {
|
||||
std::env::temp_dir()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,17 +428,22 @@ impl Config {
|
||||
path.push(p);
|
||||
return path;
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let org = "";
|
||||
#[cfg(target_os = "macos")]
|
||||
let org = ORG.read().unwrap().clone();
|
||||
// /var/root for root
|
||||
if let Some(project) = ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) {
|
||||
let mut path = patch(project.config_dir().to_path_buf());
|
||||
path.push(p);
|
||||
return path;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let org = "";
|
||||
#[cfg(target_os = "macos")]
|
||||
let org = ORG.read().unwrap().clone();
|
||||
// /var/root for root
|
||||
if let Some(project) =
|
||||
directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap())
|
||||
{
|
||||
let mut path = patch(project.config_dir().to_path_buf());
|
||||
path.push(p);
|
||||
return path;
|
||||
}
|
||||
return "".into();
|
||||
}
|
||||
return "".into();
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
@@ -577,16 +622,19 @@ impl Config {
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
let mut id = 0u32;
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if let Ok(Some(ma)) = mac_address::get_mac_address() {
|
||||
for x in &ma.bytes()[2..] {
|
||||
id = (id << 8) | (*x as u32);
|
||||
{
|
||||
let mut id = 0u32;
|
||||
if let Ok(Some(ma)) = mac_address::get_mac_address() {
|
||||
for x in &ma.bytes()[2..] {
|
||||
id = (id << 8) | (*x as u32);
|
||||
}
|
||||
id = id & 0x1FFFFFFF;
|
||||
Some(id.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
id = id & 0x1FFFFFFF;
|
||||
Some(id.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,6 +933,21 @@ impl PeerConfig {
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
|
||||
serde_field_string!(default_view_style, deserialize_view_style, "original".to_owned());
|
||||
serde_field_string!(default_scroll_style, deserialize_scroll_style, "scrollauto".to_owned());
|
||||
serde_field_string!(default_image_quality, deserialize_image_quality, "balanced".to_owned());
|
||||
|
||||
fn deserialize_options<'de, D>(deserializer: D) -> Result<HashMap<String, String>, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
let mut mp: HashMap<String, String> = de::Deserialize::deserialize(deserializer)?;
|
||||
if !mp.contains_key("codec-preference") {
|
||||
mp.insert("codec-preference".to_owned(), "auto".to_owned());
|
||||
}
|
||||
Ok(mp)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
@@ -897,6 +960,9 @@ pub struct LocalConfig {
|
||||
pub fav: Vec<String>,
|
||||
#[serde(default)]
|
||||
options: HashMap<String, String>,
|
||||
// Various data for flutter ui
|
||||
#[serde(default)]
|
||||
ui_flutter: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl LocalConfig {
|
||||
@@ -968,6 +1034,27 @@ impl LocalConfig {
|
||||
config.store();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_flutter_config(k: &str) -> String {
|
||||
if let Some(v) = LOCAL_CONFIG.read().unwrap().ui_flutter.get(k) {
|
||||
v.clone()
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_flutter_config(k: String, v: String) {
|
||||
let mut config = LOCAL_CONFIG.write().unwrap();
|
||||
let v2 = if v.is_empty() { None } else { Some(&v) };
|
||||
if v2 != config.ui_flutter.get(&k) {
|
||||
if v2.is_none() {
|
||||
config.ui_flutter.remove(&k);
|
||||
} else {
|
||||
config.ui_flutter.insert(k, v);
|
||||
}
|
||||
config.store();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
|
||||
@@ -380,7 +380,7 @@ impl TransferJob {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> {
|
||||
pub async fn write(&mut self, block: FileTransferBlock) -> ResultType<()> {
|
||||
if block.id != self.id {
|
||||
bail!("Wrong id");
|
||||
}
|
||||
@@ -402,20 +402,15 @@ impl TransferJob {
|
||||
let path = format!("{}.download", get_string(&path));
|
||||
self.file = Some(File::create(&path).await?);
|
||||
}
|
||||
let data = if let Some(data) = raw {
|
||||
data
|
||||
} else {
|
||||
&block.data
|
||||
};
|
||||
if block.compressed {
|
||||
let tmp = decompress(data);
|
||||
let tmp = decompress(&block.data);
|
||||
self.file.as_mut().unwrap().write_all(&tmp).await?;
|
||||
self.finished_size += tmp.len() as u64;
|
||||
} else {
|
||||
self.file.as_mut().unwrap().write_all(data).await?;
|
||||
self.finished_size += data.len() as u64;
|
||||
self.file.as_mut().unwrap().write_all(&block.data).await?;
|
||||
self.finished_size += block.data.len() as u64;
|
||||
}
|
||||
self.transferred += data.len() as u64;
|
||||
self.transferred += block.data.len() as u64;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -161,19 +161,23 @@ pub fn get_version_from_url(url: &str) -> String {
|
||||
}
|
||||
|
||||
pub fn gen_version() {
|
||||
use std::io::prelude::*;
|
||||
let mut file = File::create("./src/version.rs").unwrap();
|
||||
for line in read_lines("Cargo.toml").unwrap() {
|
||||
if let Ok(line) = line {
|
||||
let ab: Vec<&str> = line.split("=").map(|x| x.trim()).collect();
|
||||
if ab.len() == 2 && ab[0] == "version" {
|
||||
use std::io::prelude::*;
|
||||
file.write_all(format!("pub const VERSION: &str = {};", ab[1]).as_bytes())
|
||||
file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
|
||||
.ok();
|
||||
file.sync_all().ok();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// generate build date
|
||||
let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
|
||||
file.write_all(format!("pub const BUILD_DATE: &str = \"{}\";", build_date).as_bytes())
|
||||
.ok();
|
||||
file.sync_all().ok();
|
||||
}
|
||||
|
||||
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||
|
||||
@@ -51,24 +51,32 @@ fn execute(path: PathBuf, args: Vec<String>) {
|
||||
.expect(&format!("failed to execute {:?}", exe_name));
|
||||
}
|
||||
|
||||
fn is_setup(name: &str) -> bool {
|
||||
name.to_lowercase().ends_with("install.exe") || name.to_lowercase().ends_with("安装.exe")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let is_setup = is_setup(
|
||||
&std::env::current_exe()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
let reader = BinaryReader::default();
|
||||
if let Some(exe) = setup(reader, None, is_setup) {
|
||||
let args = if is_setup {
|
||||
vec!["--install".to_owned()]
|
||||
let mut args = Vec::new();
|
||||
let mut arg_exe = Default::default();
|
||||
let mut i = 0;
|
||||
for arg in std::env::args() {
|
||||
if i == 0 {
|
||||
arg_exe = arg.clone();
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
args.push(arg);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
let click_setup = args.is_empty() && arg_exe.to_lowercase().ends_with("install.exe");
|
||||
let quick_support = args.is_empty() && arg_exe.to_lowercase().ends_with("qs.exe");
|
||||
|
||||
let reader = BinaryReader::default();
|
||||
if let Some(exe) = setup(
|
||||
reader,
|
||||
None,
|
||||
click_setup || args.contains(&"--silent-install".to_owned()),
|
||||
) {
|
||||
if click_setup {
|
||||
args = vec!["--install".to_owned()];
|
||||
} else if quick_support {
|
||||
args = vec!["--quick_support".to_owned()];
|
||||
}
|
||||
execute(exe, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
pub mod ffi;
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub use ffi::*;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
@@ -61,7 +61,7 @@ impl TraitCapturer for Capturer {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Frame<'a>(&'a [u8]);
|
||||
pub struct Frame<'a>(pub &'a [u8]);
|
||||
|
||||
impl<'a> ops::Deref for Frame<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use hbb_common::anyhow::{anyhow, Context};
|
||||
use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame};
|
||||
use hbb_common::{ResultType, get_time};
|
||||
use hbb_common::{get_time, ResultType};
|
||||
|
||||
use crate::codec::EncoderApi;
|
||||
use crate::STRIDE_ALIGN;
|
||||
@@ -233,7 +233,9 @@ impl EncoderApi for VpxEncoder {
|
||||
|
||||
impl VpxEncoder {
|
||||
pub fn encode(&mut self, pts: i64, data: &[u8], stride_align: usize) -> Result<EncodeFrames> {
|
||||
assert!(2 * data.len() >= 3 * self.width * self.height);
|
||||
if 2 * data.len() < 3 * self.width * self.height {
|
||||
return Err(Error::FailedCall("len not enough".to_string()));
|
||||
}
|
||||
|
||||
let mut image = Default::default();
|
||||
call_vpx_ptr!(vpx_img_wrap(
|
||||
|
||||
1358
libs/virtual_display/Cargo.lock
generated
Normal file
1358
libs/virtual_display/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,12 +5,7 @@ edition = "2021"
|
||||
|
||||
# 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"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
libloading = "0.7"
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
|
||||
@@ -1,32 +1,3 @@
|
||||
# virtual display
|
||||
|
||||
Virtual display may be used on computers that do not have a monitor.
|
||||
|
||||
[Development reference](https://github.com/pavlobu/deskreen/discussions/86)
|
||||
|
||||
## windows
|
||||
|
||||
### win10
|
||||
|
||||
Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx).
|
||||
|
||||
This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver.
|
||||
|
||||
|
||||
**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display).
|
||||
|
||||
|
||||
#### tested platforms
|
||||
|
||||
- [x] 19041
|
||||
- [x] 19043
|
||||
|
||||
### win7
|
||||
|
||||
TODO
|
||||
|
||||
[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide).
|
||||
|
||||
## X11
|
||||
|
||||
## OSX
|
||||
[doc](./dylib/README.md)
|
||||
|
||||
19
libs/virtual_display/dylib/Cargo.toml
Normal file
19
libs/virtual_display/dylib/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "dylib_virtual_display"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "staticlib", "rlib"]
|
||||
|
||||
# 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"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
hbb_common = { path = "../../hbb_common" }
|
||||
32
libs/virtual_display/dylib/README.md
Normal file
32
libs/virtual_display/dylib/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# virtual display
|
||||
|
||||
Virtual display may be used on computers that do not have a monitor.
|
||||
|
||||
[Development reference](https://github.com/pavlobu/deskreen/discussions/86)
|
||||
|
||||
## windows
|
||||
|
||||
### win10
|
||||
|
||||
Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx).
|
||||
|
||||
This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver.
|
||||
|
||||
|
||||
**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display).
|
||||
|
||||
|
||||
#### tested platforms
|
||||
|
||||
- [x] 19041
|
||||
- [x] 19043
|
||||
|
||||
### win7
|
||||
|
||||
TODO
|
||||
|
||||
[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide).
|
||||
|
||||
## X11
|
||||
|
||||
## OSX
|
||||
@@ -13,7 +13,7 @@ fn build_c_impl() {
|
||||
|
||||
if build.get_compiler().is_like_msvc() {
|
||||
build.define("WIN32", "");
|
||||
build.flag("-Zi");
|
||||
build.flag("-Z7");
|
||||
build.flag("-GR-");
|
||||
// build.flag("-std:c++11");
|
||||
} else {
|
||||
@@ -24,7 +24,7 @@ fn build_c_impl() {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
build.compile("xxx");
|
||||
build.compile("win_virtual_display");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!("cargo:rerun-if-changed=src/win10/IddController.c");
|
||||
@@ -1,5 +1,5 @@
|
||||
#[cfg(windows)]
|
||||
use virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
|
||||
use dylib_virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::{
|
||||
207
libs/virtual_display/dylib/src/lib.rs
Normal file
207
libs/virtual_display/dylib/src/lib.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
#[cfg(windows)]
|
||||
pub mod win10;
|
||||
|
||||
use hbb_common::{bail, lazy_static, ResultType};
|
||||
use std::{path::Path, sync::Mutex};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
// If device is uninstalled though "Device Manager" Window.
|
||||
// Rustdesk is unable to handle device any more...
|
||||
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
|
||||
static ref MONITOR_PLUGIN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(windows)]
|
||||
pub fn get_dirver_install_path() -> &'static str {
|
||||
win10::DRIVER_INSTALL_PATH
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn download_driver() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let _download_url = win10::DRIVER_DOWNLOAD_URL;
|
||||
#[cfg(target_os = "linux")]
|
||||
let _download_url = "";
|
||||
|
||||
// process download and report progress
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
||||
#[cfg(not(windows))]
|
||||
let install_path = "";
|
||||
|
||||
let abs_path = Path::new(install_path).canonicalize()?;
|
||||
if !abs_path.exists() {
|
||||
bail!("{} not exists", install_path)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
// Device must be created before install driver.
|
||||
// https://github.com/fufesou/RustDeskIddDriver/issues/1
|
||||
if let Err(e) = create_device() {
|
||||
bail!("{}", e);
|
||||
}
|
||||
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::InstallUpdate(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
||||
#[cfg(not(windows))]
|
||||
let install_path = "";
|
||||
|
||||
let abs_path = Path::new(install_path).canonicalize()?;
|
||||
if !abs_path.exists() {
|
||||
bail!("{} not exists", install_path)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::Uninstall(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn is_device_created() -> bool {
|
||||
#[cfg(windows)]
|
||||
return *H_SW_DEVICE.lock().unwrap() != 0;
|
||||
#[cfg(not(windows))]
|
||||
return false;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn create_device() -> ResultType<()> {
|
||||
if is_device_created() {
|
||||
return Ok(());
|
||||
}
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let mut lock_device = H_SW_DEVICE.lock().unwrap();
|
||||
let mut h_sw_device = *lock_device as win10::idd::HSWDEVICE;
|
||||
if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
} else {
|
||||
*lock_device = h_sw_device as u64;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn close_device() {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
|
||||
*H_SW_DEVICE.lock().unwrap() = 0;
|
||||
MONITOR_PLUGIN.lock().unwrap().clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn plug_in_monitor() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
|
||||
for i in 0..plug_in_monitors.len() {
|
||||
if let Some(d) = plug_in_monitors.get(i) {
|
||||
if *d == monitor_index {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
}
|
||||
if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
(*plug_in_monitors).push(monitor_index);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn plug_out_monitor() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
|
||||
for i in 0..plug_in_monitors.len() {
|
||||
if let Some(d) = plug_in_monitors.get(i) {
|
||||
if *d == monitor_index {
|
||||
plug_in_monitors.remove(i);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn update_monitor_modes() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
let mut modes = vec![win10::idd::MonitorMode {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
sync: 60,
|
||||
}];
|
||||
if win10::idd::FALSE
|
||||
== win10::idd::MonitorModesUpdate(
|
||||
monitor_index as win10::idd::UINT,
|
||||
modes.len() as win10::idd::UINT,
|
||||
modes.as_mut_ptr(),
|
||||
)
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,192 +1,125 @@
|
||||
#[cfg(windows)]
|
||||
pub mod win10;
|
||||
use hbb_common::{bail, ResultType};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use hbb_common::{bail, lazy_static, ResultType};
|
||||
use std::{path::Path, sync::Mutex};
|
||||
const LIB_NAME_VIRTUAL_DISPLAY: &str = "dylib_virtual_display";
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
// If device is uninstalled though "Device Manager" Window.
|
||||
// Rustdesk is unable to handle device any more...
|
||||
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
|
||||
static ref MONITOR_PLUGIN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||
static ref LIB_VIRTUAL_DISPLAY: Arc<Mutex<Result<libloading::Library, libloading::Error>>> = {
|
||||
Arc::new(Mutex::new(unsafe { libloading::Library::new(get_lib_name()) }))
|
||||
};
|
||||
}
|
||||
|
||||
pub fn download_driver() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let _download_url = win10::DRIVER_DOWNLOAD_URL;
|
||||
#[cfg(target_os = "linux")]
|
||||
let _download_url = "";
|
||||
|
||||
// process download and report progress
|
||||
|
||||
Ok(())
|
||||
#[cfg(target_os = "windows")]
|
||||
fn get_lib_name() -> String {
|
||||
format!("{}.dll", LIB_NAME_VIRTUAL_DISPLAY)
|
||||
}
|
||||
|
||||
pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
||||
#[cfg(not(windows))]
|
||||
let install_path = "";
|
||||
|
||||
let abs_path = Path::new(install_path).canonicalize()?;
|
||||
if !abs_path.exists() {
|
||||
bail!("{} not exists", install_path)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
// Device must be created before install driver.
|
||||
// https://github.com/fufesou/RustDeskIddDriver/issues/1
|
||||
if let Err(e) = create_device() {
|
||||
bail!("{}", e);
|
||||
}
|
||||
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::InstallUpdate(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_lib_name() -> String {
|
||||
format!("lib{}.so", LIB_NAME_VIRTUAL_DISPLAY)
|
||||
}
|
||||
|
||||
pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
||||
#[cfg(not(windows))]
|
||||
let install_path = "";
|
||||
#[cfg(target_os = "macos")]
|
||||
fn get_lib_name() -> String {
|
||||
format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY)
|
||||
}
|
||||
|
||||
let abs_path = Path::new(install_path).canonicalize()?;
|
||||
if !abs_path.exists() {
|
||||
bail!("{} not exists", install_path)
|
||||
fn try_reload_lib() {
|
||||
let mut lock = LIB_VIRTUAL_DISPLAY.lock().unwrap();
|
||||
if lock.is_err() {
|
||||
*lock = unsafe { libloading::Library::new(get_lib_name()) };
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::Uninstall(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
#[cfg(windows)]
|
||||
pub fn get_dirver_install_path() -> ResultType<&'static str> {
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib.get::<libloading::Symbol<fn() -> &'static str>>(b"get_dirver_install_path") {
|
||||
Ok(func) => Ok(func()),
|
||||
Err(e) => bail!("Failed to load func get_dirver_install_path, {}", e),
|
||||
}
|
||||
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
|
||||
}
|
||||
},
|
||||
Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_device_created() -> bool {
|
||||
#[cfg(windows)]
|
||||
return *H_SW_DEVICE.lock().unwrap() != 0;
|
||||
#[cfg(not(windows))]
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn create_device() -> ResultType<()> {
|
||||
if is_device_created() {
|
||||
return Ok(());
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib.get::<libloading::Symbol<fn() -> bool>>(b"is_device_created") {
|
||||
Ok(func) => func(),
|
||||
Err(..) => false,
|
||||
}
|
||||
},
|
||||
Err(..) => false,
|
||||
}
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let mut lock_device = H_SW_DEVICE.lock().unwrap();
|
||||
let mut h_sw_device = *lock_device as win10::idd::HSWDEVICE;
|
||||
if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
} else {
|
||||
*lock_device = h_sw_device as u64;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close_device() {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
|
||||
*H_SW_DEVICE.lock().unwrap() = 0;
|
||||
MONITOR_PLUGIN.lock().unwrap().clear();
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib.get::<libloading::Symbol<fn()>>(b"close_device") {
|
||||
Ok(func) => func(),
|
||||
Err(..) => {}
|
||||
}
|
||||
},
|
||||
Err(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plug_in_monitor() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
|
||||
for i in 0..plug_in_monitors.len() {
|
||||
if let Some(d) = plug_in_monitors.get(i) {
|
||||
if *d == monitor_index {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
macro_rules! def_func_result {
|
||||
($func:ident, $name: tt) => {
|
||||
pub fn $func() -> ResultType<()> {
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib.get::<libloading::Symbol<fn() -> ResultType<()>>>($name.as_bytes()) {
|
||||
Ok(func) => func(),
|
||||
Err(e) => bail!("Failed to load func {}, {}", $name, e),
|
||||
}
|
||||
},
|
||||
Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e),
|
||||
}
|
||||
}
|
||||
if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
(*plug_in_monitors).push(monitor_index);
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
|
||||
pub fn plug_out_monitor() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE {
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
|
||||
for i in 0..plug_in_monitors.len() {
|
||||
if let Some(d) = plug_in_monitors.get(i) {
|
||||
if *d == monitor_index {
|
||||
plug_in_monitors.remove(i);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
pub fn install_update_driver(reboot_required: &mut bool) -> ResultType<()> {
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib.get::<libloading::Symbol<fn(&mut bool) -> ResultType<()>>>(
|
||||
b"install_update_driver",
|
||||
) {
|
||||
Ok(func) => func(reboot_required),
|
||||
Err(e) => bail!("Failed to load func install_update_driver, {}", e),
|
||||
}
|
||||
},
|
||||
Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_monitor_modes() -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
let monitor_index = 0 as u32;
|
||||
let mut modes = vec![win10::idd::MonitorMode {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
sync: 60,
|
||||
}];
|
||||
if win10::idd::FALSE
|
||||
== win10::idd::MonitorModesUpdate(
|
||||
monitor_index as win10::idd::UINT,
|
||||
modes.len() as win10::idd::UINT,
|
||||
modes.as_mut_ptr(),
|
||||
)
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
}
|
||||
pub fn uninstall_driver(reboot_required: &mut bool) -> ResultType<()> {
|
||||
try_reload_lib();
|
||||
match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() {
|
||||
Ok(lib) => unsafe {
|
||||
match lib
|
||||
.get::<libloading::Symbol<fn(&mut bool) -> ResultType<()>>>(b"uninstall_driver")
|
||||
{
|
||||
Ok(func) => func(reboot_required),
|
||||
Err(e) => bail!("Failed to load func uninstall_driver, {}", e),
|
||||
}
|
||||
},
|
||||
Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
def_func_result!(download_driver, "download_driver");
|
||||
def_func_result!(create_device, "create_device");
|
||||
def_func_result!(plug_in_monitor, "plug_in_monitor");
|
||||
def_func_result!(plug_out_monitor, "plug_out_monitor");
|
||||
def_func_result!(update_monitor_modes, "update_monitor_modes");
|
||||
|
||||
Reference in New Issue
Block a user