simple_rc: win init simple resource pack

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-04-24 23:39:15 +08:00
parent e1bb25c70e
commit 2081113bed
13 changed files with 444 additions and 83 deletions

12
Cargo.lock generated
View File

@ -4093,6 +4093,7 @@ dependencies = [
"serde_derive",
"serde_json 1.0.79",
"sha2",
"simple_rc",
"sys-locale",
"sysinfo",
"tray-item",
@ -4446,6 +4447,17 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"
[[package]]
name = "simple_rc"
version = "0.1.0"
dependencies = [
"confy",
"hbb_common",
"serde 1.0.136",
"serde_derive",
"walkdir",
]
[[package]]
name = "siphasher"
version = "0.2.3"

View File

@ -19,6 +19,7 @@ path = "src/naming.rs"
inline = []
hbbs = []
cli = []
with_rc = ["simple_rc"]
use_samplerate = ["samplerate"]
use_rubato = ["rubato"]
use_dasp = ["dasp"]
@ -103,7 +104,7 @@ jni = "0.19.0"
flutter_rust_bridge = "1.30.0"
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display"]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/simple_rc"]
[package.metadata.winres]
LegalCopyright = "Copyright © 2022 Purslane, Inc."
@ -117,6 +118,7 @@ winapi = { version = "0.3", features = [ "winnt" ] }
[build-dependencies]
cc = "1.0"
hbb_common = { path = "libs/hbb_common" }
simple_rc = { path = "libs/simple_rc", optional = true }
flutter_rust_bridge_codegen = "1.30.0"
[dev-dependencies]

View File

@ -27,6 +27,20 @@ fn build_manifest() {
}
}
#[cfg(all(windows, feature = "with_rc"))]
fn build_rc_source() {
use simple_rc::{generate_with_conf, Config, ConfigItem};
generate_with_conf(&Config {
outfile: "src/rc.rs".to_owned(),
confs: vec![ConfigItem {
inc: "resources".to_owned(),
exc: vec![],
suppressed_front: "resources".to_owned(),
}],
})
.unwrap();
}
fn install_oboe() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
if target_os != "android" {
@ -87,6 +101,8 @@ fn main() {
gen_flutter_rust_bridge();
return;
}
#[cfg(all(windows, feature = "with_rc"))]
build_rc_source();
#[cfg(all(windows, feature = "inline"))]
build_manifest();
#[cfg(windows)]

13
libs/simple_rc/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "simple_rc"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde_derive = "1.0"
serde = "1.0"
walkdir = "2"
confy = { git = "https://github.com/open-trade/confy" }
hbb_common = { path = "../hbb_common" }

View File

@ -0,0 +1,23 @@
extern crate simple_rc;
use simple_rc::*;
fn main() {
{
const CONF_FILE: &str = "simple_rc.toml";
generate(CONF_FILE).unwrap();
}
{
generate_with_conf(&Config {
outfile: "src/rc.rs".to_owned(),
confs: vec![ConfigItem {
inc: "D:/projects/windows/RustDeskTempTopMostWindow/x64/Release/xxx".to_owned(),
// exc: vec!["*.dll".to_owned(), "*.exe".to_owned()],
exc: vec![],
suppressed_front: "D:/projects/windows".to_owned(),
}],
})
.unwrap();
}
}

View File

@ -0,0 +1,12 @@
# The output source file
outfile = "src/rc.rs"
# The resource config list.
[[confs]]
# The file or director to integrate.
inc = "D:/projects/windows/RustDeskTempTopMostWindow/x64/Release/xxx"
# The exclusions.
exc = ["*.dll", "*.exe"]
# The front path that will ignore for extracting.
# The following config will make base output path to be "RustDeskTempTopMostWindow/x64/Release/xxx".
suppressed_front = "D:/projects/windows"

208
libs/simple_rc/src/lib.rs Normal file
View File

@ -0,0 +1,208 @@
use hbb_common::{bail, ResultType};
use serde_derive::{Deserialize, Serialize};
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path};
use walkdir::WalkDir;
//mod rc;
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
pub struct ConfigItem {
// include directory or file
pub inc: String,
// exclude files
pub exc: Vec<String>,
// out_path = origin_path - suppressed_front
pub suppressed_front: String,
}
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
pub struct Config {
// output source file
pub outfile: String,
// config items
pub confs: Vec<ConfigItem>,
}
pub fn get_outin_files<'a>(item: &'a ConfigItem) -> ResultType<HashMap<String, String>> {
let mut outin_filemap = HashMap::new();
for entry in WalkDir::new(&item.inc).follow_links(true) {
let path = entry?.into_path();
if path.is_file() {
let mut exclude = false;
for excfile in item.exc.iter() {
if excfile.starts_with("*.") {
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
if excfile.ends_with(&format!(".{}", ext)) {
exclude = true;
break;
}
}
} else {
if path.ends_with(Path::new(excfile)) {
exclude = true;
break;
}
}
}
if exclude {
continue;
}
let mut suppressed_front = item.suppressed_front.clone();
if !suppressed_front.is_empty() && suppressed_front.ends_with('/') {
suppressed_front.push('/');
}
let outpath = path.strip_prefix(Path::new(&suppressed_front))?;
let outfile = if outpath.is_absolute() {
match outpath
.file_name()
.and_then(|f| f.to_str())
.map(|f| f.to_string())
{
None => {
bail!("Failed to get filename of {}", outpath.display());
}
Some(s) => s,
}
} else {
match outpath.to_str() {
None => {
bail!("Failed to convert {} to string", outpath.display());
}
// Simple replace \ to / here.
// A better way is to use lib [path-slash](https://github.com/rhysd/path-slash)
Some(s) => s.to_string().replace("\\", "/"),
}
};
let infile = match path.canonicalize()?.to_str() {
None => {
bail!("Failed to get file path of {}", path.display());
}
Some(s) => s.to_string(),
};
if let Some(_) = outin_filemap.insert(outfile.clone(), infile) {
bail!("outfile {} is set before", outfile);
}
}
}
Ok(outin_filemap)
}
pub fn generate(conf_file: &str) -> ResultType<()> {
let conf = confy::load_path(conf_file)?;
generate_with_conf(&conf)?;
Ok(())
}
pub fn generate_with_conf<'a>(conf: &'a Config) -> ResultType<()> {
let mut outfile = File::create(&conf.outfile)?;
outfile.write(
br##"use hbb_common::{bail, ResultType};
use std::{
fs::{self, File},
io::prelude::*,
path::Path,
};
"##,
)?;
outfile.write(b"#[allow(dead_code)]\n")?;
outfile.write(b"pub fn extract_resources(root_path: &str) -> ResultType<()> {\n")?;
outfile.write(b" let mut resources: Vec<(&str, &[u8])> = Vec::new();\n")?;
let mut outin_files = HashMap::new();
for item in conf.confs.iter() {
for (o, i) in get_outin_files(item)?.into_iter() {
if let Some(_) = outin_files.insert(o.clone(), i) {
bail!("outfile {} is set before", o);
}
}
}
let mut count = 1;
for (o, i) in outin_files.iter() {
let mut infile = File::open(&i)?;
let mut buffer = Vec::<u8>::new();
infile.read_to_end(&mut buffer)?;
let var_outfile = format!("outfile_{}", count);
let var_outdata = format!("outdata_{}", count);
write!(outfile, " let {} = \"{}\";\n", var_outfile, o)?;
write!(outfile, " let {}: &[u8] = &[\n ", var_outdata)?;
let mut line_num = 20;
for v in buffer {
if line_num == 0 {
write!(outfile, "\n ")?;
line_num = 20;
}
write!(outfile, "{:#04x}, ", v)?;
line_num -= 1;
}
write!(outfile, "\n ];\n")?;
write!(
outfile,
" resources.push(({}, &{}));\n",
var_outfile, var_outdata
)?;
count += 1;
}
outfile.write(b" do_extract(root_path, resources)?;\n")?;
outfile.write(b" Ok(())\n")?;
outfile.write(b"}\n")?;
outfile.write(
br##"
#[allow(dead_code)]
fn do_extract(root_path: &str, resources: Vec<(&str, &[u8])>) -> ResultType<()> {
let mut root_path = root_path.replace("\\", "/");
if !root_path.ends_with('/') {
root_path.push('/');
}
let root_path = Path::new(&root_path);
for (outfile, data) in resources {
let outfile_path = root_path.join(outfile);
match outfile_path.parent().and_then(|p| p.to_str()) {
None => {
bail!("Failed to get parent of {}", outfile_path.display());
}
Some(p) => {
fs::create_dir_all(p)?;
let mut of = File::create(outfile_path)?;
of.write_all(data)?;
of.flush()?;
}
}
}
Ok(())
}
"##,
)?;
outfile.flush()?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
// #[test]
// fn test_extract() {
// use super::*;
// rc::extract_resources("D:").unwrap();
// }
}

View File

@ -1,12 +1,14 @@
#[cfg(windows)]
use virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
#[cfg(windows)]
use std::{
ffi::CStr,
io::{self, Read},
path::Path,
};
#[cfg(windows)]
fn prompt_input() -> u8 {
println!("Press key execute:");
println!(" 1. 'x' 1. exit");
@ -24,6 +26,7 @@ fn prompt_input() -> u8 {
.unwrap_or(0)
}
#[cfg(windows)]
unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
println!("Plug in monitor begin");
if idd::FALSE == idd::MonitorPlugIn(index, edid, 25) {
@ -48,6 +51,7 @@ unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
}
}
#[cfg(windows)]
unsafe fn plug_out(index: idd::UINT) {
println!("Plug out monitor begin");
if idd::FALSE == idd::MonitorPlugOut(index) {
@ -58,88 +62,91 @@ unsafe fn plug_out(index: idd::UINT) {
}
fn main() {
let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
#[cfg(windows)]
{
let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
unsafe {
let invalid_device = 0 as idd::HSWDEVICE;
let mut h_sw_device = invalid_device;
unsafe {
let invalid_device = 0 as idd::HSWDEVICE;
let mut h_sw_device = invalid_device;
let full_inf_path: Vec<u16> = abs_path
.to_string_lossy()
.as_ref()
.encode_utf16()
.chain(Some(0).into_iter())
.collect();
let full_inf_path: Vec<u16> = abs_path
.to_string_lossy()
.as_ref()
.encode_utf16()
.chain(Some(0).into_iter())
.collect();
loop {
match prompt_input() as char {
'x' => break,
'i' => {
println!("Install or update driver begin, {}", abs_path.display());
let mut reboot_required = idd::FALSE;
if idd::InstallUpdate(full_inf_path.as_ptr() as _, &mut reboot_required)
== idd::FALSE
{
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Install or update driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
loop {
match prompt_input() as char {
'x' => break,
'i' => {
println!("Install or update driver begin, {}", abs_path.display());
let mut reboot_required = idd::FALSE;
if idd::InstallUpdate(full_inf_path.as_ptr() as _, &mut reboot_required)
== idd::FALSE
{
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Install or update driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
}
}
}
'u' => {
println!("Uninstall driver begin {}", abs_path.display());
let mut reboot_required = idd::FALSE;
if idd::Uninstall(full_inf_path.as_ptr() as _, &mut reboot_required)
== idd::FALSE
{
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Uninstall driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
'u' => {
println!("Uninstall driver begin {}", abs_path.display());
let mut reboot_required = idd::FALSE;
if idd::Uninstall(full_inf_path.as_ptr() as _, &mut reboot_required)
== idd::FALSE
{
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Uninstall driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
}
}
}
'c' => {
println!("Create device begin");
if h_sw_device != invalid_device {
println!("Device created before");
continue;
'c' => {
println!("Create device begin");
if h_sw_device != invalid_device {
println!("Device created before");
continue;
}
if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
idd::DeviceClose(h_sw_device);
h_sw_device = invalid_device;
} else {
println!("Create device done");
}
}
if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
'd' => {
println!("Close device begin");
idd::DeviceClose(h_sw_device);
h_sw_device = invalid_device;
} else {
println!("Create device done");
println!("Close device done");
}
'1' => plug_in(0, 0),
'2' => plug_in(1, 0),
'3' => plug_in(2, 0),
'4' => plug_out(0),
'5' => plug_out(1),
'6' => plug_out(2),
_ => {}
}
'd' => {
println!("Close device begin");
idd::DeviceClose(h_sw_device);
h_sw_device = invalid_device;
println!("Close device done");
}
'1' => plug_in(0, 0),
'2' => plug_in(1, 0),
'3' => plug_in(2, 0),
'4' => plug_out(0),
'5' => plug_out(1),
'6' => plug_out(2),
_ => {}
}
}
idd::DeviceClose(h_sw_device);
idd::DeviceClose(h_sw_device);
}
}
}

View File

@ -42,3 +42,6 @@ mod tray;
#[cfg(windows)]
pub mod clipboard_file;
#[cfg(all(windows, feature = "with_rc"))]
pub mod rc;

View File

@ -1,6 +1,6 @@
// Specify the Windows subsystem to eliminate console window.
// Requires Rust 1.18.
//#![windows_subsystem = "windows"]
#![windows_subsystem = "windows"]
use hbb_common::log;
use librustdesk::*;
@ -104,6 +104,10 @@ fn main() {
"".to_owned()
));
return;
} else if args[0] == "--extract" {
#[cfg(feature = "with_rc")]
hbb_common::allow_err!(crate::rc::extract_resources(&args[1]));
return;
}
}
if args[0] == "--remove" {

View File

@ -10,7 +10,6 @@ use std::io::prelude::*;
use std::{
ffi::OsString,
fs, io, mem,
path::Path,
sync::{Arc, Mutex},
time::{Duration, Instant},
};
@ -856,7 +855,7 @@ fn get_install_info_with_subkey(subkey: String) -> (String, String, String, Stri
}
pub fn update_me() -> ResultType<()> {
let (_, _, _, exe) = get_install_info();
let (_, path, _, exe) = get_install_info();
let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_owned();
let cmds = format!(
"
@ -865,12 +864,14 @@ pub fn update_me() -> ResultType<()> {
taskkill /F /IM {broker_exe}
taskkill /F /IM {app_name}.exe
copy /Y \"{src_exe}\" \"{exe}\"
\"{src_exe}\" --extract \"{path}\"
sc start {app_name}
{lic}
",
src_exe = src_exe,
exe = exe,
broker_exe = crate::ui::win_privacy::INJECTED_PROCESS_EXE,
path = path,
app_name = crate::get_app_name(),
lic = register_licence(),
);
@ -1023,6 +1024,7 @@ chcp 65001
md \"{path}\"
copy /Y \"{src_exe}\" \"{exe}\"
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
\"{src_exe}\" --extract \"{path}\"
reg add {subkey} /f
reg add {subkey} /f /v DisplayIcon /t REG_SZ /d \"{exe}\"
reg add {subkey} /f /v DisplayName /t REG_SZ /d \"{app_name}\"

38
src/rc.rs Normal file
View File

@ -0,0 +1,38 @@
use hbb_common::{bail, ResultType};
use std::{
fs::{self, File},
io::prelude::*,
path::Path,
};
#[allow(dead_code)]
pub fn extract_resources(root_path: &str) -> ResultType<()> {
let mut resources: Vec<(&str, &[u8])> = Vec::new();
resources.push((outfile_4, &outdata_4));
do_extract(root_path, resources)?;
Ok(())
}
#[allow(dead_code)]
fn do_extract(root_path: &str, resources: Vec<(&str, &[u8])>) -> ResultType<()> {
let mut root_path = root_path.replace("\\", "/");
if !root_path.ends_with('/') {
root_path.push('/');
}
let root_path = Path::new(&root_path);
for (outfile, data) in resources {
let outfile_path = root_path.join(outfile);
match outfile_path.parent().and_then(|p| p.to_str()) {
None => {
bail!("Failed to get parent of {}", outfile_path.display());
}
Some(p) => {
fs::create_dir_all(p)?;
let mut of = File::create(outfile_path)?;
of.write_all(data)?;
of.flush()?;
}
}
}
Ok(())
}

View File

@ -24,8 +24,8 @@ use clipboard::{
};
use enigo::{self, Enigo, KeyboardControllable};
use hbb_common::fs::{
can_enable_overwrite_detection, get_string, new_send_confirm,
DigestCheckResult, RemoveJobMeta, get_job,
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
RemoveJobMeta,
};
use hbb_common::{
allow_err,
@ -48,7 +48,7 @@ use hbb_common::{config::TransferSerde, fs::TransferJobMeta};
use crate::clipboard_file::*;
use crate::{
client::*,
common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}
common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL},
};
type Video = AssetPtr<video_destination>;
@ -267,7 +267,8 @@ impl Handler {
std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev
use rdev::{EventType::*, *};
let func = move |evt: Event| {
if !IS_IN.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst) {
if !IS_IN.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst)
{
return;
}
let (key, down) = match evt.event_type {
@ -1660,7 +1661,12 @@ impl Remote {
Data::AddJob((id, path, to, file_num, include_hidden, is_remote)) => {
let od = can_enable_overwrite_detection(self.handler.lc.read().unwrap().version);
if is_remote {
log::debug!("new write waiting job {}, write to {} from remote {}", id, to, path);
log::debug!(
"new write waiting job {}, write to {} from remote {}",
id,
to,
path
);
let mut job = fs::TransferJob::new_write(
id,
path.clone(),
@ -1708,15 +1714,27 @@ impl Remote {
if let Some(job) = get_job(id, &mut self.write_jobs) {
job.is_last_job = false;
allow_err!(
peer.send(&fs::new_send(id, job.remote.clone(), job.file_num, job.show_hidden))
peer.send(&fs::new_send(
id,
job.remote.clone(),
job.file_num,
job.show_hidden
))
.await
);
}
} else {
if let Some(job) = get_job(id, &mut self.read_jobs) {
job.is_last_job = false;
allow_err!(peer.send(&fs::new_receive(id, job.path.to_string_lossy().to_string(),
job.file_num, job.files.clone())).await);
allow_err!(
peer.send(&fs::new_receive(
id,
job.path.to_string_lossy().to_string(),
job.file_num,
job.files.clone()
))
.await
);
}
}
}
@ -2024,6 +2042,9 @@ impl Remote {
Some(message::Union::file_response(fr)) => {
match fr.union {
Some(file_response::Union::dir(fd)) => {
#[cfg(windows)]
let entries = fd.entries.to_vec();
#[cfg(not(windows))]
let mut entries = fd.entries.to_vec();
#[cfg(not(windows))]
{