feat, topmost window, exclude from capture

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-11-19 15:26:02 +08:00
parent 98f56fd506
commit c23f377039
44 changed files with 468 additions and 394 deletions

View File

@ -57,9 +57,9 @@ def parse_rc_features(feature):
},
'PrivacyMode': {
'platform': ['windows'],
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2'
'/TempTopMostWindow_x64_pic_en.zip',
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2/checksum_md5',
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3'
'/TempTopMostWindow_x64.zip',
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3/checksum_md5',
'include': ['WindowInjection.dll'],
}
}

View File

@ -94,11 +94,11 @@ mod windows {
// Used for privacy mode(magnifier impl).
pub const RUNTIME_BROKER_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe";
pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe";
pub const WIN_TOPMOST_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe";
pub(super) fn copy_runtime_broker(dir: &PathBuf) {
let src = RUNTIME_BROKER_EXE;
let tgt = WIN_MAG_INJECTED_PROCESS_EXE;
let tgt = WIN_TOPMOST_INJECTED_PROCESS_EXE;
let target_file = dir.join(tgt);
if target_file.exists() {
if let (Ok(src_file), Ok(tgt_file)) = (fs::read(src), fs::read(&target_file)) {

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", "模式 1 (不推荐)"),
("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"),
("privacy_mode_impl_exclude_from_capture_tip", "模式 3"),
("Enter privacy mode", "进入隐私模式"),
("Exit privacy mode", "退出隐私模式"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Můžete zadat ID, přímou IP adresu nebo doménu s portem (<doména>:<port>).\nPokud chcete přistupovat k zařízení na jiném serveru, připojte adresu serveru (<id>@<adresa_serveru>?key=<hodnota_klíče>), například,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nPokud chcete přistupovat k zařízení na veřejném serveru, zadejte \"<id>@public\", klíč není pro veřejný server potřeba."),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Sie können eine ID, eine direkte IP oder eine Domäne mit einem Port (<domain>:<port>) eingeben.\nWenn Sie auf ein Gerät auf einem anderen Server zugreifen möchten, fügen Sie bitte die Serveradresse (<id>@<server_address>?key=<key_value>) hinzu, zum Beispiel\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nWenn Sie auf ein Gerät auf einem öffentlichen Server zugreifen wollen, geben Sie bitte \"<id>@public\" ein. Der Schlüssel wird für öffentliche Server nicht benötigt."),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -205,5 +205,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "You can input an ID, a direct IP, or a domain with a port (<domain>:<port>).\nIf you want to access a device on another server, please append the server address (<id>@<server_address>?key=<key_value>), for example,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nIf you want to access a device on a public server, please input \"<id>@public\", the key is not needed for public server"),
("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"),
("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"),
("privacy_mode_impl_exclude_from_capture_tip", "Mode 3"),
].iter().cloned().collect();
}

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Puedes introducir una ID, una IP directa o un dominio con un puerto (<dominio>:<puerto>).\nSi quieres acceder a un dispositivo en otro servidor, por favor añade la ip del servidor (<id>@<dirección_servidor>?key=<clave_valor>), por ejemplo,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSi quieres acceder a un dispositivo en un servidor público, por favor, introduce \"<id>@public\", la clave no es necesaria para un servidor público."),
("privacy_mode_impl_mag_tip", "Modo 1 (obsoleto)"),
("privacy_mode_impl_virtual_display_tip", "Modo 2 (recomendado)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Entrar al modo privado"),
("Exit privacy mode", "Salir del modo privado"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Anda bisa memasukkan ID, IP langsung, atau domain dengan port kostum yang sudah ditentukan (<domain>:<port>).\nJika anda ingin mengakses perangkat lain yang berbeda server, tambahkan alamat server setelah penulisan ID(<id>@<server_address>?key=<key_value>), sebagai contoh,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJika anda ingin mengakses perangkat yang menggunakan server publik, masukkan \"<id>@public\", server public tidak memerlukan key khusus"),
("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"),
("privacy_mode_impl_virtual_display_tip", "Mode 2 (direkomendasikan)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Masuk mode privasi"),
("Exit privacy mode", "Keluar mode privasi"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Puoi inserire un ID, un IP diretto o un dominio con una porta (<dominio>:<porta>).\nSe vuoi accedere as un dispositivo in un altro server, aggiungi l'indirizzo del server (<id>@<indirizzo_server >?key=<valore_chiave>), ad esempio\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vuoi accedere as un dispositivo in un server pubblico, inserisci \"<id>@public\", per il server pubblico la chiave non è necessaria"),
("privacy_mode_impl_mag_tip", "Modo 1 (deprecato)"),
("privacy_mode_impl_virtual_display_tip", "Modo 2 (consigliato)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Entra in modalità privacy"),
("Exit privacy mode", "Esci dalla modalità privacy"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "입력된 ID, IP, 도메인과 포트(<domain>:<port>)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(<id>@<server_address>?key=<key_value>)를 추가하세요"),
("privacy_mode_impl_mag_tip", "모드 1(더 이상 사용되지 않음)"),
("privacy_mode_impl_virtual_display_tip", "모드 2(권장)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "개인정보 보호 모드 사용"),
("Exit privacy mode", "개인정보 보호 모드 종료"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Varat ievadīt ID, tiešo IP vai domēnu ar portu (<domēns>:<ports>).\nJa vēlaties piekļūt ierīcei citā serverī, lūdzu, pievienojiet servera adresi (<id>@<servera_adrese>?key=<atslēgas_vērtība>), piemēram,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJa vēlaties piekļūt ierīcei publiskajā serverī, lūdzu, ievadiet \"<id>@public\", publiskajam serverim atslēga nav nepieciešama"),
("privacy_mode_impl_mag_tip", "1. režīms (novecojis)"),
("privacy_mode_impl_virtual_display_tip", "2. režīms (ieteicams)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Ieiet privātuma režīmā"),
("Exit privacy mode", "Iziet no privātuma režīma"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Je kunt een ID, een direct IP of een domein met een poort (<domein>:<poort>) invoeren. Als je toegang wilt als apparaat op een andere server, voeg dan het serveradres toe (<id>@<server_adres>?key=<key_value>), bijvoorbeeld \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.Als je toegang wilt als apparaat op een openbare server, voer dan \"<id>@public\" in, voor de openbare server is de sleutel niet nodig."),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Możesz wprowadzić identyfikator, bezpośredni adres IP lub domenę z portem (<adres_domenowy>:<port>).\nJeżeli chcesz uzyskać dostęp do urządzenia na innym serwerze, dołącz adres serwera (<id>@<adres_serwera>?key=<wartość_klucza>, np. \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJeżeli chcesz uzyskać dostęp do urządzenia na serwerze publicznym, wpisz \"<id>@public\", klucz nie jest potrzebny dla serwera publicznego."),
("privacy_mode_impl_mag_tip", "Tryb 1 (przestarzały)"),
("privacy_mode_impl_virtual_display_tip", "Tryb 2 (zalecany)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Wejdź w tryb prywatności"),
("Exit privacy mode", "Wyjdź z trybu prywatności"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Можно ввести идентификатор, прямой IP-адрес или домен с портом (<домен>:<порт>).\nЕсли необходимо получить доступ к устройству на другом сервере, добавьте адрес сервера (<id>@<адрес_сервера>?key=<ключ_значение>), например:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЕсли необходимо получить доступ к устройству на общедоступном сервере, введите \"<id>@public\", ключ для публичного сервера не требуется."),
("privacy_mode_impl_mag_tip", "Режим 1 (устаревший)"),
("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендуемый)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", "Включить режим конфиденциальности"),
("Exit privacy mode", "Отключить режим конфиденциальности"),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "Môžete zadať ID, priamu IP adresu alebo doménu s portom (<doména>:<port>).\nAk chcete získať prístup k zariadeniu na inom serveri, doplňte adresu servera (<id>@<adresa_servera>?key=<hodnota_kľúča>), napríklad,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nAk chcete získať prístup k zariadeniu na verejnom serveri, zadajte \"<id>@public\", kľúč nie je potrebný pre verejný server."),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -569,6 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Enable blocking user input", "Блокувати введення для користувача"),
("id_input_tip", "Ви можете ввести ID, безпосередню IP, або ж домен з портом (<домен>:<порт>).\nЯкщо ви хочете отримати доступ до пристрою на іншому сервері, будь ласка, додайте адресу сервера (<id>@<адреса_сервера>?key=<значення_ключа>), наприклад,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЯкщо ви хочете отримати доступ до пристрою на публічному сервері, будь ласка, введіть \"<id>@public\", ключ для публічного сервера не потрібен."),
("privacy_mode_impl_mag_tip", "Режим 1 (застарілий)"),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендований)"),
("Enter privacy mode", "Увійти в режим конфіденційності"),
("Exit privacy mode", "Вийти з режиму конфіденційності"),

View File

@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", ""),
("privacy_mode_impl_mag_tip", ""),
("privacy_mode_impl_virtual_display_tip", ""),
("privacy_mode_impl_exclude_from_capture_tip", ""),
("Enter privacy mode", ""),
("Exit privacy mode", ""),
].iter().cloned().collect();

View File

@ -3,7 +3,7 @@ use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY;
use crate::{
ipc,
license::*,
privacy_mode::win_mag::{self, WIN_MAG_INJECTED_PROCESS_EXE},
privacy_mode::win_topmost_window::{self, WIN_TOPMOST_INJECTED_PROCESS_EXE},
};
use hbb_common::{
allow_err,
@ -848,8 +848,8 @@ fn get_default_install_path() -> String {
}
pub fn check_update_broker_process() -> ResultType<()> {
let process_exe = win_mag::INJECTED_PROCESS_EXE;
let origin_process_exe = win_mag::ORIGIN_PROCESS_EXE;
let process_exe = win_topmost_window::INJECTED_PROCESS_EXE;
let origin_process_exe = win_topmost_window::ORIGIN_PROCESS_EXE;
let exe_file = std::env::current_exe()?;
let Some(cur_dir) = exe_file.parent() else {
@ -926,8 +926,8 @@ pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> ResultType<String>
{main_exe}
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
",
ORIGIN_PROCESS_EXE = win_mag::ORIGIN_PROCESS_EXE,
broker_exe = win_mag::INJECTED_PROCESS_EXE,
ORIGIN_PROCESS_EXE = win_topmost_window::ORIGIN_PROCESS_EXE,
broker_exe = win_topmost_window::INJECTED_PROCESS_EXE,
))
}
@ -1157,7 +1157,7 @@ fn get_before_uninstall(kill_self: bool) -> String {
reg delete HKEY_CLASSES_ROOT\\{ext} /f
netsh advfirewall firewall delete rule name=\"{app_name} Service\"
",
broker_exe = WIN_MAG_INJECTED_PROCESS_EXE,
broker_exe = WIN_TOPMOST_INJECTED_PROCESS_EXE,
)
}
@ -2164,7 +2164,7 @@ pub fn uninstall_service(show_new_window: bool) -> bool {
taskkill /F /IM {app_name}.exe{filter}
",
app_name = crate::get_app_name(),
broker_exe = WIN_MAG_INJECTED_PROCESS_EXE,
broker_exe = WIN_TOPMOST_INJECTED_PROCESS_EXE,
);
if let Err(err) = run_cmds(cmds, false, "uninstall") {
Config::set_option("stop-service".into(), "".into());
@ -2279,7 +2279,10 @@ fn run_after_run_cmds(silent: bool) {
pub fn try_kill_broker() {
allow_err!(std::process::Command::new("cmd")
.arg("/c")
.arg(&format!("taskkill /F /IM {}", WIN_MAG_INJECTED_PROCESS_EXE))
.arg(&format!(
"taskkill /F /IM {}",
WIN_TOPMOST_INJECTED_PROCESS_EXE
))
.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW)
.spawn());
}

View File

@ -15,11 +15,14 @@ use std::{
sync::{Arc, Mutex},
};
#[cfg(windows)]
pub mod win_exclude_from_capture;
#[cfg(windows)]
mod win_input;
#[cfg(windows)]
pub mod win_mag;
#[cfg(windows)]
pub mod win_topmost_window;
#[cfg(all(windows, feature = "virtual_display_driver"))]
mod win_virtual_display;
@ -34,6 +37,9 @@ pub const NO_DISPLAYS: &'static str = "No displays";
#[cfg(windows)]
pub const PRIVACY_MODE_IMPL_WIN_MAG: &str = win_mag::PRIVACY_MODE_IMPL;
#[cfg(windows)]
pub const PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE: &str =
win_exclude_from_capture::PRIVACY_MODE_IMPL;
#[cfg(all(windows, feature = "virtual_display_driver"))]
pub const PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY: &str = win_virtual_display::PRIVACY_MODE_IMPL;
@ -84,22 +90,23 @@ lazy_static::lazy_static! {
pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = {
#[cfg(windows)]
{
if display_service::is_privacy_mode_mag_supported() {
PRIVACY_MODE_IMPL_WIN_MAG
} else {
#[cfg(feature = "virtual_display_driver")]
{
if is_installed() {
PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY
} else {
""
}
}
#[cfg(not(feature = "virtual_display_driver"))]
{
""
}
}.to_owned()
PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE.to_owned()
// if display_service::is_privacy_mode_mag_supported() {
// PRIVACY_MODE_IMPL_WIN_MAG
// } else {
// #[cfg(feature = "virtual_display_driver")]
// {
// if is_installed() {
// PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY
// } else {
// ""
// }
// }
// #[cfg(not(feature = "virtual_display_driver"))]
// {
// ""
// }
// }.to_owned()
}
#[cfg(not(windows))]
{
@ -137,6 +144,10 @@ lazy_static::lazy_static! {
Box::new(win_mag::PrivacyModeImpl::default())
});
map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, || {
Box::new(win_exclude_from_capture::PrivacyModeImpl::default())
});
#[cfg(feature = "virtual_display_driver")]
map.insert(win_virtual_display::PRIVACY_MODE_IMPL, || {
Box::new(win_virtual_display::PrivacyModeImpl::default())
@ -272,6 +283,10 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> {
if display_service::is_privacy_mode_mag_supported() {
vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip"));
}
vec_impls.push((
PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE,
"privacy_mode_impl_exclude_from_capture_tip",
));
#[cfg(feature = "virtual_display_driver")]
if is_installed() {
vec_impls.push((

View File

@ -0,0 +1,3 @@
pub use super::win_topmost_window::PrivacyModeImpl;
pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_exclude_from_capture";

View File

@ -1,370 +1,11 @@
use super::{PrivacyMode, INVALID_PRIVACY_MODE_CONN_ID};
use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState};
use hbb_common::{allow_err, bail, log, ResultType};
use std::{
ffi::CString,
time::{Duration, Instant},
};
use winapi::{
shared::{
minwindef::FALSE,
ntdef::{HANDLE, NULL},
windef::HWND,
},
um::{
errhandlingapi::GetLastError,
handleapi::CloseHandle,
libloaderapi::{GetModuleHandleA, GetProcAddress},
memoryapi::{VirtualAllocEx, WriteProcessMemory},
processthreadsapi::{
CreateProcessAsUserW, QueueUserAPC, ResumeThread, TerminateProcess,
PROCESS_INFORMATION, STARTUPINFOW,
},
winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS},
winnt::{MEM_COMMIT, PAGE_READWRITE},
winuser::*,
},
};
use super::win_topmost_window::PRIVACY_WINDOW_NAME;
use hbb_common::{bail, log, ResultType};
use std::time::Instant;
pub use super::win_topmost_window::PrivacyModeImpl;
pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_mag";
pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe";
pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe";
pub const INJECTED_PROCESS_EXE: &'static str = WIN_MAG_INJECTED_PROCESS_EXE;
const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow";
struct WindowHandlers {
hthread: u64,
hprocess: u64,
}
impl Drop for WindowHandlers {
fn drop(&mut self) {
self.reset();
}
}
impl WindowHandlers {
fn reset(&mut self) {
unsafe {
if self.hprocess != 0 {
let _res = TerminateProcess(self.hprocess as _, 0);
CloseHandle(self.hprocess as _);
}
self.hprocess = 0;
if self.hthread != 0 {
CloseHandle(self.hthread as _);
}
self.hthread = 0;
}
}
fn is_default(&self) -> bool {
self.hthread == 0 && self.hprocess == 0
}
}
pub struct PrivacyModeImpl {
conn_id: i32,
handlers: WindowHandlers,
}
impl Default for PrivacyModeImpl {
fn default() -> Self {
Self {
conn_id: INVALID_PRIVACY_MODE_CONN_ID,
handlers: WindowHandlers {
hthread: 0,
hprocess: 0,
},
}
}
}
impl PrivacyMode for PrivacyModeImpl {
fn init(&self) -> ResultType<()> {
Ok(())
}
fn clear(&mut self) {
allow_err!(self.turn_off_privacy(self.conn_id, None));
}
fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType<bool> {
if self.check_on_conn_id(conn_id)? {
log::debug!("Privacy mode of conn {} is already on", conn_id);
return Ok(true);
}
let exe_file = std::env::current_exe()?;
if let Some(cur_dir) = exe_file.parent() {
if !cur_dir.join("WindowInjection.dll").exists() {
return Ok(false);
}
} else {
bail!(
"Invalid exe parent for {}",
exe_file.to_string_lossy().as_ref()
);
}
if self.handlers.is_default() {
log::info!("turn_on_privacy, dll not found when started, try start");
self.start()?;
std::thread::sleep(std::time::Duration::from_millis(1_000));
}
let hwnd = wait_find_privacy_hwnd(0)?;
if hwnd.is_null() {
bail!("No privacy window created");
}
super::win_input::hook()?;
unsafe {
ShowWindow(hwnd as _, SW_SHOW);
}
self.conn_id = conn_id;
Ok(true)
}
fn turn_off_privacy(
&mut self,
conn_id: i32,
state: Option<PrivacyModeState>,
) -> ResultType<()> {
self.check_off_conn_id(conn_id)?;
super::win_input::unhook()?;
unsafe {
let hwnd = wait_find_privacy_hwnd(0)?;
if !hwnd.is_null() {
ShowWindow(hwnd, SW_HIDE);
}
}
if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID {
if let Some(state) = state {
allow_err!(super::set_privacy_mode_state(
conn_id,
state,
PRIVACY_MODE_IMPL.to_string(),
1_000
));
}
self.conn_id = INVALID_PRIVACY_MODE_CONN_ID.to_owned();
}
Ok(())
}
#[inline]
fn pre_conn_id(&self) -> i32 {
self.conn_id
}
}
impl PrivacyModeImpl {
pub fn start(&mut self) -> ResultType<()> {
if self.handlers.hprocess != 0 {
return Ok(());
}
log::info!("Start privacy mode window broker, check_update_broker_process");
if let Err(e) = crate::platform::windows::check_update_broker_process() {
log::warn!(
"Failed to check update broker process. Privacy mode may not work properly. {}",
e
);
}
let exe_file = std::env::current_exe()?;
let Some(cur_dir) = exe_file.parent() else {
bail!("Cannot get parent of current exe file");
};
let dll_file = cur_dir.join("WindowInjection.dll");
if !dll_file.exists() {
bail!(
"Failed to find required file {}",
dll_file.to_string_lossy().as_ref()
);
}
let hwnd = wait_find_privacy_hwnd(1_000)?;
if !hwnd.is_null() {
log::info!("Privacy window is ready");
return Ok(());
}
// let cmdline = cur_dir.join("MiniBroker.exe").to_string_lossy().to_string();
let cmdline = cur_dir
.join(INJECTED_PROCESS_EXE)
.to_string_lossy()
.to_string();
unsafe {
let cmd_utf16: Vec<u16> = cmdline.encode_utf16().chain(Some(0).into_iter()).collect();
let mut start_info = STARTUPINFOW {
cb: 0,
lpReserved: NULL as _,
lpDesktop: NULL as _,
lpTitle: NULL as _,
dwX: 0,
dwY: 0,
dwXSize: 0,
dwYSize: 0,
dwXCountChars: 0,
dwYCountChars: 0,
dwFillAttribute: 0,
dwFlags: 0,
wShowWindow: 0,
cbReserved2: 0,
lpReserved2: NULL as _,
hStdInput: NULL as _,
hStdOutput: NULL as _,
hStdError: NULL as _,
};
let mut proc_info = PROCESS_INFORMATION {
hProcess: NULL as _,
hThread: NULL as _,
dwProcessId: 0,
dwThreadId: 0,
};
let session_id = WTSGetActiveConsoleSessionId();
let token = get_user_token(session_id, true);
if token.is_null() {
bail!("Failed to get token of current user");
}
let create_res = CreateProcessAsUserW(
token,
NULL as _,
cmd_utf16.as_ptr() as _,
NULL as _,
NULL as _,
FALSE,
CREATE_SUSPENDED | DETACHED_PROCESS,
NULL,
NULL as _,
&mut start_info,
&mut proc_info,
);
CloseHandle(token);
if 0 == create_res {
bail!(
"Failed to create privacy window process {}, code {}",
cmdline,
GetLastError()
);
};
inject_dll(
proc_info.hProcess,
proc_info.hThread,
dll_file.to_string_lossy().as_ref(),
)?;
if 0xffffffff == ResumeThread(proc_info.hThread) {
// CloseHandle
CloseHandle(proc_info.hThread);
CloseHandle(proc_info.hProcess);
bail!(
"Failed to create privacy window process, {}",
GetLastError()
);
}
self.handlers.hthread = proc_info.hThread as _;
self.handlers.hprocess = proc_info.hProcess as _;
let hwnd = wait_find_privacy_hwnd(1_000)?;
if hwnd.is_null() {
bail!("Failed to get hwnd after started");
}
}
Ok(())
}
#[inline]
pub fn stop(&mut self) {
self.handlers.reset();
}
}
impl Drop for PrivacyModeImpl {
fn drop(&mut self) {
if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID {
allow_err!(self.turn_off_privacy(self.conn_id, None));
}
}
}
unsafe fn inject_dll<'a>(hproc: HANDLE, hthread: HANDLE, dll_file: &'a str) -> ResultType<()> {
let dll_file_utf16: Vec<u16> = dll_file.encode_utf16().chain(Some(0).into_iter()).collect();
let buf = VirtualAllocEx(
hproc,
NULL as _,
dll_file_utf16.len() * 2,
MEM_COMMIT,
PAGE_READWRITE,
);
if buf.is_null() {
bail!("Failed VirtualAllocEx");
}
let mut written: usize = 0;
if 0 == WriteProcessMemory(
hproc,
buf,
dll_file_utf16.as_ptr() as _,
dll_file_utf16.len() * 2,
&mut written,
) {
bail!("Failed WriteProcessMemory");
}
let kernel32_modulename = CString::new("kernel32")?;
let hmodule = GetModuleHandleA(kernel32_modulename.as_ptr() as _);
if hmodule.is_null() {
bail!("Failed GetModuleHandleA");
}
let load_librarya_name = CString::new("LoadLibraryW")?;
let load_librarya = GetProcAddress(hmodule, load_librarya_name.as_ptr() as _);
if load_librarya.is_null() {
bail!("Failed GetProcAddress of LoadLibraryW");
}
if 0 == QueueUserAPC(Some(std::mem::transmute(load_librarya)), hthread, buf as _) {
bail!("Failed QueueUserAPC");
}
Ok(())
}
fn wait_find_privacy_hwnd(msecs: u128) -> ResultType<HWND> {
let tm_begin = Instant::now();
let wndname = CString::new(PRIVACY_WINDOW_NAME)?;
loop {
unsafe {
let hwnd = FindWindowA(NULL as _, wndname.as_ptr() as _);
if !hwnd.is_null() {
return Ok(hwnd);
}
}
if msecs == 0 || tm_begin.elapsed().as_millis() > msecs {
return Ok(NULL as _);
}
std::thread::sleep(Duration::from_millis(100));
}
}
pub fn create_capturer(
privacy_mode_id: i32,
origin: (i32, i32),

View File

@ -0,0 +1,375 @@
use super::{PrivacyMode, INVALID_PRIVACY_MODE_CONN_ID};
use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState};
use hbb_common::{allow_err, bail, log, ResultType};
use std::{
ffi::CString,
time::{Duration, Instant},
};
use winapi::{
shared::{
minwindef::FALSE,
ntdef::{HANDLE, NULL},
windef::HWND,
},
um::{
errhandlingapi::GetLastError,
handleapi::CloseHandle,
libloaderapi::{GetModuleHandleA, GetProcAddress},
memoryapi::{VirtualAllocEx, WriteProcessMemory},
processthreadsapi::{
CreateProcessAsUserW, QueueUserAPC, ResumeThread, TerminateProcess,
PROCESS_INFORMATION, STARTUPINFOW,
},
winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS},
winnt::{MEM_COMMIT, PAGE_READWRITE},
winuser::*,
},
};
pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_mag";
pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe";
pub const WIN_TOPMOST_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe";
pub const INJECTED_PROCESS_EXE: &'static str = WIN_TOPMOST_INJECTED_PROCESS_EXE;
pub(super) const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow";
struct WindowHandlers {
hthread: u64,
hprocess: u64,
}
impl Drop for WindowHandlers {
fn drop(&mut self) {
self.reset();
}
}
impl WindowHandlers {
fn reset(&mut self) {
unsafe {
if self.hprocess != 0 {
let _res = TerminateProcess(self.hprocess as _, 0);
CloseHandle(self.hprocess as _);
}
self.hprocess = 0;
if self.hthread != 0 {
CloseHandle(self.hthread as _);
}
self.hthread = 0;
}
}
fn is_default(&self) -> bool {
self.hthread == 0 && self.hprocess == 0
}
}
pub struct PrivacyModeImpl {
conn_id: i32,
handlers: WindowHandlers,
hwnd: u64,
}
impl Default for PrivacyModeImpl {
fn default() -> Self {
Self {
conn_id: INVALID_PRIVACY_MODE_CONN_ID,
handlers: WindowHandlers {
hthread: 0,
hprocess: 0,
},
hwnd: 0,
}
}
}
impl PrivacyMode for PrivacyModeImpl {
fn init(&self) -> ResultType<()> {
Ok(())
}
fn clear(&mut self) {
allow_err!(self.turn_off_privacy(self.conn_id, None));
}
fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType<bool> {
if self.check_on_conn_id(conn_id)? {
log::debug!("Privacy mode of conn {} is already on", conn_id);
return Ok(true);
}
let exe_file = std::env::current_exe()?;
if let Some(cur_dir) = exe_file.parent() {
if !cur_dir.join("WindowInjection.dll").exists() {
return Ok(false);
}
} else {
bail!(
"Invalid exe parent for {}",
exe_file.to_string_lossy().as_ref()
);
}
if self.handlers.is_default() {
log::info!("turn_on_privacy, dll not found when started, try start");
self.start()?;
std::thread::sleep(std::time::Duration::from_millis(1_000));
}
let hwnd = wait_find_privacy_hwnd(0)?;
if hwnd.is_null() {
bail!("No privacy window created");
}
super::win_input::hook()?;
unsafe {
ShowWindow(hwnd as _, SW_SHOW);
}
self.conn_id = conn_id;
self.hwnd = hwnd as _;
Ok(true)
}
fn turn_off_privacy(
&mut self,
conn_id: i32,
state: Option<PrivacyModeState>,
) -> ResultType<()> {
self.check_off_conn_id(conn_id)?;
super::win_input::unhook()?;
unsafe {
let hwnd = wait_find_privacy_hwnd(0)?;
if !hwnd.is_null() {
ShowWindow(hwnd, SW_HIDE);
}
}
if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID {
if let Some(state) = state {
allow_err!(super::set_privacy_mode_state(
conn_id,
state,
PRIVACY_MODE_IMPL.to_string(),
1_000
));
}
self.conn_id = INVALID_PRIVACY_MODE_CONN_ID.to_owned();
}
Ok(())
}
#[inline]
fn pre_conn_id(&self) -> i32 {
self.conn_id
}
}
impl PrivacyModeImpl {
#[inline]
pub fn get_hwnd(&self) -> u64 {
self.hwnd
}
pub fn start(&mut self) -> ResultType<()> {
if self.handlers.hprocess != 0 {
return Ok(());
}
log::info!("Start privacy mode window broker, check_update_broker_process");
if let Err(e) = crate::platform::windows::check_update_broker_process() {
log::warn!(
"Failed to check update broker process. Privacy mode may not work properly. {}",
e
);
}
let exe_file = std::env::current_exe()?;
let Some(cur_dir) = exe_file.parent() else {
bail!("Cannot get parent of current exe file");
};
let dll_file = cur_dir.join("WindowInjection.dll");
if !dll_file.exists() {
bail!(
"Failed to find required file {}",
dll_file.to_string_lossy().as_ref()
);
}
let hwnd = wait_find_privacy_hwnd(1_000)?;
if !hwnd.is_null() {
log::info!("Privacy window is ready");
return Ok(());
}
// let cmdline = cur_dir.join("MiniBroker.exe").to_string_lossy().to_string();
let cmdline = cur_dir
.join(INJECTED_PROCESS_EXE)
.to_string_lossy()
.to_string();
unsafe {
let cmd_utf16: Vec<u16> = cmdline.encode_utf16().chain(Some(0).into_iter()).collect();
let mut start_info = STARTUPINFOW {
cb: 0,
lpReserved: NULL as _,
lpDesktop: NULL as _,
lpTitle: NULL as _,
dwX: 0,
dwY: 0,
dwXSize: 0,
dwYSize: 0,
dwXCountChars: 0,
dwYCountChars: 0,
dwFillAttribute: 0,
dwFlags: 0,
wShowWindow: 0,
cbReserved2: 0,
lpReserved2: NULL as _,
hStdInput: NULL as _,
hStdOutput: NULL as _,
hStdError: NULL as _,
};
let mut proc_info = PROCESS_INFORMATION {
hProcess: NULL as _,
hThread: NULL as _,
dwProcessId: 0,
dwThreadId: 0,
};
let session_id = WTSGetActiveConsoleSessionId();
let token = get_user_token(session_id, true);
if token.is_null() {
bail!("Failed to get token of current user");
}
let create_res = CreateProcessAsUserW(
token,
NULL as _,
cmd_utf16.as_ptr() as _,
NULL as _,
NULL as _,
FALSE,
CREATE_SUSPENDED | DETACHED_PROCESS,
NULL,
NULL as _,
&mut start_info,
&mut proc_info,
);
CloseHandle(token);
if 0 == create_res {
bail!(
"Failed to create privacy window process {}, code {}",
cmdline,
GetLastError()
);
};
inject_dll(
proc_info.hProcess,
proc_info.hThread,
dll_file.to_string_lossy().as_ref(),
)?;
if 0xffffffff == ResumeThread(proc_info.hThread) {
// CloseHandle
CloseHandle(proc_info.hThread);
CloseHandle(proc_info.hProcess);
bail!(
"Failed to create privacy window process, {}",
GetLastError()
);
}
self.handlers.hthread = proc_info.hThread as _;
self.handlers.hprocess = proc_info.hProcess as _;
let hwnd = wait_find_privacy_hwnd(1_000)?;
if hwnd.is_null() {
bail!("Failed to get hwnd after started");
}
}
Ok(())
}
#[inline]
pub fn stop(&mut self) {
self.handlers.reset();
}
}
impl Drop for PrivacyModeImpl {
fn drop(&mut self) {
if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID {
allow_err!(self.turn_off_privacy(self.conn_id, None));
}
}
}
unsafe fn inject_dll<'a>(hproc: HANDLE, hthread: HANDLE, dll_file: &'a str) -> ResultType<()> {
let dll_file_utf16: Vec<u16> = dll_file.encode_utf16().chain(Some(0).into_iter()).collect();
let buf = VirtualAllocEx(
hproc,
NULL as _,
dll_file_utf16.len() * 2,
MEM_COMMIT,
PAGE_READWRITE,
);
if buf.is_null() {
bail!("Failed VirtualAllocEx");
}
let mut written: usize = 0;
if 0 == WriteProcessMemory(
hproc,
buf,
dll_file_utf16.as_ptr() as _,
dll_file_utf16.len() * 2,
&mut written,
) {
bail!("Failed WriteProcessMemory");
}
let kernel32_modulename = CString::new("kernel32")?;
let hmodule = GetModuleHandleA(kernel32_modulename.as_ptr() as _);
if hmodule.is_null() {
bail!("Failed GetModuleHandleA");
}
let load_librarya_name = CString::new("LoadLibraryW")?;
let load_librarya = GetProcAddress(hmodule, load_librarya_name.as_ptr() as _);
if load_librarya.is_null() {
bail!("Failed GetProcAddress of LoadLibraryW");
}
if 0 == QueueUserAPC(Some(std::mem::transmute(load_librarya)), hthread, buf as _) {
bail!("Failed QueueUserAPC");
}
Ok(())
}
pub(super) fn wait_find_privacy_hwnd(msecs: u128) -> ResultType<HWND> {
let tm_begin = Instant::now();
let wndname = CString::new(PRIVACY_WINDOW_NAME)?;
loop {
unsafe {
let hwnd = FindWindowA(NULL as _, wndname.as_ptr() as _);
if !hwnd.is_null() {
return Ok(hwnd);
}
}
if msecs == 0 || tm_begin.elapsed().as_millis() > msecs {
return Ok(NULL as _);
}
std::thread::sleep(Duration::from_millis(100));
}
}