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
|
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
|
curl -LJ -o ./usbmmidd_v2.zip https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip
|
||||||
unzip 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
|
mv ./usbmmidd_v2 ./Release || true
|
||||||
|
|
||||||
- name: find Runner.res
|
- name: find Runner.res
|
||||||
|
@ -598,6 +598,19 @@ UINT __stdcall RemoveAmyuniIdd(
|
|||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
DWORD er = ERROR_SUCCESS;
|
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;
|
BOOL rebootRequired = FALSE;
|
||||||
|
|
||||||
hr = WcaInitialize(hInstall, "RemoveAmyuniIdd");
|
hr = WcaInitialize(hInstall, "RemoveAmyuniIdd");
|
||||||
@ -605,7 +618,49 @@ UINT __stdcall RemoveAmyuniIdd(
|
|||||||
|
|
||||||
UninstallDriver(L"usbmmidd", rebootRequired);
|
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:
|
LExit:
|
||||||
|
if (pwzData) {
|
||||||
|
ReleaseStr(pwzData);
|
||||||
|
}
|
||||||
|
|
||||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||||
return WcaFinalize(er);
|
return WcaFinalize(er);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<CustomAction Id="SetPropertyServiceStop.SetParam.ConfigKey" Return="check" Property="ConfigKey" Value="stop-service" />
|
<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="SetPropertyServiceStop.SetParam.PropertyName" Return="check" Property="PropertyName" Value="STOP_SERVICE" />
|
||||||
<CustomAction Id="TryDeleteStartupShortcut.SetParam" Return="check" Property="ShortcutName" Value="$(var.Product) Tray" />
|
<CustomAction Id="TryDeleteStartupShortcut.SetParam" Return="check" Property="ShortcutName" Value="$(var.Product) Tray" />
|
||||||
|
<CustomAction Id="RemoveAmyuniIdd.SetParam" Return="check" Property="RemoveAmyuniIdd" Value="[INSTALLFOLDER]" />
|
||||||
<InstallExecuteSequence>
|
<InstallExecuteSequence>
|
||||||
|
|
||||||
<Custom Action="SetPropertyIsServiceRunning" After="InstallInitialize" Condition="Installed" />
|
<Custom Action="SetPropertyIsServiceRunning" After="InstallInitialize" Condition="Installed" />
|
||||||
@ -73,6 +74,7 @@
|
|||||||
<Custom Action="TerminateBrokers" Before="RemoveInstallFolder"/>
|
<Custom Action="TerminateBrokers" Before="RemoveInstallFolder"/>
|
||||||
<Custom Action="TerminateBrokers.SetParam" Before="TerminateBrokers"/>
|
<Custom Action="TerminateBrokers.SetParam" Before="TerminateBrokers"/>
|
||||||
<Custom Action="RemoveAmyuniIdd" Before="RemoveInstallFolder"/>
|
<Custom Action="RemoveAmyuniIdd" Before="RemoveInstallFolder"/>
|
||||||
|
<Custom Action="RemoveAmyuniIdd.SetParam" Before="RemoveAmyuniIdd"/>
|
||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
<!-- Shortcuts -->
|
<!-- Shortcuts -->
|
||||||
|
@ -46,16 +46,20 @@ pub enum DeviceError {
|
|||||||
Raw(String),
|
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);
|
struct DeviceInfo(HDEVINFO);
|
||||||
|
|
||||||
impl DeviceInfo {
|
impl DeviceInfo {
|
||||||
fn setup_di_create_device_info_list(class_guid: &mut GUID) -> Result<Self, DeviceError> {
|
fn setup_di_create_device_info_list(class_guid: &mut GUID) -> Result<Self, DeviceError> {
|
||||||
let dev_info = unsafe { SetupDiCreateDeviceInfoList(class_guid, null_mut()) };
|
let dev_info = unsafe { SetupDiCreateDeviceInfoList(class_guid, null_mut()) };
|
||||||
if dev_info == null_mut() {
|
if dev_info == null_mut() {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiCreateDeviceInfoList"));
|
||||||
"SetupDiCreateDeviceInfoList".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self(dev_info))
|
Ok(Self(dev_info))
|
||||||
@ -77,10 +81,7 @@ impl DeviceInfo {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
if dev_info == null_mut() {
|
if dev_info == null_mut() {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiGetClassDevsExW"));
|
||||||
"SetupDiGetClassDevsExW".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Ok(Self(dev_info))
|
Ok(Self(dev_info))
|
||||||
}
|
}
|
||||||
@ -133,10 +134,7 @@ pub unsafe fn install_driver(
|
|||||||
null_mut(),
|
null_mut(),
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiGetINFClassW"));
|
||||||
"SetupDiGetINFClassW".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let dev_info = DeviceInfo::setup_di_create_device_info_list(&mut class_guid)?;
|
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,
|
&mut dev_info_data,
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiCreateDeviceInfoW"));
|
||||||
"SetupDiCreateDeviceInfoW".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if SetupDiSetDeviceRegistryPropertyW(
|
if SetupDiSetDeviceRegistryPropertyW(
|
||||||
@ -171,17 +166,13 @@ pub unsafe fn install_driver(
|
|||||||
(hardware_id.len() * 2) as _,
|
(hardware_id.len() * 2) as _,
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"SetupDiSetDeviceRegistryPropertyW".to_string(),
|
"SetupDiSetDeviceRegistryPropertyW",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if SetupDiCallClassInstaller(DIF_REGISTERDEVICE, *dev_info, &mut dev_info_data) == FALSE {
|
if SetupDiCallClassInstaller(DIF_REGISTERDEVICE, *dev_info, &mut dev_info_data) == FALSE {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiCallClassInstaller"));
|
||||||
"SetupDiCallClassInstaller".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut reboot_required_ = FALSE;
|
let mut reboot_required_ = FALSE;
|
||||||
@ -193,9 +184,8 @@ pub unsafe fn install_driver(
|
|||||||
&mut reboot_required_,
|
&mut reboot_required_,
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"UpdateDriverForPlugAndPlayDevicesW".to_string(),
|
"UpdateDriverForPlugAndPlayDevicesW",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
*reboot_required = reboot_required_ == TRUE;
|
*reboot_required = reboot_required_ == TRUE;
|
||||||
@ -219,9 +209,8 @@ unsafe fn is_same_hardware_id(
|
|||||||
null_mut(),
|
null_mut(),
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"SetupDiGetDeviceRegistryPropertyW".to_string(),
|
"SetupDiGetDeviceRegistryPropertyW",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,9 +234,8 @@ pub unsafe fn uninstall_driver(
|
|||||||
RemoteMachineName: [0; SP_MAX_MACHINENAME_LENGTH],
|
RemoteMachineName: [0; SP_MAX_MACHINENAME_LENGTH],
|
||||||
};
|
};
|
||||||
if SetupDiGetDeviceInfoListDetailW(*dev_info, &mut device_info_list_detail) == FALSE {
|
if SetupDiGetDeviceInfoListDetailW(*dev_info, &mut device_info_list_detail) == FALSE {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"SetupDiGetDeviceInfoListDetailW".to_string(),
|
"SetupDiGetDeviceInfoListDetailW",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,17 +288,13 @@ pub unsafe fn uninstall_driver(
|
|||||||
std::mem::size_of::<SP_REMOVEDEVICE_PARAMS>() as _,
|
std::mem::size_of::<SP_REMOVEDEVICE_PARAMS>() as _,
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"SetupDiSetClassInstallParams".to_string(),
|
"SetupDiSetClassInstallParams",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if SetupDiCallClassInstaller(DIF_REMOVE, *dev_info, &mut devinfo_data) == FALSE {
|
if SetupDiCallClassInstaller(DIF_REMOVE, *dev_info, &mut devinfo_data) == FALSE {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiCallClassInstaller"));
|
||||||
"SetupDiCallClassInstaller".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut device_params = SP_DEVINSTALL_PARAMS_W {
|
let mut device_params = SP_DEVINSTALL_PARAMS_W {
|
||||||
@ -371,10 +355,7 @@ pub unsafe fn device_io_control(
|
|||||||
);
|
);
|
||||||
CloseHandle(h_device);
|
CloseHandle(h_device);
|
||||||
if result == FALSE {
|
if result == FALSE {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("DeviceIoControl"));
|
||||||
"DeviceIoControl".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if outbuf_max_len > 0 {
|
if outbuf_max_len > 0 {
|
||||||
outbuf.set_len(bytes_returned as _);
|
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,
|
&mut device_interface_data,
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("SetupDiEnumDeviceInterfaces"));
|
||||||
"SetupDiEnumDeviceInterfaces".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut required_length = 0;
|
let mut required_length = 0;
|
||||||
@ -444,14 +422,14 @@ unsafe fn get_device_path(interface_guid: &GUID) -> Result<Vec<u16>, DeviceError
|
|||||||
null_mut(),
|
null_mut(),
|
||||||
) == FALSE
|
) == FALSE
|
||||||
{
|
{
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err(
|
||||||
"SetupDiGetDeviceInterfaceDetailW".to_string(),
|
"SetupDiGetDeviceInterfaceDetailW",
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = Vec::new();
|
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;
|
let steps = device_path_ptr as usize - vec_data.as_ptr() as usize;
|
||||||
for i in 0..(predicted_length - steps as u32) / 2 {
|
for i in 0..(predicted_length - steps as u32) / 2 {
|
||||||
if *device_path_ptr.offset(i as _) == 0 {
|
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> {
|
unsafe fn open_device_handle(interface_guid: &GUID) -> Result<HANDLE, DeviceError> {
|
||||||
let device_path = get_device_path(interface_guid)?;
|
let device_path = get_device_path(interface_guid)?;
|
||||||
println!("device_path: {:?}", String::from_utf16_lossy(&device_path));
|
|
||||||
let h_device = CreateFileW(
|
let h_device = CreateFileW(
|
||||||
device_path.as_ptr(),
|
device_path.as_ptr(),
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
@ -476,10 +453,7 @@ unsafe fn open_device_handle(interface_guid: &GUID) -> Result<HANDLE, DeviceErro
|
|||||||
null_mut(),
|
null_mut(),
|
||||||
);
|
);
|
||||||
if h_device == INVALID_HANDLE_VALUE || h_device == NULL {
|
if h_device == INVALID_HANDLE_VALUE || h_device == NULL {
|
||||||
return Err(DeviceError::WinApiLastErr(
|
return Err(DeviceError::new_api_last_err("CreateFileW"));
|
||||||
"CreateFileW".to_string(),
|
|
||||||
io::Error::last_os_error(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Ok(h_device)
|
Ok(h_device)
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use wallpaper;
|
use wallpaper;
|
||||||
|
use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO};
|
||||||
use winapi::{
|
use winapi::{
|
||||||
ctypes::c_void,
|
ctypes::c_void,
|
||||||
shared::{minwindef::*, ntdef::NULL, windef::*, winerror::*},
|
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\"
|
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),
|
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(),
|
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() {
|
match std::env::current_exe() {
|
||||||
Ok(path) => format!("\"{}\" --uninstall-amyuni-idd", path.to_str().unwrap_or("")),
|
Ok(path) => format!("\"{}\" --uninstall-amyuni-idd", path.to_str().unwrap_or("")),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -2390,3 +2391,13 @@ pub fn is_service_running(service_name: &str) -> bool {
|
|||||||
is_service_running_w(service_name.as_ptr() as _)
|
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,
|
display_service,
|
||||||
ipc::{connect, Data},
|
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 serde_derive::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -51,6 +56,8 @@ pub enum PrivacyModeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait PrivacyMode: Sync + Send {
|
pub trait PrivacyMode: Sync + Send {
|
||||||
|
fn is_async_privacy_mode(&self) -> bool;
|
||||||
|
|
||||||
fn init(&self) -> ResultType<()>;
|
fn init(&self) -> ResultType<()>;
|
||||||
fn clear(&mut self);
|
fn clear(&mut self);
|
||||||
fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType<bool>;
|
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
|
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
|
// Check if privacy mode is already on or occupied by another one
|
||||||
let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap();
|
let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap();
|
||||||
|
|
||||||
|
@ -72,6 +72,10 @@ pub struct PrivacyModeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrivacyMode for PrivacyModeImpl {
|
impl PrivacyMode for PrivacyModeImpl {
|
||||||
|
fn is_async_privacy_mode(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn init(&self) -> ResultType<()> {
|
fn init(&self) -> ResultType<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -360,6 +360,10 @@ impl PrivacyModeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrivacyMode for PrivacyModeImpl {
|
impl PrivacyMode for PrivacyModeImpl {
|
||||||
|
fn is_async_privacy_mode(&self) -> bool {
|
||||||
|
virtual_display_manager::is_amyuni_idd()
|
||||||
|
}
|
||||||
|
|
||||||
fn init(&self) -> ResultType<()> {
|
fn init(&self) -> ResultType<()> {
|
||||||
Ok(())
|
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 {
|
match turn_on_res {
|
||||||
Some(Ok(res)) => {
|
Some(Ok(res)) => {
|
||||||
if res {
|
if res {
|
||||||
|
@ -403,9 +403,16 @@ pub mod rustdesk_idd {
|
|||||||
pub mod amyuni_idd {
|
pub mod amyuni_idd {
|
||||||
use super::windows;
|
use super::windows;
|
||||||
use crate::platform::win_device;
|
use crate::platform::win_device;
|
||||||
use hbb_common::{bail, lazy_static, log, ResultType};
|
use hbb_common::{bail, lazy_static, log, tokio::time::Instant, ResultType};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::{
|
||||||
use winapi::shared::guiddef::GUID;
|
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 INF_PATH: &str = r#"usbmmidd_v2\usbmmIdd.inf"#;
|
||||||
const INTERFACE_GUID: GUID = GUID {
|
const INTERFACE_GUID: GUID = GUID {
|
||||||
@ -416,49 +423,116 @@ pub mod amyuni_idd {
|
|||||||
};
|
};
|
||||||
const HARDWARE_ID: &str = "usbmmidd";
|
const HARDWARE_ID: &str = "usbmmidd";
|
||||||
const PLUG_MONITOR_IO_CONTROL_CDOE: u32 = 2307084;
|
const PLUG_MONITOR_IO_CONTROL_CDOE: u32 = 2307084;
|
||||||
|
const INSTALLER_EXE_FILE: &str = "deviceinstaller64.exe";
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref LOCK: Arc<Mutex<()>> = Default::default();
|
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<()> {
|
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;
|
let mut reboot_required = false;
|
||||||
unsafe {
|
let _ = unsafe { win_device::uninstall_driver(HARDWARE_ID, &mut reboot_required)? };
|
||||||
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(())
|
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 _l = LOCK.lock().unwrap();
|
||||||
let drivers = windows::get_display_drivers();
|
let drivers = windows::get_display_drivers();
|
||||||
if drivers
|
if drivers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(s, c)| s == super::AMYUNI_IDD_DEVICE_STRING && *c == 0)
|
.any(|(s, c)| s == super::AMYUNI_IDD_DEVICE_STRING && *c == 0)
|
||||||
{
|
{
|
||||||
|
*is_async = false;
|
||||||
return Ok(());
|
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 exe_file = std::env::current_exe()?;
|
||||||
let Some(cur_dir) = exe_file.parent() else {
|
let Some(cur_dir) = exe_file.parent() else {
|
||||||
bail!("Cannot get parent of current exe file");
|
bail!("Cannot get parent of current exe file");
|
||||||
};
|
};
|
||||||
|
|
||||||
let inf_path = cur_dir.join(INF_PATH);
|
let inf_path = cur_dir.join(INF_PATH);
|
||||||
if !inf_path.exists() {
|
if !inf_path.exists() {
|
||||||
bail!("Driver inf file not found.");
|
bail!("Driver inf file not found.");
|
||||||
}
|
}
|
||||||
let inf_path = inf_path.to_string_lossy().to_string();
|
let inf_path = inf_path.to_string_lossy().to_string();
|
||||||
|
|
||||||
|
log::info!("Installing driver by SetupAPI");
|
||||||
let mut reboot_required = false;
|
let mut reboot_required = false;
|
||||||
unsafe {
|
let _ =
|
||||||
win_device::install_driver(&inf_path, HARDWARE_ID, &mut reboot_required)?;
|
unsafe { win_device::install_driver(&inf_path, HARDWARE_ID, &mut reboot_required)? };
|
||||||
}
|
*is_async = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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 = if add { 0x10 } else { 0x00 };
|
||||||
let cmd = [cmd, 0x00, 0x00, 0x00];
|
let cmd = [cmd, 0x00, 0x00, 0x00];
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -467,21 +541,51 @@ pub mod amyuni_idd {
|
|||||||
Ok(())
|
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<()> {
|
pub fn plug_in_headless() -> ResultType<()> {
|
||||||
if get_monitor_count() > 0 {
|
if get_monitor_count() > 0 {
|
||||||
return Ok(());
|
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);
|
log::error!("Failed to install driver: {}", e);
|
||||||
bail!("Failed to install driver.");
|
bail!("Failed to install driver.");
|
||||||
}
|
}
|
||||||
|
|
||||||
plug_in_monitor_(true)
|
plug_in_monitor_(true, is_async)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plug_in_monitor() -> ResultType<()> {
|
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);
|
log::error!("Failed to install driver: {}", e);
|
||||||
bail!("Failed to install driver.");
|
bail!("Failed to install driver.");
|
||||||
}
|
}
|
||||||
@ -490,7 +594,7 @@ pub mod amyuni_idd {
|
|||||||
bail!("There are already 4 monitors plugged in.");
|
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<()> {
|
pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
||||||
@ -525,7 +629,7 @@ pub mod amyuni_idd {
|
|||||||
to_plug_out_count = 1;
|
to_plug_out_count = 1;
|
||||||
}
|
}
|
||||||
for _i in 0..to_plug_out_count {
|
for _i in 0..to_plug_out_count {
|
||||||
let _ = plug_in_monitor_(false);
|
let _ = plug_monitor_(false);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user