Merge pull request #6470 from fufesou/feat/topmost_window_exclude_from_capture
Feat/topmost window exclude from capture
This commit is contained in:
commit
b535722421
6
build.py
6
build.py
@ -57,9 +57,9 @@ def parse_rc_features(feature):
|
|||||||
},
|
},
|
||||||
'PrivacyMode': {
|
'PrivacyMode': {
|
||||||
'platform': ['windows'],
|
'platform': ['windows'],
|
||||||
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2'
|
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3'
|
||||||
'/TempTopMostWindow_x64_pic_en.zip',
|
'/TempTopMostWindow_x64.zip',
|
||||||
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2/checksum_md5',
|
'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3/checksum_md5',
|
||||||
'include': ['WindowInjection.dll'],
|
'include': ['WindowInjection.dll'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,11 +94,11 @@ mod windows {
|
|||||||
|
|
||||||
// Used for privacy mode(magnifier impl).
|
// Used for privacy mode(magnifier impl).
|
||||||
pub const RUNTIME_BROKER_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe";
|
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) {
|
pub(super) fn copy_runtime_broker(dir: &PathBuf) {
|
||||||
let src = RUNTIME_BROKER_EXE;
|
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);
|
let target_file = dir.join(tgt);
|
||||||
if target_file.exists() {
|
if target_file.exists() {
|
||||||
if let (Ok(src_file), Ok(tgt_file)) = (fs::read(src), fs::read(&target_file)) {
|
if let (Ok(src_file), Ok(tgt_file)) = (fs::read(src), fs::read(&target_file)) {
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "真彩模式(4:4:4)"),
|
("True color (4:4:4)", "真彩模式(4:4:4)"),
|
||||||
("Enable blocking user input", "允许阻止用户输入"),
|
("Enable blocking user input", "允许阻止用户输入"),
|
||||||
("id_input_tip", ""),
|
("id_input_tip", ""),
|
||||||
("privacy_mode_impl_mag_tip", "模式 1 (不推荐)"),
|
("privacy_mode_impl_mag_tip", "模式 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"),
|
("privacy_mode_impl_virtual_display_tip", "模式 2"),
|
||||||
("Enter privacy mode", "进入隐私模式"),
|
("Enter privacy mode", "进入隐私模式"),
|
||||||
("Exit privacy mode", "退出隐私模式"),
|
("Exit privacy mode", "退出隐私模式"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -203,7 +203,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."),
|
("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."),
|
||||||
("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly as controlled side."),
|
("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly as controlled side."),
|
||||||
("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"),
|
("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_mag_tip", "Mode 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"),
|
("privacy_mode_impl_virtual_display_tip", "Mode 2"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "Color real (4:4:4)"),
|
("True color (4:4:4)", "Color real (4:4:4)"),
|
||||||
("Enable blocking user input", "Habilitar el bloqueo de la entrada del usuario"),
|
("Enable blocking user input", "Habilitar el bloqueo de la entrada del usuario"),
|
||||||
("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."),
|
("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_mag_tip", "Modo 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Modo 2 (recomendado)"),
|
("privacy_mode_impl_virtual_display_tip", "Modo 2"),
|
||||||
("Enter privacy mode", "Entrar al modo privado"),
|
("Enter privacy mode", "Entrar al modo privado"),
|
||||||
("Exit privacy mode", "Salir del modo privado"),
|
("Exit privacy mode", "Salir del modo privado"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", ""),
|
("True color (4:4:4)", ""),
|
||||||
("Enable blocking user input", "Aktifkan pemblokiran input pengguna"),
|
("Enable blocking user input", "Aktifkan pemblokiran input pengguna"),
|
||||||
("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"),
|
("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_mag_tip", "Mode 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Mode 2 (direkomendasikan)"),
|
("privacy_mode_impl_virtual_display_tip", "Mode 2"),
|
||||||
("Enter privacy mode", "Masuk mode privasi"),
|
("Enter privacy mode", "Masuk mode privasi"),
|
||||||
("Exit privacy mode", "Keluar mode privasi"),
|
("Exit privacy mode", "Keluar mode privasi"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "Colore reale (4:4:4)"),
|
("True color (4:4:4)", "Colore reale (4:4:4)"),
|
||||||
("Enable blocking user input", "Abilita blocco input utente"),
|
("Enable blocking user input", "Abilita blocco input utente"),
|
||||||
("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"),
|
("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_mag_tip", "Modo 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Modo 2 (consigliato)"),
|
("privacy_mode_impl_virtual_display_tip", "Modo 2"),
|
||||||
("Enter privacy mode", "Entra in modalità privacy"),
|
("Enter privacy mode", "Entra in modalità privacy"),
|
||||||
("Exit privacy mode", "Esci dalla modalità privacy"),
|
("Exit privacy mode", "Esci dalla modalità privacy"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "트루컬러(4:4:4)"),
|
("True color (4:4:4)", "트루컬러(4:4:4)"),
|
||||||
("Enable blocking user input", "사용자 입력 차단 허용"),
|
("Enable blocking user input", "사용자 입력 차단 허용"),
|
||||||
("id_input_tip", "입력된 ID, IP, 도메인과 포트(<domain>:<port>)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(<id>@<server_address>?key=<key_value>)를 추가하세요"),
|
("id_input_tip", "입력된 ID, IP, 도메인과 포트(<domain>:<port>)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(<id>@<server_address>?key=<key_value>)를 추가하세요"),
|
||||||
("privacy_mode_impl_mag_tip", "모드 1(더 이상 사용되지 않음)"),
|
("privacy_mode_impl_mag_tip", "모드 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "모드 2(권장)"),
|
("privacy_mode_impl_virtual_display_tip", "모드 2"),
|
||||||
("Enter privacy mode", "개인정보 보호 모드 사용"),
|
("Enter privacy mode", "개인정보 보호 모드 사용"),
|
||||||
("Exit privacy mode", "개인정보 보호 모드 종료"),
|
("Exit privacy mode", "개인정보 보호 모드 종료"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "Īstā krāsa (4:4:4)"),
|
("True color (4:4:4)", "Īstā krāsa (4:4:4)"),
|
||||||
("Enable blocking user input", "Iespējot lietotāja ievades bloķēšanu"),
|
("Enable blocking user input", "Iespējot lietotāja ievades bloķēšanu"),
|
||||||
("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"),
|
("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_mag_tip", "1. režīms"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "2. režīms (ieteicams)"),
|
("privacy_mode_impl_virtual_display_tip", "2. režīms"),
|
||||||
("Enter privacy mode", "Ieiet privātuma režīmā"),
|
("Enter privacy mode", "Ieiet privātuma režīmā"),
|
||||||
("Exit privacy mode", "Iziet no privātuma režīma"),
|
("Exit privacy mode", "Iziet no privātuma režīma"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "True color (4:4:4)"),
|
("True color (4:4:4)", "True color (4:4:4)"),
|
||||||
("Enable blocking user input", "Zablokuj wprowadzanie danych przez użytkownika"),
|
("Enable blocking user input", "Zablokuj wprowadzanie danych przez użytkownika"),
|
||||||
("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."),
|
("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_mag_tip", "Tryb 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Tryb 2 (zalecany)"),
|
("privacy_mode_impl_virtual_display_tip", "Tryb 2"),
|
||||||
("Enter privacy mode", "Wejdź w tryb prywatności"),
|
("Enter privacy mode", "Wejdź w tryb prywatności"),
|
||||||
("Exit privacy mode", "Wyjdź z trybu prywatności"),
|
("Exit privacy mode", "Wyjdź z trybu prywatności"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "True color (4:4:4)"),
|
("True color (4:4:4)", "True color (4:4:4)"),
|
||||||
("Enable blocking user input", "Блокировать ввод пользователя"),
|
("Enable blocking user input", "Блокировать ввод пользователя"),
|
||||||
("id_input_tip", "Можно ввести идентификатор, прямой IP-адрес или домен с портом (<домен>:<порт>).\nЕсли необходимо получить доступ к устройству на другом сервере, добавьте адрес сервера (<id>@<адрес_сервера>?key=<ключ_значение>), например:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЕсли необходимо получить доступ к устройству на общедоступном сервере, введите \"<id>@public\", ключ для публичного сервера не требуется."),
|
("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_mag_tip", "Режим 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендуемый)"),
|
("privacy_mode_impl_virtual_display_tip", "Режим 2"),
|
||||||
("Enter privacy mode", "Включить режим конфиденциальности"),
|
("Enter privacy mode", "Включить режим конфиденциальности"),
|
||||||
("Exit privacy mode", "Отключить режим конфиденциальности"),
|
("Exit privacy mode", "Отключить режим конфиденциальности"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -568,8 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("True color (4:4:4)", "Спражній колір (4:4:4)"),
|
("True color (4:4:4)", "Спражній колір (4:4:4)"),
|
||||||
("Enable blocking user input", "Блокувати введення для користувача"),
|
("Enable blocking user input", "Блокувати введення для користувача"),
|
||||||
("id_input_tip", "Ви можете ввести ID, безпосередню IP, або ж домен з портом (<домен>:<порт>).\nЯкщо ви хочете отримати доступ до пристрою на іншому сервері, будь ласка, додайте адресу сервера (<id>@<адреса_сервера>?key=<значення_ключа>), наприклад,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЯкщо ви хочете отримати доступ до пристрою на публічному сервері, будь ласка, введіть \"<id>@public\", ключ для публічного сервера не потрібен."),
|
("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_mag_tip", "Режим 1"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендований)"),
|
("privacy_mode_impl_virtual_display_tip", "Режим 2"),
|
||||||
("Enter privacy mode", "Увійти в режим конфіденційності"),
|
("Enter privacy mode", "Увійти в режим конфіденційності"),
|
||||||
("Exit privacy mode", "Вийти з режиму конфіденційності"),
|
("Exit privacy mode", "Вийти з режиму конфіденційності"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
|
@ -628,8 +628,48 @@ extern "C"
|
|||||||
return bSystem;
|
return bSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void alloc_console_and_redirect() {
|
void alloc_console_and_redirect()
|
||||||
|
{
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
freopen("CONOUT$", "w", stdout);
|
freopen("CONOUT$", "w", stdout);
|
||||||
}
|
}
|
||||||
} // end of extern "C"
|
} // end of extern "C"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
|
||||||
|
// https://github.com/nodejs/node-convergence-archive/blob/e11fe0c2777561827cdb7207d46b0917ef3c42a7/deps/uv/src/win/util.c#L780
|
||||||
|
BOOL IsWindowsVersionOrGreater(DWORD os_major,
|
||||||
|
DWORD os_minor,
|
||||||
|
DWORD build_number,
|
||||||
|
WORD service_pack_major,
|
||||||
|
WORD service_pack_minor)
|
||||||
|
{
|
||||||
|
OSVERSIONINFOEX osvi;
|
||||||
|
DWORDLONG condition_mask = 0;
|
||||||
|
int op = VER_GREATER_EQUAL;
|
||||||
|
|
||||||
|
/* Initialize the OSVERSIONINFOEX structure. */
|
||||||
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
||||||
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||||
|
osvi.dwMajorVersion = os_major;
|
||||||
|
osvi.dwMinorVersion = os_minor;
|
||||||
|
osvi.dwBuildNumber = build_number;
|
||||||
|
osvi.wServicePackMajor = service_pack_major;
|
||||||
|
osvi.wServicePackMinor = service_pack_minor;
|
||||||
|
|
||||||
|
/* Initialize the condition mask. */
|
||||||
|
VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
|
||||||
|
VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
|
||||||
|
VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, op);
|
||||||
|
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
|
||||||
|
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
|
||||||
|
|
||||||
|
/* Perform the test. */
|
||||||
|
return VerifyVersionInfo(
|
||||||
|
&osvi,
|
||||||
|
VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER |
|
||||||
|
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
|
||||||
|
condition_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ipc,
|
ipc,
|
||||||
license::*,
|
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::{
|
use hbb_common::{
|
||||||
allow_err,
|
allow_err,
|
||||||
@ -460,6 +460,13 @@ extern "C" {
|
|||||||
fn is_win_down() -> BOOL;
|
fn is_win_down() -> BOOL;
|
||||||
fn is_local_system() -> BOOL;
|
fn is_local_system() -> BOOL;
|
||||||
fn alloc_console_and_redirect();
|
fn alloc_console_and_redirect();
|
||||||
|
fn IsWindowsVersionOrGreater(
|
||||||
|
os_major: DWORD,
|
||||||
|
os_minor: DWORD,
|
||||||
|
build_number: DWORD,
|
||||||
|
service_pack_major: WORD,
|
||||||
|
service_pack_minor: WORD,
|
||||||
|
) -> BOOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "system" {
|
extern "system" {
|
||||||
@ -848,8 +855,8 @@ fn get_default_install_path() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_update_broker_process() -> ResultType<()> {
|
pub fn check_update_broker_process() -> ResultType<()> {
|
||||||
let process_exe = win_mag::INJECTED_PROCESS_EXE;
|
let process_exe = win_topmost_window::INJECTED_PROCESS_EXE;
|
||||||
let origin_process_exe = win_mag::ORIGIN_PROCESS_EXE;
|
let origin_process_exe = win_topmost_window::ORIGIN_PROCESS_EXE;
|
||||||
|
|
||||||
let exe_file = std::env::current_exe()?;
|
let exe_file = std::env::current_exe()?;
|
||||||
let Some(cur_dir) = exe_file.parent() else {
|
let Some(cur_dir) = exe_file.parent() else {
|
||||||
@ -926,8 +933,8 @@ pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> ResultType<String>
|
|||||||
{main_exe}
|
{main_exe}
|
||||||
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
||||||
",
|
",
|
||||||
ORIGIN_PROCESS_EXE = win_mag::ORIGIN_PROCESS_EXE,
|
ORIGIN_PROCESS_EXE = win_topmost_window::ORIGIN_PROCESS_EXE,
|
||||||
broker_exe = win_mag::INJECTED_PROCESS_EXE,
|
broker_exe = win_topmost_window::INJECTED_PROCESS_EXE,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,7 +1164,7 @@ fn get_before_uninstall(kill_self: bool) -> String {
|
|||||||
reg delete HKEY_CLASSES_ROOT\\{ext} /f
|
reg delete HKEY_CLASSES_ROOT\\{ext} /f
|
||||||
netsh advfirewall firewall delete rule name=\"{app_name} Service\"
|
netsh advfirewall firewall delete rule name=\"{app_name} Service\"
|
||||||
",
|
",
|
||||||
broker_exe = WIN_MAG_INJECTED_PROCESS_EXE,
|
broker_exe = WIN_TOPMOST_INJECTED_PROCESS_EXE,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1283,6 +1290,25 @@ pub fn block_input(v: bool) -> (bool, String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_windows_version_or_greater(
|
||||||
|
os_major: u32,
|
||||||
|
os_minor: u32,
|
||||||
|
build_number: u32,
|
||||||
|
service_pack_major: u32,
|
||||||
|
service_pack_minor: u32,
|
||||||
|
) -> bool {
|
||||||
|
unsafe {
|
||||||
|
IsWindowsVersionOrGreater(
|
||||||
|
os_major as _,
|
||||||
|
os_minor as _,
|
||||||
|
build_number as _,
|
||||||
|
service_pack_major as _,
|
||||||
|
service_pack_minor as _,
|
||||||
|
) == TRUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_recent_document(path: &str) {
|
pub fn add_recent_document(path: &str) {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn AddRecentDocument(path: *const u16);
|
fn AddRecentDocument(path: *const u16);
|
||||||
@ -2164,7 +2190,7 @@ pub fn uninstall_service(show_new_window: bool) -> bool {
|
|||||||
taskkill /F /IM {app_name}.exe{filter}
|
taskkill /F /IM {app_name}.exe{filter}
|
||||||
",
|
",
|
||||||
app_name = crate::get_app_name(),
|
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") {
|
if let Err(err) = run_cmds(cmds, false, "uninstall") {
|
||||||
Config::set_option("stop-service".into(), "".into());
|
Config::set_option("stop-service".into(), "".into());
|
||||||
@ -2279,7 +2305,10 @@ fn run_after_run_cmds(silent: bool) {
|
|||||||
pub fn try_kill_broker() {
|
pub fn try_kill_broker() {
|
||||||
allow_err!(std::process::Command::new("cmd")
|
allow_err!(std::process::Command::new("cmd")
|
||||||
.arg("/c")
|
.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)
|
.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW)
|
||||||
.spawn());
|
.spawn());
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,14 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod win_exclude_from_capture;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod win_input;
|
mod win_input;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod win_mag;
|
pub mod win_mag;
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod win_topmost_window;
|
||||||
|
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
mod win_virtual_display;
|
mod win_virtual_display;
|
||||||
@ -34,6 +37,9 @@ pub const NO_DISPLAYS: &'static str = "No displays";
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub const PRIVACY_MODE_IMPL_WIN_MAG: &str = win_mag::PRIVACY_MODE_IMPL;
|
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"))]
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
pub const PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY: &str = win_virtual_display::PRIVACY_MODE_IMPL;
|
pub const PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY: &str = win_virtual_display::PRIVACY_MODE_IMPL;
|
||||||
@ -55,6 +61,8 @@ pub trait PrivacyMode: Sync + Send {
|
|||||||
|
|
||||||
fn pre_conn_id(&self) -> i32;
|
fn pre_conn_id(&self) -> i32;
|
||||||
|
|
||||||
|
fn get_impl_key(&self) -> &str;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn check_on_conn_id(&self, conn_id: i32) -> ResultType<bool> {
|
fn check_on_conn_id(&self, conn_id: i32) -> ResultType<bool> {
|
||||||
let pre_conn_id = self.pre_conn_id();
|
let pre_conn_id = self.pre_conn_id();
|
||||||
@ -84,21 +92,25 @@ lazy_static::lazy_static! {
|
|||||||
pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = {
|
pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
if display_service::is_privacy_mode_mag_supported() {
|
if win_exclude_from_capture::is_supported() {
|
||||||
PRIVACY_MODE_IMPL_WIN_MAG
|
PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE
|
||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "virtual_display_driver")]
|
if display_service::is_privacy_mode_mag_supported() {
|
||||||
{
|
PRIVACY_MODE_IMPL_WIN_MAG
|
||||||
if is_installed() {
|
} else {
|
||||||
PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY
|
#[cfg(feature = "virtual_display_driver")]
|
||||||
} else {
|
{
|
||||||
|
if is_installed() {
|
||||||
|
PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "virtual_display_driver"))]
|
||||||
|
{
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "virtual_display_driver"))]
|
|
||||||
{
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}.to_owned()
|
}.to_owned()
|
||||||
}
|
}
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -107,24 +119,21 @@ lazy_static::lazy_static! {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static ref CUR_PRIVACY_MODE_IMPL: Arc<Mutex<String>> = {
|
static ref PRIVACY_MODE: Arc<Mutex<Option<Box<dyn PrivacyMode>>>> = {
|
||||||
let mut cur_impl = get_option("privacy-mode-impl-key".to_owned());
|
let mut cur_impl = get_option("privacy-mode-impl-key".to_owned());
|
||||||
if !get_supported_privacy_mode_impl().iter().any(|(k, _)| k == &cur_impl) {
|
if !get_supported_privacy_mode_impl().iter().any(|(k, _)| k == &cur_impl) {
|
||||||
cur_impl = DEFAULT_PRIVACY_MODE_IMPL.to_owned();
|
cur_impl = DEFAULT_PRIVACY_MODE_IMPL.to_owned();
|
||||||
}
|
}
|
||||||
Arc::new(Mutex::new(cur_impl))
|
|
||||||
};
|
|
||||||
static ref PRIVACY_MODE: Arc<Mutex<Option<Box<dyn PrivacyMode>>>> = {
|
|
||||||
let cur_impl = (*CUR_PRIVACY_MODE_IMPL.lock().unwrap()).clone();
|
|
||||||
let privacy_mode = match PRIVACY_MODE_CREATOR.lock().unwrap().get(&(&cur_impl as &str)) {
|
let privacy_mode = match PRIVACY_MODE_CREATOR.lock().unwrap().get(&(&cur_impl as &str)) {
|
||||||
Some(creator) => Some(creator()),
|
Some(creator) => Some(creator(&cur_impl)),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
Arc::new(Mutex::new(privacy_mode))
|
Arc::new(Mutex::new(privacy_mode))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PrivacyModeCreator = fn() -> Box<dyn PrivacyMode>;
|
pub type PrivacyModeCreator = fn(impl_key: &str) -> Box<dyn PrivacyMode>;
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref PRIVACY_MODE_CREATOR: Arc<Mutex<HashMap<&'static str, PrivacyModeCreator>>> = {
|
static ref PRIVACY_MODE_CREATOR: Arc<Mutex<HashMap<&'static str, PrivacyModeCreator>>> = {
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -133,13 +142,19 @@ lazy_static::lazy_static! {
|
|||||||
let mut map: HashMap<&'static str, PrivacyModeCreator> = HashMap::new();
|
let mut map: HashMap<&'static str, PrivacyModeCreator> = HashMap::new();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
map.insert(win_mag::PRIVACY_MODE_IMPL, || {
|
if win_exclude_from_capture::is_supported() {
|
||||||
Box::new(win_mag::PrivacyModeImpl::default())
|
map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, |impl_key: &str| {
|
||||||
|
Box::new(win_exclude_from_capture::PrivacyModeImpl::new(impl_key))
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
map.insert(win_mag::PRIVACY_MODE_IMPL, |impl_key: &str| {
|
||||||
|
Box::new(win_mag::PrivacyModeImpl::new(impl_key))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "virtual_display_driver")]
|
#[cfg(feature = "virtual_display_driver")]
|
||||||
map.insert(win_virtual_display::PRIVACY_MODE_IMPL, || {
|
map.insert(win_virtual_display::PRIVACY_MODE_IMPL, |impl_key: &str| {
|
||||||
Box::new(win_virtual_display::PrivacyModeImpl::default())
|
Box::new(win_virtual_display::PrivacyModeImpl::new(impl_key))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Arc::new(Mutex::new(map))
|
Arc::new(Mutex::new(map))
|
||||||
@ -158,13 +173,15 @@ pub fn clear() -> Option<()> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn switch(impl_key: &str) {
|
pub fn switch(impl_key: &str) {
|
||||||
let mut cur_impl_lock = CUR_PRIVACY_MODE_IMPL.lock().unwrap();
|
let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap();
|
||||||
if *cur_impl_lock == impl_key {
|
if let Some(privacy_mode) = privacy_mode_lock.as_ref() {
|
||||||
return;
|
if privacy_mode.get_impl_key() == impl_key {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(creator) = PRIVACY_MODE_CREATOR.lock().unwrap().get(impl_key) {
|
if let Some(creator) = PRIVACY_MODE_CREATOR.lock().unwrap().get(impl_key) {
|
||||||
*PRIVACY_MODE.lock().unwrap() = Some(creator());
|
*privacy_mode_lock = Some(creator(impl_key));
|
||||||
*cur_impl_lock = impl_key.to_owned();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,13 +209,15 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>>
|
|||||||
|
|
||||||
// Check or switch privacy mode implementation
|
// Check or switch privacy mode implementation
|
||||||
let impl_key = get_supported_impl(impl_key);
|
let impl_key = get_supported_impl(impl_key);
|
||||||
let mut cur_impl_lock = CUR_PRIVACY_MODE_IMPL.lock().unwrap();
|
|
||||||
|
|
||||||
|
let mut cur_impl_key = "".to_string();
|
||||||
if let Some(privacy_mode) = privacy_mode_lock.as_ref() {
|
if let Some(privacy_mode) = privacy_mode_lock.as_ref() {
|
||||||
|
cur_impl_key = privacy_mode.get_impl_key().to_string();
|
||||||
let check_on_conn_id = privacy_mode.check_on_conn_id(conn_id);
|
let check_on_conn_id = privacy_mode.check_on_conn_id(conn_id);
|
||||||
match check_on_conn_id.as_ref() {
|
match check_on_conn_id.as_ref() {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
if *cur_impl_lock == impl_key {
|
if cur_impl_key == impl_key {
|
||||||
|
// Same peer, same implementation.
|
||||||
return Some(Ok(true));
|
return Some(Ok(true));
|
||||||
} else {
|
} else {
|
||||||
// Same peer, switch to new implementation.
|
// Same peer, switch to new implementation.
|
||||||
@ -209,7 +228,7 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *cur_impl_lock != impl_key {
|
if cur_impl_key != impl_key {
|
||||||
if let Some(creator) = PRIVACY_MODE_CREATOR
|
if let Some(creator) = PRIVACY_MODE_CREATOR
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -219,8 +238,7 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>>
|
|||||||
privacy_mode.clear();
|
privacy_mode.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
*privacy_mode_lock = Some(creator());
|
*privacy_mode_lock = Some(creator(&impl_key));
|
||||||
*cur_impl_lock = impl_key.to_owned();
|
|
||||||
} else {
|
} else {
|
||||||
return Some(Err(anyhow!("Unsupported privacy mode: {}", impl_key)));
|
return Some(Err(anyhow!("Unsupported privacy mode: {}", impl_key)));
|
||||||
}
|
}
|
||||||
@ -269,9 +287,18 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
let mut vec_impls = Vec::new();
|
let mut vec_impls = Vec::new();
|
||||||
if display_service::is_privacy_mode_mag_supported() {
|
|
||||||
vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip"));
|
if win_exclude_from_capture::is_supported() {
|
||||||
|
vec_impls.push((
|
||||||
|
PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE,
|
||||||
|
"privacy_mode_impl_mag_tip",
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
if display_service::is_privacy_mode_mag_supported() {
|
||||||
|
vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "virtual_display_driver")]
|
#[cfg(feature = "virtual_display_driver")]
|
||||||
if is_installed() {
|
if is_installed() {
|
||||||
vec_impls.push((
|
vec_impls.push((
|
||||||
@ -279,6 +306,7 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> {
|
|||||||
"privacy_mode_impl_virtual_display_tip",
|
"privacy_mode_impl_virtual_display_tip",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_impls
|
vec_impls
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
@ -287,9 +315,23 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_cur_impl_key() -> Option<String> {
|
||||||
|
PRIVACY_MODE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.map(|pm| pm.get_impl_key().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_current_privacy_mode_impl(impl_key: &str) -> bool {
|
pub fn is_current_privacy_mode_impl(impl_key: &str) -> bool {
|
||||||
*CUR_PRIVACY_MODE_IMPL.lock().unwrap() == impl_key
|
PRIVACY_MODE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.map(|pm| pm.get_impl_key() == impl_key)
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -309,6 +351,7 @@ pub fn check_privacy_mode_err(
|
|||||||
display_idx: usize,
|
display_idx: usize,
|
||||||
timeout_millis: u64,
|
timeout_millis: u64,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
// win magnifier implementation requires a test of creating a capturer.
|
||||||
if is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) {
|
if is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) {
|
||||||
crate::video_service::test_create_capturer(privacy_mode_id, display_idx, timeout_millis)
|
crate::video_service::test_create_capturer(privacy_mode_id, display_idx, timeout_millis)
|
||||||
} else {
|
} else {
|
||||||
@ -320,3 +363,22 @@ pub fn check_privacy_mode_err(
|
|||||||
pub fn is_privacy_mode_supported() -> bool {
|
pub fn is_privacy_mode_supported() -> bool {
|
||||||
!DEFAULT_PRIVACY_MODE_IMPL.is_empty()
|
!DEFAULT_PRIVACY_MODE_IMPL.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_privacy_mode_conn_id() -> Option<i32> {
|
||||||
|
PRIVACY_MODE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.map(|pm| pm.pre_conn_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_in_privacy_mode() -> bool {
|
||||||
|
PRIVACY_MODE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.map(|pm| pm.pre_conn_id() != INVALID_PRIVACY_MODE_CONN_ID)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
9
src/privacy_mode/win_exclude_from_capture.rs
Normal file
9
src/privacy_mode/win_exclude_from_capture.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub use super::win_topmost_window::PrivacyModeImpl;
|
||||||
|
|
||||||
|
pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_exclude_from_capture";
|
||||||
|
|
||||||
|
pub(super) fn is_supported() -> bool {
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity
|
||||||
|
// https://en.wikipedia.org/wiki/Windows_10_version_history
|
||||||
|
crate::platform::windows::is_windows_version_or_greater(10, 0, 19041, 0, 0)
|
||||||
|
}
|
@ -1,370 +1,11 @@
|
|||||||
use super::{PrivacyMode, INVALID_PRIVACY_MODE_CONN_ID};
|
use super::win_topmost_window::PRIVACY_WINDOW_NAME;
|
||||||
use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState};
|
use hbb_common::{bail, log, ResultType};
|
||||||
use hbb_common::{allow_err, bail, log, ResultType};
|
use std::time::Instant;
|
||||||
use std::{
|
|
||||||
ffi::CString,
|
pub use super::win_topmost_window::PrivacyModeImpl;
|
||||||
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(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(
|
pub fn create_capturer(
|
||||||
privacy_mode_id: i32,
|
privacy_mode_id: i32,
|
||||||
origin: (i32, i32),
|
origin: (i32, i32),
|
||||||
|
379
src/privacy_mode/win_topmost_window.rs
Normal file
379
src/privacy_mode/win_topmost_window.rs
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
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 {
|
||||||
|
impl_key: String,
|
||||||
|
conn_id: i32,
|
||||||
|
handlers: WindowHandlers,
|
||||||
|
hwnd: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_impl_key(&self) -> &str {
|
||||||
|
&self.impl_key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrivacyModeImpl {
|
||||||
|
pub fn new(impl_key: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
impl_key: impl_key.to_owned(),
|
||||||
|
conn_id: INVALID_PRIVACY_MODE_CONN_ID,
|
||||||
|
handlers: WindowHandlers {
|
||||||
|
hthread: 0,
|
||||||
|
hprocess: 0,
|
||||||
|
},
|
||||||
|
hwnd: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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));
|
||||||
|
}
|
||||||
|
}
|
@ -35,23 +35,13 @@ struct Display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrivacyModeImpl {
|
pub struct PrivacyModeImpl {
|
||||||
|
impl_key: String,
|
||||||
conn_id: i32,
|
conn_id: i32,
|
||||||
displays: Vec<Display>,
|
displays: Vec<Display>,
|
||||||
virtual_displays: Vec<Display>,
|
virtual_displays: Vec<Display>,
|
||||||
virtual_displays_added: Vec<u32>,
|
virtual_displays_added: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PrivacyModeImpl {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
conn_id: INVALID_PRIVACY_MODE_CONN_ID,
|
|
||||||
displays: Vec::new(),
|
|
||||||
virtual_displays: Vec::new(),
|
|
||||||
virtual_displays_added: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TurnOnGuard<'a> {
|
struct TurnOnGuard<'a> {
|
||||||
privacy_mode: &'a mut PrivacyModeImpl,
|
privacy_mode: &'a mut PrivacyModeImpl,
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
@ -82,6 +72,16 @@ impl<'a> Drop for TurnOnGuard<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrivacyModeImpl {
|
impl PrivacyModeImpl {
|
||||||
|
pub fn new(impl_key: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
impl_key: impl_key.to_owned(),
|
||||||
|
conn_id: INVALID_PRIVACY_MODE_CONN_ID,
|
||||||
|
displays: Vec::new(),
|
||||||
|
virtual_displays: Vec::new(),
|
||||||
|
virtual_displays_added: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// mainly from https://github.com/fufesou/rustdesk/blob/44c3a52ca8502cf53b58b59db130611778d34dbe/libs/scrap/src/dxgi/mod.rs#L365
|
// mainly from https://github.com/fufesou/rustdesk/blob/44c3a52ca8502cf53b58b59db130611778d34dbe/libs/scrap/src/dxgi/mod.rs#L365
|
||||||
fn set_displays(&mut self) {
|
fn set_displays(&mut self) {
|
||||||
self.displays.clear();
|
self.displays.clear();
|
||||||
@ -431,6 +431,11 @@ impl PrivacyMode for PrivacyModeImpl {
|
|||||||
fn pre_conn_id(&self) -> i32 {
|
fn pre_conn_id(&self) -> i32 {
|
||||||
self.conn_id
|
self.conn_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_impl_key(&self) -> &str {
|
||||||
|
&self.impl_key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for PrivacyModeImpl {
|
impl Drop for PrivacyModeImpl {
|
||||||
|
@ -508,21 +508,18 @@ impl Connection {
|
|||||||
ipc::Data::PrivacyModeState((_, state, impl_key)) => {
|
ipc::Data::PrivacyModeState((_, state, impl_key)) => {
|
||||||
let msg_out = match state {
|
let msg_out = match state {
|
||||||
privacy_mode::PrivacyModeState::OffSucceeded => {
|
privacy_mode::PrivacyModeState::OffSucceeded => {
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
|
||||||
crate::common::make_privacy_mode_msg(
|
crate::common::make_privacy_mode_msg(
|
||||||
back_notification::PrivacyModeState::PrvOffSucceeded,
|
back_notification::PrivacyModeState::PrvOffSucceeded,
|
||||||
impl_key,
|
impl_key,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
privacy_mode::PrivacyModeState::OffByPeer => {
|
privacy_mode::PrivacyModeState::OffByPeer => {
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
|
||||||
crate::common::make_privacy_mode_msg(
|
crate::common::make_privacy_mode_msg(
|
||||||
back_notification::PrivacyModeState::PrvOffByPeer,
|
back_notification::PrivacyModeState::PrvOffByPeer,
|
||||||
impl_key,
|
impl_key,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
privacy_mode::PrivacyModeState::OffUnknown => {
|
privacy_mode::PrivacyModeState::OffUnknown => {
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
|
||||||
crate::common::make_privacy_mode_msg(
|
crate::common::make_privacy_mode_msg(
|
||||||
back_notification::PrivacyModeState::PrvOffUnknown,
|
back_notification::PrivacyModeState::PrvOffUnknown,
|
||||||
impl_key,
|
impl_key,
|
||||||
@ -682,10 +679,10 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let video_privacy_conn_id = video_service::get_privacy_mode_conn_id();
|
if let Some(video_privacy_conn_id) = privacy_mode::get_privacy_mode_conn_id() {
|
||||||
if video_privacy_conn_id == id {
|
if video_privacy_conn_id == id {
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
let _ = Self::turn_off_privacy_to_msg(id);
|
||||||
let _ = Self::turn_off_privacy_to_msg(id);
|
}
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
@ -880,7 +877,7 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn check_privacy_mode_on(&mut self) -> bool {
|
async fn check_privacy_mode_on(&mut self) -> bool {
|
||||||
if video_service::get_privacy_mode_conn_id() > 0 {
|
if privacy_mode::is_in_privacy_mode() {
|
||||||
self.send_login_error("Someone turns on privacy mode, exit")
|
self.send_login_error("Someone turns on privacy mode, exit")
|
||||||
.await;
|
.await;
|
||||||
false
|
false
|
||||||
@ -2610,7 +2607,23 @@ impl Connection {
|
|||||||
impl_key,
|
impl_key,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
match privacy_mode::turn_on_privacy(&impl_key, self.inner.id) {
|
let is_pre_privacy_on = privacy_mode::is_in_privacy_mode();
|
||||||
|
let pre_impl_key = privacy_mode::get_cur_impl_key();
|
||||||
|
let turn_on_res = privacy_mode::turn_on_privacy(&impl_key, self.inner.id);
|
||||||
|
|
||||||
|
if is_pre_privacy_on {
|
||||||
|
if let Some(pre_impl_key) = pre_impl_key {
|
||||||
|
if !privacy_mode::is_current_privacy_mode_impl(&pre_impl_key) {
|
||||||
|
let off_msg = crate::common::make_privacy_mode_msg(
|
||||||
|
back_notification::PrivacyModeState::PrvOffSucceeded,
|
||||||
|
pre_impl_key,
|
||||||
|
);
|
||||||
|
self.send(off_msg).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match turn_on_res {
|
||||||
Some(Ok(res)) => {
|
Some(Ok(res)) => {
|
||||||
if res {
|
if res {
|
||||||
let err_msg = privacy_mode::check_privacy_mode_err(
|
let err_msg = privacy_mode::check_privacy_mode_err(
|
||||||
@ -2619,7 +2632,6 @@ impl Connection {
|
|||||||
5_000,
|
5_000,
|
||||||
);
|
);
|
||||||
if err_msg.is_empty() {
|
if err_msg.is_empty() {
|
||||||
video_service::set_privacy_mode_conn_id(self.inner.id);
|
|
||||||
crate::common::make_privacy_mode_msg(
|
crate::common::make_privacy_mode_msg(
|
||||||
back_notification::PrivacyModeState::PrvOnSucceeded,
|
back_notification::PrivacyModeState::PrvOnSucceeded,
|
||||||
impl_key,
|
impl_key,
|
||||||
@ -2629,7 +2641,6 @@ impl Connection {
|
|||||||
"Check privacy mode failed: {}, turn off privacy mode.",
|
"Check privacy mode failed: {}, turn off privacy mode.",
|
||||||
&err_msg
|
&err_msg
|
||||||
);
|
);
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
|
||||||
let _ = Self::turn_off_privacy_to_msg(self.inner.id);
|
let _ = Self::turn_off_privacy_to_msg(self.inner.id);
|
||||||
crate::common::make_privacy_mode_msg_with_details(
|
crate::common::make_privacy_mode_msg_with_details(
|
||||||
back_notification::PrivacyModeState::PrvOnFailed,
|
back_notification::PrivacyModeState::PrvOnFailed,
|
||||||
@ -2646,8 +2657,10 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
log::error!("Failed to turn on privacy mode. {}", e);
|
log::error!("Failed to turn on privacy mode. {}", e);
|
||||||
if video_service::get_privacy_mode_conn_id() == 0 {
|
if !privacy_mode::is_in_privacy_mode() {
|
||||||
let _ = Self::turn_off_privacy_to_msg(0);
|
let _ = Self::turn_off_privacy_to_msg(
|
||||||
|
privacy_mode::INVALID_PRIVACY_MODE_CONN_ID,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
crate::common::make_privacy_mode_msg_with_details(
|
crate::common::make_privacy_mode_msg_with_details(
|
||||||
back_notification::PrivacyModeState::PrvOnFailed,
|
back_notification::PrivacyModeState::PrvOnFailed,
|
||||||
@ -2674,7 +2687,6 @@ impl Connection {
|
|||||||
impl_key,
|
impl_key,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
video_service::set_privacy_mode_conn_id(0);
|
|
||||||
Self::turn_off_privacy_to_msg(self.inner.id)
|
Self::turn_off_privacy_to_msg(self.inner.id)
|
||||||
};
|
};
|
||||||
self.send(msg_out).await;
|
self.send(msg_out).await;
|
||||||
|
@ -28,6 +28,7 @@ use super::{
|
|||||||
use crate::common::SimpleCallOnReturn;
|
use crate::common::SimpleCallOnReturn;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::platform::linux::is_x11;
|
use crate::platform::linux::is_x11;
|
||||||
|
use crate::privacy_mode::{get_privacy_mode_conn_id, INVALID_PRIVACY_MODE_CONN_ID};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::{
|
use crate::{
|
||||||
platform::windows::is_process_consent_running,
|
platform::windows::is_process_consent_running,
|
||||||
@ -68,7 +69,6 @@ lazy_static::lazy_static! {
|
|||||||
let (tx, rx) = unbounded_channel();
|
let (tx, rx) = unbounded_channel();
|
||||||
(tx, Arc::new(TokioMutex::new(rx)))
|
(tx, Arc::new(TokioMutex::new(rx)))
|
||||||
};
|
};
|
||||||
static ref PRIVACY_MODE_CONN_ID: Mutex<i32> = Mutex::new(0);
|
|
||||||
pub static ref VIDEO_QOS: Arc<Mutex<VideoQoS>> = Default::default();
|
pub static ref VIDEO_QOS: Arc<Mutex<VideoQoS>> = Default::default();
|
||||||
pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default();
|
pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default();
|
||||||
pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default();
|
pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default();
|
||||||
@ -79,16 +79,6 @@ pub fn notify_video_frame_fetched(conn_id: i32, frame_tm: Option<Instant>) {
|
|||||||
FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).ok();
|
FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_privacy_mode_conn_id(conn_id: i32) {
|
|
||||||
*PRIVACY_MODE_CONN_ID.lock().unwrap() = conn_id
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_privacy_mode_conn_id() -> i32 {
|
|
||||||
*PRIVACY_MODE_CONN_ID.lock().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VideoFrameController {
|
struct VideoFrameController {
|
||||||
cur: Instant,
|
cur: Instant,
|
||||||
send_conn_ids: HashSet<i32>,
|
send_conn_ids: HashSet<i32>,
|
||||||
@ -251,7 +241,9 @@ pub fn test_create_capturer(
|
|||||||
// Note: This function is extremely expensive, do not call it frequently.
|
// Note: This function is extremely expensive, do not call it frequently.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn check_uac_switch(privacy_mode_id: i32, capturer_privacy_mode_id: i32) -> ResultType<()> {
|
fn check_uac_switch(privacy_mode_id: i32, capturer_privacy_mode_id: i32) -> ResultType<()> {
|
||||||
if capturer_privacy_mode_id != 0 && is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) {
|
if capturer_privacy_mode_id != INVALID_PRIVACY_MODE_CONN_ID
|
||||||
|
&& is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG)
|
||||||
|
{
|
||||||
if !is_installed() {
|
if !is_installed() {
|
||||||
if privacy_mode_id != capturer_privacy_mode_id {
|
if privacy_mode_id != capturer_privacy_mode_id {
|
||||||
if !is_process_consent_running()? {
|
if !is_process_consent_running()? {
|
||||||
@ -323,18 +315,19 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<Ca
|
|||||||
&name,
|
&name,
|
||||||
);
|
);
|
||||||
|
|
||||||
let privacy_mode_id = *PRIVACY_MODE_CONN_ID.lock().unwrap();
|
let privacy_mode_id = get_privacy_mode_conn_id().unwrap_or(INVALID_PRIVACY_MODE_CONN_ID);
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
let capturer_privacy_mode_id = privacy_mode_id;
|
let capturer_privacy_mode_id = privacy_mode_id;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let mut capturer_privacy_mode_id = privacy_mode_id;
|
let mut capturer_privacy_mode_id = privacy_mode_id;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
if capturer_privacy_mode_id != 0 && is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG)
|
if capturer_privacy_mode_id != INVALID_PRIVACY_MODE_CONN_ID
|
||||||
|
&& is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG)
|
||||||
{
|
{
|
||||||
if !is_installed() {
|
if !is_installed() {
|
||||||
if is_process_consent_running()? {
|
if is_process_consent_running()? {
|
||||||
capturer_privacy_mode_id = 0;
|
capturer_privacy_mode_id = INVALID_PRIVACY_MODE_CONN_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,7 +337,7 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<Ca
|
|||||||
capturer_privacy_mode_id,
|
capturer_privacy_mode_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
if privacy_mode_id != 0 {
|
if privacy_mode_id != INVALID_PRIVACY_MODE_CONN_ID {
|
||||||
if privacy_mode_id != capturer_privacy_mode_id {
|
if privacy_mode_id != capturer_privacy_mode_id {
|
||||||
log::info!("In privacy mode, but show UAC prompt window for now");
|
log::info!("In privacy mode, but show UAC prompt window for now");
|
||||||
} else {
|
} else {
|
||||||
@ -658,9 +651,9 @@ fn get_recorder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> ResultType<()> {
|
fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> ResultType<()> {
|
||||||
let privacy_mode_id_2 = *PRIVACY_MODE_CONN_ID.lock().unwrap();
|
let privacy_mode_id_2 = get_privacy_mode_conn_id().unwrap_or(INVALID_PRIVACY_MODE_CONN_ID);
|
||||||
if privacy_mode_id != privacy_mode_id_2 {
|
if privacy_mode_id != privacy_mode_id_2 {
|
||||||
if privacy_mode_id_2 != 0 {
|
if privacy_mode_id_2 != INVALID_PRIVACY_MODE_CONN_ID {
|
||||||
let msg_out = crate::common::make_privacy_mode_msg(
|
let msg_out = crate::common::make_privacy_mode_msg(
|
||||||
back_notification::PrivacyModeState::PrvOnByOther,
|
back_notification::PrivacyModeState::PrvOnByOther,
|
||||||
"".to_owned(),
|
"".to_owned(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user