refact: win idd, x86 on x64 (#7796)
* refact: win idd, x86 on x64 Signed-off-by: fufesou <shuanglongchen@yeah.net> * comments Signed-off-by: fufesou <shuanglongchen@yeah.net> * typo Signed-off-by: fufesou <shuanglongchen@yeah.net> * refact: win idd, check if x64 and deviceinstaller64 exits Signed-off-by: fufesou <shuanglongchen@yeah.net> * refact: win idd Signed-off-by: fufesou <shuanglongchen@yeah.net> * refact: win idd, add logs Signed-off-by: fufesou <shuanglongchen@yeah.net> --------- Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
		
							parent
							
								
									1b4a41b522
								
							
						
					
					
						commit
						b407893db5
					
				
							
								
								
									
										5
									
								
								.github/workflows/flutter-build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/flutter-build.yml
									
									
									
									
										vendored
									
									
								
							| @ -264,7 +264,10 @@ jobs: | ||||
|           echo "output_folder=./Release" >> $GITHUB_OUTPUT | ||||
|           curl -LJ -o ./usbmmidd_v2.zip https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip | ||||
|           unzip usbmmidd_v2.zip | ||||
|           rm -rf ./usbmmidd_v2/x64 ./usbmmidd_v2/deviceinstaller.exe ./usbmmidd_v2/deviceinstaller64.exe ./usbmmidd_v2/usbmmidd.bat  | ||||
|           # Do not remove x64 files, because the user may run the 32bit version on a 64bit system. | ||||
|           # Do not remove ./usbmmidd_v2/deviceinstaller64.exe, as x86 exe cannot install and uninstall drivers when running on x64, | ||||
|           # we need the x64 exe to install and uninstall the driver. | ||||
|           rm -rf ./usbmmidd_v2/deviceinstaller.exe ./usbmmidd_v2/usbmmidd.bat  | ||||
|           mv ./usbmmidd_v2 ./Release || true | ||||
| 
 | ||||
|       - name: find Runner.res | ||||
|  | ||||
| @ -598,6 +598,19 @@ UINT __stdcall RemoveAmyuniIdd( | ||||
|     HRESULT hr = S_OK; | ||||
|     DWORD er = ERROR_SUCCESS; | ||||
| 
 | ||||
|     int nResult = 0; | ||||
|     LPWSTR installFolder = NULL; | ||||
|     LPWSTR pwz = NULL; | ||||
|     LPWSTR pwzData = NULL; | ||||
| 
 | ||||
|     WCHAR workDir[1024] = L""; | ||||
|     DWORD fileAttributes = 0; | ||||
|     HINSTANCE hi = 0; | ||||
| 
 | ||||
|     SYSTEM_INFO si; | ||||
|     LPCWSTR exe = L"deviceinstaller64.exe"; | ||||
|     WCHAR exePath[1024] = L""; | ||||
| 
 | ||||
|     BOOL rebootRequired = FALSE; | ||||
| 
 | ||||
|     hr = WcaInitialize(hInstall, "RemoveAmyuniIdd"); | ||||
| @ -605,7 +618,49 @@ UINT __stdcall RemoveAmyuniIdd( | ||||
| 
 | ||||
|     UninstallDriver(L"usbmmidd", rebootRequired); | ||||
| 
 | ||||
|     // Only for x86 app on x64
 | ||||
|     GetNativeSystemInfo(&si); | ||||
|     if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64) { | ||||
|         goto LExit; | ||||
|     } | ||||
| 
 | ||||
|     hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||||
|     ExitOnFailure(hr, "failed to get CustomActionData"); | ||||
| 
 | ||||
|     pwz = pwzData; | ||||
|     hr = WcaReadStringFromCaData(&pwz, &installFolder); | ||||
|     ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz); | ||||
| 
 | ||||
|     hr = StringCchPrintfW(workDir, 1024, L"%lsusbmmidd_v2", installFolder); | ||||
|     ExitOnFailure(hr, "Failed to compose a resource identifier string"); | ||||
|     fileAttributes = GetFileAttributesW(workDir); | ||||
|     if (fileAttributes == INVALID_FILE_ATTRIBUTES) { | ||||
|         WcaLog(LOGMSG_STANDARD, "Amyuni idd dir \"%ls\" is not found, %d", workDir, fileAttributes); | ||||
|         goto LExit; | ||||
|     } | ||||
| 
 | ||||
|     hr = StringCchPrintfW(exePath, 1024, L"%ls\\%ls", workDir, exe); | ||||
|     ExitOnFailure(hr, "Failed to compose a resource identifier string"); | ||||
|     fileAttributes = GetFileAttributesW(exePath); | ||||
|     if (fileAttributes == INVALID_FILE_ATTRIBUTES) { | ||||
|         goto LExit; | ||||
|     } | ||||
| 
 | ||||
|     WcaLog(LOGMSG_STANDARD, "Remove amyuni idd %ls in %ls", exe, workDir); | ||||
|     hi = ShellExecuteW(NULL, L"open", exe, L"remove usbmmidd", workDir, SW_HIDE); | ||||
|     // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew
 | ||||
|     if ((int)hi <= 32) { | ||||
|         WcaLog(LOGMSG_STANDARD, "Failed to remove amyuni idd : %d, last error: %d", (int)hi, GetLastError()); | ||||
|     } | ||||
|     else { | ||||
|         WcaLog(LOGMSG_STANDARD, "Amyuni idd is removed"); | ||||
|     } | ||||
| 
 | ||||
| LExit: | ||||
|     if (pwzData) { | ||||
|         ReleaseStr(pwzData); | ||||
|     } | ||||
| 
 | ||||
|     er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||||
|     return WcaFinalize(er); | ||||
| } | ||||
|  | ||||
| @ -29,6 +29,7 @@ | ||||
| 		<CustomAction Id="SetPropertyServiceStop.SetParam.ConfigKey" Return="check" Property="ConfigKey" Value="stop-service" /> | ||||
| 		<CustomAction Id="SetPropertyServiceStop.SetParam.PropertyName" Return="check" Property="PropertyName" Value="STOP_SERVICE" /> | ||||
| 		<CustomAction Id="TryDeleteStartupShortcut.SetParam" Return="check" Property="ShortcutName" Value="$(var.Product) Tray" /> | ||||
| 		<CustomAction Id="RemoveAmyuniIdd.SetParam" Return="check" Property="RemoveAmyuniIdd" Value="[INSTALLFOLDER]" /> | ||||
| 		<InstallExecuteSequence> | ||||
| 
 | ||||
| 			<Custom Action="SetPropertyIsServiceRunning" After="InstallInitialize" Condition="Installed" /> | ||||
| @ -73,6 +74,7 @@ | ||||
| 			<Custom Action="TerminateBrokers" Before="RemoveInstallFolder"/> | ||||
| 			<Custom Action="TerminateBrokers.SetParam" Before="TerminateBrokers"/> | ||||
| 			<Custom Action="RemoveAmyuniIdd" Before="RemoveInstallFolder"/> | ||||
| 			<Custom Action="RemoveAmyuniIdd.SetParam" Before="RemoveAmyuniIdd"/> | ||||
| 		</InstallExecuteSequence> | ||||
| 
 | ||||
| 		<!-- Shortcuts --> | ||||
|  | ||||
| @ -46,16 +46,20 @@ pub enum DeviceError { | ||||
|     Raw(String), | ||||
| } | ||||
| 
 | ||||
| impl DeviceError { | ||||
|     #[inline] | ||||
|     fn new_api_last_err(api: &str) -> Self { | ||||
|         Self::WinApiLastErr(api.to_string(), io::Error::last_os_error()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct DeviceInfo(HDEVINFO); | ||||
| 
 | ||||
| impl DeviceInfo { | ||||
|     fn setup_di_create_device_info_list(class_guid: &mut GUID) -> Result<Self, DeviceError> { | ||||
|         let dev_info = unsafe { SetupDiCreateDeviceInfoList(class_guid, null_mut()) }; | ||||
|         if dev_info == null_mut() { | ||||
|             return Err(DeviceError::WinApiLastErr( | ||||
|                 "SetupDiCreateDeviceInfoList".to_string(), | ||||
|                 io::Error::last_os_error(), | ||||
|             )); | ||||
|             return Err(DeviceError::new_api_last_err("SetupDiCreateDeviceInfoList")); | ||||
|         } | ||||
| 
 | ||||
|         Ok(Self(dev_info)) | ||||
| @ -77,10 +81,7 @@ impl DeviceInfo { | ||||
|             ) | ||||
|         }; | ||||
|         if dev_info == null_mut() { | ||||
|             return Err(DeviceError::WinApiLastErr( | ||||
|                 "SetupDiGetClassDevsExW".to_string(), | ||||
|                 io::Error::last_os_error(), | ||||
|             )); | ||||
|             return Err(DeviceError::new_api_last_err("SetupDiGetClassDevsExW")); | ||||
|         } | ||||
|         Ok(Self(dev_info)) | ||||
|     } | ||||
| @ -133,10 +134,7 @@ pub unsafe fn install_driver( | ||||
|         null_mut(), | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiGetINFClassW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("SetupDiGetINFClassW")); | ||||
|     } | ||||
| 
 | ||||
|     let dev_info = DeviceInfo::setup_di_create_device_info_list(&mut class_guid)?; | ||||
| @ -157,10 +155,7 @@ pub unsafe fn install_driver( | ||||
|         &mut dev_info_data, | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiCreateDeviceInfoW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("SetupDiCreateDeviceInfoW")); | ||||
|     } | ||||
| 
 | ||||
|     if SetupDiSetDeviceRegistryPropertyW( | ||||
| @ -171,17 +166,13 @@ pub unsafe fn install_driver( | ||||
|         (hardware_id.len() * 2) as _, | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiSetDeviceRegistryPropertyW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         return Err(DeviceError::new_api_last_err( | ||||
|             "SetupDiSetDeviceRegistryPropertyW", | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     if SetupDiCallClassInstaller(DIF_REGISTERDEVICE, *dev_info, &mut dev_info_data) == FALSE { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiCallClassInstaller".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("SetupDiCallClassInstaller")); | ||||
|     } | ||||
| 
 | ||||
|     let mut reboot_required_ = FALSE; | ||||
| @ -193,9 +184,8 @@ pub unsafe fn install_driver( | ||||
|         &mut reboot_required_, | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "UpdateDriverForPlugAndPlayDevicesW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         return Err(DeviceError::new_api_last_err( | ||||
|             "UpdateDriverForPlugAndPlayDevicesW", | ||||
|         )); | ||||
|     } | ||||
|     *reboot_required = reboot_required_ == TRUE; | ||||
| @ -219,9 +209,8 @@ unsafe fn is_same_hardware_id( | ||||
|         null_mut(), | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiGetDeviceRegistryPropertyW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         return Err(DeviceError::new_api_last_err( | ||||
|             "SetupDiGetDeviceRegistryPropertyW", | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
| @ -245,9 +234,8 @@ pub unsafe fn uninstall_driver( | ||||
|         RemoteMachineName: [0; SP_MAX_MACHINENAME_LENGTH], | ||||
|     }; | ||||
|     if SetupDiGetDeviceInfoListDetailW(*dev_info, &mut device_info_list_detail) == FALSE { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiGetDeviceInfoListDetailW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         return Err(DeviceError::new_api_last_err( | ||||
|             "SetupDiGetDeviceInfoListDetailW", | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
| @ -300,17 +288,13 @@ pub unsafe fn uninstall_driver( | ||||
|             std::mem::size_of::<SP_REMOVEDEVICE_PARAMS>() as _, | ||||
|         ) == FALSE | ||||
|         { | ||||
|             return Err(DeviceError::WinApiLastErr( | ||||
|                 "SetupDiSetClassInstallParams".to_string(), | ||||
|                 io::Error::last_os_error(), | ||||
|             return Err(DeviceError::new_api_last_err( | ||||
|                 "SetupDiSetClassInstallParams", | ||||
|             )); | ||||
|         } | ||||
| 
 | ||||
|         if SetupDiCallClassInstaller(DIF_REMOVE, *dev_info, &mut devinfo_data) == FALSE { | ||||
|             return Err(DeviceError::WinApiLastErr( | ||||
|                 "SetupDiCallClassInstaller".to_string(), | ||||
|                 io::Error::last_os_error(), | ||||
|             )); | ||||
|             return Err(DeviceError::new_api_last_err("SetupDiCallClassInstaller")); | ||||
|         } | ||||
| 
 | ||||
|         let mut device_params = SP_DEVINSTALL_PARAMS_W { | ||||
| @ -371,10 +355,7 @@ pub unsafe fn device_io_control( | ||||
|     ); | ||||
|     CloseHandle(h_device); | ||||
|     if result == FALSE { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "DeviceIoControl".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("DeviceIoControl")); | ||||
|     } | ||||
|     if outbuf_max_len > 0 { | ||||
|         outbuf.set_len(bytes_returned as _); | ||||
| @ -403,10 +384,7 @@ unsafe fn get_device_path(interface_guid: &GUID) -> Result<Vec<u16>, DeviceError | ||||
|         &mut device_interface_data, | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiEnumDeviceInterfaces".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("SetupDiEnumDeviceInterfaces")); | ||||
|     } | ||||
| 
 | ||||
|     let mut required_length = 0; | ||||
| @ -444,14 +422,14 @@ unsafe fn get_device_path(interface_guid: &GUID) -> Result<Vec<u16>, DeviceError | ||||
|         null_mut(), | ||||
|     ) == FALSE | ||||
|     { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "SetupDiGetDeviceInterfaceDetailW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         return Err(DeviceError::new_api_last_err( | ||||
|             "SetupDiGetDeviceInterfaceDetailW", | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let mut path = Vec::new(); | ||||
|     let device_path_ptr = std::ptr::addr_of!((*device_interface_detail_data).DevicePath) as *const u16; | ||||
|     let device_path_ptr = | ||||
|         std::ptr::addr_of!((*device_interface_detail_data).DevicePath) as *const u16; | ||||
|     let steps = device_path_ptr as usize - vec_data.as_ptr() as usize; | ||||
|     for i in 0..(predicted_length - steps as u32) / 2 { | ||||
|         if *device_path_ptr.offset(i as _) == 0 { | ||||
| @ -465,7 +443,6 @@ unsafe fn get_device_path(interface_guid: &GUID) -> Result<Vec<u16>, DeviceError | ||||
| 
 | ||||
| unsafe fn open_device_handle(interface_guid: &GUID) -> Result<HANDLE, DeviceError> { | ||||
|     let device_path = get_device_path(interface_guid)?; | ||||
|     println!("device_path: {:?}", String::from_utf16_lossy(&device_path)); | ||||
|     let h_device = CreateFileW( | ||||
|         device_path.as_ptr(), | ||||
|         GENERIC_READ | GENERIC_WRITE, | ||||
| @ -476,10 +453,7 @@ unsafe fn open_device_handle(interface_guid: &GUID) -> Result<HANDLE, DeviceErro | ||||
|         null_mut(), | ||||
|     ); | ||||
|     if h_device == INVALID_HANDLE_VALUE || h_device == NULL { | ||||
|         return Err(DeviceError::WinApiLastErr( | ||||
|             "CreateFileW".to_string(), | ||||
|             io::Error::last_os_error(), | ||||
|         )); | ||||
|         return Err(DeviceError::new_api_last_err("CreateFileW")); | ||||
|     } | ||||
|     Ok(h_device) | ||||
| } | ||||
|  | ||||
| @ -29,6 +29,7 @@ use std::{ | ||||
|     time::{Duration, Instant}, | ||||
| }; | ||||
| use wallpaper; | ||||
| use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO}; | ||||
| use winapi::{ | ||||
|     ctypes::c_void, | ||||
|     shared::{minwindef::*, ntdef::NULL, windef::*, winerror::*}, | ||||
| @ -1302,7 +1303,7 @@ fn get_uninstall(kill_self: bool) -> String { | ||||
|     if exist \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" del /f /q \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" | ||||
|     ",
 | ||||
|         before_uninstall=get_before_uninstall(kill_self), | ||||
|         uninstall_amyuni_idd=get_uninstall_amyuni_idd(&path), | ||||
|         uninstall_amyuni_idd=get_uninstall_amyuni_idd(), | ||||
|         app_name = crate::get_app_name(), | ||||
|     ) | ||||
| } | ||||
| @ -2369,7 +2370,7 @@ impl Drop for WallPaperRemover { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn get_uninstall_amyuni_idd(path: &str) -> String { | ||||
| fn get_uninstall_amyuni_idd() -> String { | ||||
|     match std::env::current_exe() { | ||||
|         Ok(path) => format!("\"{}\" --uninstall-amyuni-idd", path.to_str().unwrap_or("")), | ||||
|         Err(e) => { | ||||
| @ -2390,3 +2391,13 @@ pub fn is_service_running(service_name: &str) -> bool { | ||||
|         is_service_running_w(service_name.as_ptr() as _) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn is_x64() -> bool { | ||||
|     const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; | ||||
| 
 | ||||
|     let mut sys_info = SYSTEM_INFO::default(); | ||||
|     unsafe { | ||||
|         GetNativeSystemInfo(&mut sys_info as _); | ||||
|     } | ||||
|     unsafe { sys_info.u.s().wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,12 @@ use crate::{ | ||||
|     display_service, | ||||
|     ipc::{connect, Data}, | ||||
| }; | ||||
| use hbb_common::{anyhow::anyhow, bail, lazy_static, tokio, ResultType}; | ||||
| use hbb_common::{ | ||||
|     anyhow::anyhow, | ||||
|     bail, lazy_static, | ||||
|     tokio::{self, sync::oneshot}, | ||||
|     ResultType, | ||||
| }; | ||||
| use serde_derive::{Deserialize, Serialize}; | ||||
| use std::{ | ||||
|     collections::HashMap, | ||||
| @ -51,6 +56,8 @@ pub enum PrivacyModeState { | ||||
| } | ||||
| 
 | ||||
| pub trait PrivacyMode: Sync + Send { | ||||
|     fn is_async_privacy_mode(&self) -> bool; | ||||
| 
 | ||||
|     fn init(&self) -> ResultType<()>; | ||||
|     fn clear(&mut self); | ||||
|     fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType<bool>; | ||||
| @ -200,7 +207,40 @@ fn get_supported_impl(impl_key: &str) -> String { | ||||
|     cur_impl | ||||
| } | ||||
| 
 | ||||
| pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>> { | ||||
| pub async fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>> { | ||||
|     if is_async_privacy_mode() { | ||||
|         turn_on_privacy_async(impl_key.to_string(), conn_id).await | ||||
|     } else { | ||||
|         turn_on_privacy_sync(impl_key, conn_id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[inline] | ||||
| fn is_async_privacy_mode() -> bool { | ||||
|     PRIVACY_MODE | ||||
|         .lock() | ||||
|         .unwrap() | ||||
|         .as_ref() | ||||
|         .map_or(false, |m| m.is_async_privacy_mode()) | ||||
| } | ||||
| 
 | ||||
| #[inline] | ||||
| async fn turn_on_privacy_async(impl_key: String, conn_id: i32) -> Option<ResultType<bool>> { | ||||
|     let (tx, rx) = oneshot::channel(); | ||||
|     std::thread::spawn(move || { | ||||
|         let res = turn_on_privacy_sync(&impl_key, conn_id); | ||||
|         let _ = tx.send(res); | ||||
|     }); | ||||
|     match hbb_common::timeout(5000, rx).await { | ||||
|         Ok(res) => match res { | ||||
|             Ok(res) => res, | ||||
|             Err(e) => Some(Err(anyhow!(e.to_string()))), | ||||
|         }, | ||||
|         Err(e) => Some(Err(anyhow!(e.to_string()))), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn turn_on_privacy_sync(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>> { | ||||
|     // Check if privacy mode is already on or occupied by another one
 | ||||
|     let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap(); | ||||
| 
 | ||||
|  | ||||
| @ -72,6 +72,10 @@ pub struct PrivacyModeImpl { | ||||
| } | ||||
| 
 | ||||
| impl PrivacyMode for PrivacyModeImpl { | ||||
|     fn is_async_privacy_mode(&self) -> bool { | ||||
|         false | ||||
|     } | ||||
|     
 | ||||
|     fn init(&self) -> ResultType<()> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -360,6 +360,10 @@ impl PrivacyModeImpl { | ||||
| } | ||||
| 
 | ||||
| impl PrivacyMode for PrivacyModeImpl { | ||||
|     fn is_async_privacy_mode(&self) -> bool { | ||||
|         virtual_display_manager::is_amyuni_idd() | ||||
|     } | ||||
| 
 | ||||
|     fn init(&self) -> ResultType<()> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -2883,7 +2883,7 @@ impl Connection { | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let turn_on_res = privacy_mode::turn_on_privacy(&impl_key, self.inner.id); | ||||
|             let turn_on_res = privacy_mode::turn_on_privacy(&impl_key, self.inner.id).await; | ||||
|             match turn_on_res { | ||||
|                 Some(Ok(res)) => { | ||||
|                     if res { | ||||
|  | ||||
| @ -403,9 +403,16 @@ pub mod rustdesk_idd { | ||||
| pub mod amyuni_idd { | ||||
|     use super::windows; | ||||
|     use crate::platform::win_device; | ||||
|     use hbb_common::{bail, lazy_static, log, ResultType}; | ||||
|     use std::sync::{Arc, Mutex}; | ||||
|     use winapi::shared::guiddef::GUID; | ||||
|     use hbb_common::{bail, lazy_static, log, tokio::time::Instant, ResultType}; | ||||
|     use std::{ | ||||
|         ptr::null_mut, | ||||
|         sync::{Arc, Mutex}, | ||||
|         time::Duration, | ||||
|     }; | ||||
|     use winapi::{ | ||||
|         shared::{guiddef::GUID, winerror::ERROR_NO_MORE_ITEMS}, | ||||
|         um::shellapi::ShellExecuteA, | ||||
|     }; | ||||
| 
 | ||||
|     const INF_PATH: &str = r#"usbmmidd_v2\usbmmIdd.inf"#; | ||||
|     const INTERFACE_GUID: GUID = GUID { | ||||
| @ -416,49 +423,116 @@ pub mod amyuni_idd { | ||||
|     }; | ||||
|     const HARDWARE_ID: &str = "usbmmidd"; | ||||
|     const PLUG_MONITOR_IO_CONTROL_CDOE: u32 = 2307084; | ||||
|     const INSTALLER_EXE_FILE: &str = "deviceinstaller64.exe"; | ||||
| 
 | ||||
|     lazy_static::lazy_static! { | ||||
|         static ref LOCK: Arc<Mutex<()>> = Default::default(); | ||||
|     } | ||||
| 
 | ||||
|     fn get_deviceinstaller64_work_dir() -> ResultType<Option<Vec<u8>>> { | ||||
|         let cur_exe = std::env::current_exe()?; | ||||
|         let Some(cur_dir) = cur_exe.parent() else { | ||||
|             bail!("Cannot get parent of current exe file."); | ||||
|         }; | ||||
|         let work_dir = cur_dir.join("usbmmidd_v2"); | ||||
|         if !work_dir.exists() { | ||||
|             return Ok(None); | ||||
|         } | ||||
|         let exe_path = work_dir.join(INSTALLER_EXE_FILE); | ||||
|         if !exe_path.exists() { | ||||
|             return Ok(None); | ||||
|         } | ||||
| 
 | ||||
|         let Some(work_dir) = work_dir.to_str() else { | ||||
|             bail!("Cannot convert work_dir to string."); | ||||
|         }; | ||||
|         let mut work_dir2 = work_dir.as_bytes().to_vec(); | ||||
|         work_dir2.push(0); | ||||
|         Ok(Some(work_dir2)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn uninstall_driver() -> ResultType<()> { | ||||
|         if let Ok(Some(work_dir)) = get_deviceinstaller64_work_dir() { | ||||
|             if crate::platform::windows::is_x64() { | ||||
|                 log::info!("Uninstalling driver by deviceinstaller64.exe"); | ||||
|                 install_if_x86_on_x64(&work_dir, "remove usbmmidd")?; | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         log::info!("Uninstalling driver by SetupAPI"); | ||||
|         let mut reboot_required = false; | ||||
|         unsafe { | ||||
|             win_device::uninstall_driver(HARDWARE_ID, &mut reboot_required)?; | ||||
|         let _ = unsafe { win_device::uninstall_driver(HARDWARE_ID, &mut reboot_required)? }; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     // SetupDiCallClassInstaller() will always fail if current_exe() is built as x86 and running on x64.
 | ||||
|     // So we need to call another x64 version exe to install and uninstall the driver.
 | ||||
|     fn install_if_x86_on_x64(work_dir: &[u8], args: &str) -> ResultType<()> { | ||||
|         const SW_HIDE: i32 = 0; | ||||
|         let mut args = args.bytes().collect::<Vec<_>>(); | ||||
|         args.push(0); | ||||
|         let mut exe_file = INSTALLER_EXE_FILE.bytes().collect::<Vec<_>>(); | ||||
|         exe_file.push(0); | ||||
|         let hi = unsafe { | ||||
|             ShellExecuteA( | ||||
|                 null_mut(), | ||||
|                 "open\0".as_ptr() as _, | ||||
|                 exe_file.as_ptr() as _, | ||||
|                 args.as_ptr() as _, | ||||
|                 work_dir.as_ptr() as _, | ||||
|                 SW_HIDE, | ||||
|             ) as i32 | ||||
|         }; | ||||
|         if hi <= 32 { | ||||
|             log::error!("Failed to run deviceinstaller: {}", hi); | ||||
|             bail!("Failed to run deviceinstaller.") | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn check_install_driver() -> ResultType<()> { | ||||
|     // If the driver is installed by "deviceinstaller64.exe", the driver will be installed asynchronously.
 | ||||
|     // The caller must wait some time before using the driver.
 | ||||
|     fn check_install_driver(is_async: &mut bool) -> ResultType<()> { | ||||
|         let _l = LOCK.lock().unwrap(); | ||||
|         let drivers = windows::get_display_drivers(); | ||||
|         if drivers | ||||
|             .iter() | ||||
|             .any(|(s, c)| s == super::AMYUNI_IDD_DEVICE_STRING && *c == 0) | ||||
|         { | ||||
|             *is_async = false; | ||||
|             return Ok(()); | ||||
|         } | ||||
| 
 | ||||
|         if let Ok(Some(work_dir)) = get_deviceinstaller64_work_dir() { | ||||
|             if crate::platform::windows::is_x64() { | ||||
|                 log::info!("Installing driver by deviceinstaller64.exe"); | ||||
|                 install_if_x86_on_x64(&work_dir, "install usbmmidd.inf usbmmidd")?; | ||||
|                 *is_async = true; | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let exe_file = std::env::current_exe()?; | ||||
|         let Some(cur_dir) = exe_file.parent() else { | ||||
|             bail!("Cannot get parent of current exe file"); | ||||
|         }; | ||||
| 
 | ||||
|         let inf_path = cur_dir.join(INF_PATH); | ||||
|         if !inf_path.exists() { | ||||
|             bail!("Driver inf file not found."); | ||||
|         } | ||||
|         let inf_path = inf_path.to_string_lossy().to_string(); | ||||
| 
 | ||||
|         log::info!("Installing driver by SetupAPI"); | ||||
|         let mut reboot_required = false; | ||||
|         unsafe { | ||||
|             win_device::install_driver(&inf_path, HARDWARE_ID, &mut reboot_required)?; | ||||
|         } | ||||
|         let _ = | ||||
|             unsafe { win_device::install_driver(&inf_path, HARDWARE_ID, &mut reboot_required)? }; | ||||
|         *is_async = false; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn plug_in_monitor_(add: bool) -> ResultType<()> { | ||||
|     fn plug_monitor_(add: bool) -> Result<(), win_device::DeviceError> { | ||||
|         let cmd = if add { 0x10 } else { 0x00 }; | ||||
|         let cmd = [cmd, 0x00, 0x00, 0x00]; | ||||
|         unsafe { | ||||
| @ -467,21 +541,51 @@ pub mod amyuni_idd { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     // `std::thread::sleep()` with a timeout is acceptable here.
 | ||||
|     // Because user can wait for a while to plug in a monitor.
 | ||||
|     fn plug_in_monitor_(add: bool, is_driver_async_installed: bool) -> ResultType<()> { | ||||
|         let timeout = Duration::from_secs(3); | ||||
|         let now = Instant::now(); | ||||
|         loop { | ||||
|             match plug_monitor_(add) { | ||||
|                 Ok(_) => { | ||||
|                     break; | ||||
|                 } | ||||
|                 Err(e) => { | ||||
|                     if is_driver_async_installed { | ||||
|                         if let win_device::DeviceError::WinApiLastErr(_, e2) = &e { | ||||
|                             if e2.raw_os_error() == Some(ERROR_NO_MORE_ITEMS as _) { | ||||
|                                 if now.elapsed() < timeout { | ||||
|                                     std::thread::sleep(Duration::from_millis(100)); | ||||
|                                     continue; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     return Err(e.into()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn plug_in_headless() -> ResultType<()> { | ||||
|         if get_monitor_count() > 0 { | ||||
|             return Ok(()); | ||||
|         } | ||||
| 
 | ||||
|         if let Err(e) = check_install_driver() { | ||||
|         let mut is_async = false; | ||||
|         if let Err(e) = check_install_driver(&mut is_async) { | ||||
|             log::error!("Failed to install driver: {}", e); | ||||
|             bail!("Failed to install driver."); | ||||
|         } | ||||
| 
 | ||||
|         plug_in_monitor_(true) | ||||
|         plug_in_monitor_(true, is_async) | ||||
|     } | ||||
| 
 | ||||
|     pub fn plug_in_monitor() -> ResultType<()> { | ||||
|         if let Err(e) = check_install_driver() { | ||||
|         let mut is_async = false; | ||||
|         if let Err(e) = check_install_driver(&mut is_async) { | ||||
|             log::error!("Failed to install driver: {}", e); | ||||
|             bail!("Failed to install driver."); | ||||
|         } | ||||
| @ -490,7 +594,7 @@ pub mod amyuni_idd { | ||||
|             bail!("There are already 4 monitors plugged in."); | ||||
|         } | ||||
| 
 | ||||
|         plug_in_monitor_(true) | ||||
|         plug_in_monitor_(true, is_async) | ||||
|     } | ||||
| 
 | ||||
|     pub fn plug_out_monitor(index: i32) -> ResultType<()> { | ||||
| @ -525,7 +629,7 @@ pub mod amyuni_idd { | ||||
|             to_plug_out_count = 1; | ||||
|         } | ||||
|         for _i in 0..to_plug_out_count { | ||||
|             let _ = plug_in_monitor_(false); | ||||
|             let _ = plug_monitor_(false); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user