refact: win, idd control (#7789)
* refact: win, idd control Signed-off-by: fufesou <shuanglongchen@yeah.net> * refact: win device control, better addr of Signed-off-by: fufesou <shuanglongchen@yeah.net> * refact: simple refact Signed-off-by: fufesou <shuanglongchen@yeah.net> --------- Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
ad062486ff
commit
4f47d4482b
3
.github/workflows/flutter-build.yml
vendored
3
.github/workflows/flutter-build.yml
vendored
@ -118,7 +118,7 @@ jobs:
|
|||||||
Expand-Archive usbmmidd_v2.zip -DestinationPath .
|
Expand-Archive usbmmidd_v2.zip -DestinationPath .
|
||||||
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack --virtual-display
|
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack --virtual-display
|
||||||
Remove-Item -Path usbmmidd_v2\Win32 -Recurse
|
Remove-Item -Path usbmmidd_v2\Win32 -Recurse
|
||||||
Remove-Item -Path usbmmidd_v2\deviceinstaller.exe
|
Remove-Item -Path "usbmmidd_v2\deviceinstaller64.exe", "usbmmidd_v2\deviceinstaller.exe", "usbmmidd_v2\usbmmidd.bat"
|
||||||
mv -Force .\usbmmidd_v2 ./flutter/build/windows/x64/runner/Release/
|
mv -Force .\usbmmidd_v2 ./flutter/build/windows/x64/runner/Release/
|
||||||
|
|
||||||
- name: find Runner.res
|
- name: find Runner.res
|
||||||
@ -264,6 +264,7 @@ 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
|
||||||
mv ./usbmmidd_v2 ./Release || true
|
mv ./usbmmidd_v2 ./Release || true
|
||||||
|
|
||||||
- name: find Runner.res
|
- name: find Runner.res
|
||||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2904,6 +2904,7 @@ dependencies = [
|
|||||||
"socket2 0.3.19",
|
"socket2 0.3.19",
|
||||||
"sodiumoxide",
|
"sodiumoxide",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
15
Cargo.toml
15
Cargo.toml
@ -100,7 +100,20 @@ system_shutdown = "4.0"
|
|||||||
qrcode-generator = "4.1"
|
qrcode-generator = "4.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi", "pdh", "synchapi", "memoryapi", "shellapi", "devguid", "setupapi", "cguid", "cfgmgr32"] }
|
winapi = { version = "0.3", features = [
|
||||||
|
"winuser",
|
||||||
|
"wincrypt",
|
||||||
|
"shellscalingapi",
|
||||||
|
"pdh",
|
||||||
|
"synchapi",
|
||||||
|
"memoryapi",
|
||||||
|
"shellapi",
|
||||||
|
"devguid",
|
||||||
|
"setupapi",
|
||||||
|
"cguid",
|
||||||
|
"cfgmgr32",
|
||||||
|
"ioapiset",
|
||||||
|
] }
|
||||||
winreg = "0.11"
|
winreg = "0.11"
|
||||||
windows-service = "0.6"
|
windows-service = "0.6"
|
||||||
virtual_display = { path = "libs/virtual_display", optional = true }
|
virtual_display = { path = "libs/virtual_display", optional = true }
|
||||||
|
@ -40,6 +40,7 @@ toml = "0.7"
|
|||||||
uuid = { version = "1.3", features = ["v4"] }
|
uuid = { version = "1.3", features = ["v4"] }
|
||||||
# crash, versions >= 0.29.1 are affected by #GuillaumeGomez/sysinfo/1052
|
# crash, versions >= 0.29.1 are affected by #GuillaumeGomez/sysinfo/1052
|
||||||
sysinfo = { git = "https://github.com/rustdesk-org/sysinfo" }
|
sysinfo = { git = "https://github.com/rustdesk-org/sysinfo" }
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
mac_address = "1.1"
|
mac_address = "1.1"
|
||||||
|
@ -51,6 +51,7 @@ pub use serde_json;
|
|||||||
pub use sysinfo;
|
pub use sysinfo;
|
||||||
pub use toml;
|
pub use toml;
|
||||||
pub use uuid;
|
pub use uuid;
|
||||||
|
pub use thiserror;
|
||||||
|
|
||||||
#[cfg(feature = "quic")]
|
#[cfg(feature = "quic")]
|
||||||
pub type Stream = quic::Connection;
|
pub type Stream = quic::Connection;
|
||||||
|
@ -13,3 +13,4 @@ bool MyStopServiceW(LPCWSTR serviceName);
|
|||||||
|
|
||||||
std::wstring ReadConfig(const std::wstring& filename, const std::wstring& key);
|
std::wstring ReadConfig(const std::wstring& filename, const std::wstring& key);
|
||||||
|
|
||||||
|
void UninstallDriver(LPCWSTR hardwareId, BOOL &rebootRequired);
|
||||||
|
@ -70,7 +70,7 @@ UINT __stdcall RemoveInstallFolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LExit:
|
LExit:
|
||||||
ReleaseStr(installFolder);
|
ReleaseStr(pwzData);
|
||||||
|
|
||||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||||
return WcaFinalize(er);
|
return WcaFinalize(er);
|
||||||
@ -598,57 +598,14 @@ UINT __stdcall RemoveAmyuniIdd(
|
|||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
DWORD er = ERROR_SUCCESS;
|
DWORD er = ERROR_SUCCESS;
|
||||||
|
|
||||||
int nResult = 0;
|
BOOL rebootRequired = FALSE;
|
||||||
LPWSTR installFolder = NULL;
|
|
||||||
LPWSTR pwz = NULL;
|
|
||||||
LPWSTR pwzData = NULL;
|
|
||||||
|
|
||||||
WCHAR workDir[1024] = L"";
|
|
||||||
DWORD fileAttributes = 0;
|
|
||||||
HINSTANCE hi = 0;
|
|
||||||
|
|
||||||
SYSTEM_INFO si;
|
|
||||||
LPCWSTR exe = NULL;
|
|
||||||
|
|
||||||
hr = WcaInitialize(hInstall, "RemoveAmyuniIdd");
|
hr = WcaInitialize(hInstall, "RemoveAmyuniIdd");
|
||||||
ExitOnFailure(hr, "Failed to initialize");
|
ExitOnFailure(hr, "Failed to initialize");
|
||||||
|
|
||||||
hr = WcaGetProperty(L"CustomActionData", &pwzData);
|
UninstallDriver(L"usbmmidd", rebootRequired);
|
||||||
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 out found, %d", workDir, fileAttributes);
|
|
||||||
goto LExit;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetNativeSystemInfo(&si);
|
|
||||||
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
|
||||||
exe = L"deviceinstaller64.exe";
|
|
||||||
} else {
|
|
||||||
// No need to check if is other architecture.
|
|
||||||
// Because the driver is only for x86 and x64. It will not work at on other architectures.
|
|
||||||
exe = L"deviceinstaller.exe";
|
|
||||||
}
|
|
||||||
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:
|
||||||
ReleaseStr(installFolder);
|
|
||||||
|
|
||||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||||
return WcaFinalize(er);
|
return WcaFinalize(er);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="CustomActions.cpp" />
|
<ClCompile Include="CustomActions.cpp" />
|
||||||
|
<ClCompile Include="DeviceUtils.cpp" />
|
||||||
<ClCompile Include="dllmain.cpp" />
|
<ClCompile Include="dllmain.cpp" />
|
||||||
<ClCompile Include="FirewallRules.cpp" />
|
<ClCompile Include="FirewallRules.cpp" />
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
@ -81,4 +82,4 @@
|
|||||||
<Error Condition="!Exists('..\packages\WixToolset.DUtil.4.0.5\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.4.0.5\build\WixToolset.DUtil.props'))" />
|
<Error Condition="!Exists('..\packages\WixToolset.DUtil.4.0.5\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.4.0.5\build\WixToolset.DUtil.props'))" />
|
||||||
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.4.0.5\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.4.0.5\build\WixToolset.WcaUtil.props'))" />
|
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.4.0.5\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.4.0.5\build\WixToolset.WcaUtil.props'))" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
84
res/msi/CustomActions/DeviceUtils.cpp
Normal file
84
res/msi/CustomActions/DeviceUtils.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
#include <devguid.h>
|
||||||
|
#include <cfgmgr32.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "SetupAPI.lib")
|
||||||
|
|
||||||
|
|
||||||
|
void UninstallDriver(LPCWSTR hardwareId, BOOL &rebootRequired)
|
||||||
|
{
|
||||||
|
HDEVINFO deviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
|
||||||
|
if (deviceInfoSet == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WcaLog(LOGMSG_STANDARD, "Failed to get device information set, last error: %d", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
|
||||||
|
devInfoListDetail.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA);
|
||||||
|
if (!SetupDiGetDeviceInfoListDetailW(deviceInfoSet, &devInfoListDetail))
|
||||||
|
{
|
||||||
|
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||||
|
WcaLog(LOGMSG_STANDARD, "Failed to call SetupDiGetDeviceInfoListDetail, last error: %d", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_DEVINFO_DATA deviceInfoData;
|
||||||
|
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
|
||||||
|
DWORD dataType;
|
||||||
|
WCHAR deviceId[MAX_DEVICE_ID_LEN] = { 0, };
|
||||||
|
|
||||||
|
DWORD deviceIndex = 0;
|
||||||
|
while (SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
|
||||||
|
{
|
||||||
|
if (!SetupDiGetDeviceRegistryPropertyW(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, &dataType, (PBYTE)deviceId, MAX_DEVICE_ID_LEN, NULL))
|
||||||
|
{
|
||||||
|
WcaLog(LOGMSG_STANDARD, "Failed to get hardware id, last error: %d", GetLastError());
|
||||||
|
deviceIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (wcscmp(deviceId, hardwareId) != 0)
|
||||||
|
{
|
||||||
|
deviceIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_REMOVEDEVICE_PARAMS remove_device_params;
|
||||||
|
remove_device_params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
||||||
|
remove_device_params.ClassInstallHeader.InstallFunction = DIF_REMOVE;
|
||||||
|
remove_device_params.Scope = DI_REMOVEDEVICE_GLOBAL;
|
||||||
|
remove_device_params.HwProfile = 0;
|
||||||
|
|
||||||
|
if (!SetupDiSetClassInstallParamsW(deviceInfoSet, &deviceInfoData, &remove_device_params.ClassInstallHeader, sizeof(SP_REMOVEDEVICE_PARAMS)))
|
||||||
|
{
|
||||||
|
WcaLog(LOGMSG_STANDARD, "Failed to set class install params, last error: %d", GetLastError());
|
||||||
|
deviceIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetupDiCallClassInstaller(DIF_REMOVE, deviceInfoSet, &deviceInfoData))
|
||||||
|
{
|
||||||
|
WcaLog(LOGMSG_STANDARD, "ailed to uninstall driver, last error: %d", GetLastError());
|
||||||
|
deviceIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_DEVINSTALL_PARAMS deviceParams;
|
||||||
|
if (SetupDiGetDeviceInstallParamsW(deviceInfoSet, &deviceInfoData, &deviceParams))
|
||||||
|
{
|
||||||
|
if (deviceParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
|
||||||
|
{
|
||||||
|
rebootRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WcaLog(LOGMSG_STANDARD, "Driver uninstalled successfully");
|
||||||
|
deviceIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||||
|
}
|
@ -29,7 +29,6 @@
|
|||||||
<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" />
|
||||||
@ -74,7 +73,6 @@
|
|||||||
<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 -->
|
||||||
|
@ -232,6 +232,12 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
_is_run_as_system,
|
_is_run_as_system,
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
|
} else if args[0] == "--uninstall-amyuni-idd" {
|
||||||
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
|
hbb_common::allow_err!(
|
||||||
|
crate::virtual_display_manager::amyuni_idd::uninstall_driver()
|
||||||
|
);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if args[0] == "--remove" {
|
if args[0] == "--remove" {
|
||||||
|
@ -8,6 +8,9 @@ pub use windows::*;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod win_device;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub mod macos;
|
pub mod macos;
|
||||||
|
|
||||||
|
485
src/platform/win_device.rs
Normal file
485
src/platform/win_device.rs
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
use hbb_common::{log, thiserror};
|
||||||
|
use std::{
|
||||||
|
ffi::OsStr,
|
||||||
|
io,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
os::windows::ffi::OsStrExt,
|
||||||
|
ptr::null_mut,
|
||||||
|
result::Result,
|
||||||
|
};
|
||||||
|
use winapi::{
|
||||||
|
shared::{
|
||||||
|
guiddef::GUID,
|
||||||
|
minwindef::{BOOL, DWORD, FALSE, MAX_PATH, PBOOL, TRUE},
|
||||||
|
ntdef::{HANDLE, LPCWSTR, NULL},
|
||||||
|
windef::HWND,
|
||||||
|
winerror::{ERROR_INSUFFICIENT_BUFFER, ERROR_NO_MORE_ITEMS},
|
||||||
|
},
|
||||||
|
um::{
|
||||||
|
cfgmgr32::MAX_DEVICE_ID_LEN,
|
||||||
|
fileapi::{CreateFileW, OPEN_EXISTING},
|
||||||
|
handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
|
||||||
|
ioapiset::DeviceIoControl,
|
||||||
|
setupapi::*,
|
||||||
|
winnt::{GENERIC_READ, GENERIC_WRITE},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[link(name = "Newdev")]
|
||||||
|
extern "system" {
|
||||||
|
fn UpdateDriverForPlugAndPlayDevicesW(
|
||||||
|
hwnd_parent: HWND,
|
||||||
|
hardware_id: LPCWSTR,
|
||||||
|
full_inf_path: LPCWSTR,
|
||||||
|
install_flags: DWORD,
|
||||||
|
b_reboot_required: PBOOL,
|
||||||
|
) -> BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum DeviceError {
|
||||||
|
#[error("Failed to call {0}, {1:?}")]
|
||||||
|
WinApiLastErr(String, io::Error),
|
||||||
|
#[error("Failed to call {0}, returns {1}")]
|
||||||
|
WinApiErrCode(String, DWORD),
|
||||||
|
#[error("{0}")]
|
||||||
|
Raw(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(dev_info))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_di_get_class_devs_ex_w(
|
||||||
|
class_guid: *const GUID,
|
||||||
|
flags: DWORD,
|
||||||
|
) -> Result<Self, DeviceError> {
|
||||||
|
let dev_info = unsafe {
|
||||||
|
SetupDiGetClassDevsExW(
|
||||||
|
class_guid,
|
||||||
|
null_mut(),
|
||||||
|
null_mut(),
|
||||||
|
flags,
|
||||||
|
null_mut(),
|
||||||
|
null_mut(),
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if dev_info == null_mut() {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiGetClassDevsExW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Self(dev_info))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DeviceInfo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
SetupDiDestroyDeviceInfoList(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for DeviceInfo {
|
||||||
|
type Target = HDEVINFO;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for DeviceInfo {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn install_driver(
|
||||||
|
inf_path: &str,
|
||||||
|
hardware_id: &str,
|
||||||
|
reboot_required: &mut bool,
|
||||||
|
) -> Result<(), DeviceError> {
|
||||||
|
let driver_inf_path = OsStr::new(inf_path)
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0).into_iter())
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
let hardware_id = OsStr::new(hardware_id)
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0).into_iter())
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
|
||||||
|
let mut class_guid: GUID = std::mem::zeroed();
|
||||||
|
let mut class_name: [u16; 32] = [0; 32];
|
||||||
|
|
||||||
|
if SetupDiGetINFClassW(
|
||||||
|
driver_inf_path.as_ptr(),
|
||||||
|
&mut class_guid,
|
||||||
|
class_name.as_mut_ptr(),
|
||||||
|
class_name.len() as _,
|
||||||
|
null_mut(),
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiGetINFClassW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let dev_info = DeviceInfo::setup_di_create_device_info_list(&mut class_guid)?;
|
||||||
|
|
||||||
|
let mut dev_info_data = SP_DEVINFO_DATA {
|
||||||
|
cbSize: std::mem::size_of::<SP_DEVINFO_DATA>() as _,
|
||||||
|
ClassGuid: class_guid,
|
||||||
|
DevInst: 0,
|
||||||
|
Reserved: 0,
|
||||||
|
};
|
||||||
|
if SetupDiCreateDeviceInfoW(
|
||||||
|
*dev_info,
|
||||||
|
class_name.as_ptr(),
|
||||||
|
&class_guid,
|
||||||
|
null_mut(),
|
||||||
|
null_mut(),
|
||||||
|
DICD_GENERATE_ID,
|
||||||
|
&mut dev_info_data,
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiCreateDeviceInfoW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetupDiSetDeviceRegistryPropertyW(
|
||||||
|
*dev_info,
|
||||||
|
&mut dev_info_data,
|
||||||
|
SPDRP_HARDWAREID,
|
||||||
|
hardware_id.as_ptr() as _,
|
||||||
|
(hardware_id.len() * 2) as _,
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiSetDeviceRegistryPropertyW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetupDiCallClassInstaller(DIF_REGISTERDEVICE, *dev_info, &mut dev_info_data) == FALSE {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiCallClassInstaller".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut reboot_required_ = FALSE;
|
||||||
|
if UpdateDriverForPlugAndPlayDevicesW(
|
||||||
|
null_mut(),
|
||||||
|
hardware_id.as_ptr(),
|
||||||
|
driver_inf_path.as_ptr(),
|
||||||
|
1,
|
||||||
|
&mut reboot_required_,
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"UpdateDriverForPlugAndPlayDevicesW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
*reboot_required = reboot_required_ == TRUE;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn is_same_hardware_id(
|
||||||
|
dev_info: &DeviceInfo,
|
||||||
|
devinfo_data: &mut SP_DEVINFO_DATA,
|
||||||
|
hardware_id: &str,
|
||||||
|
) -> Result<bool, DeviceError> {
|
||||||
|
let mut cur_hardware_id = [0u16; MAX_DEVICE_ID_LEN];
|
||||||
|
if SetupDiGetDeviceRegistryPropertyW(
|
||||||
|
**dev_info,
|
||||||
|
devinfo_data,
|
||||||
|
SPDRP_HARDWAREID,
|
||||||
|
null_mut(),
|
||||||
|
cur_hardware_id.as_mut_ptr() as _,
|
||||||
|
cur_hardware_id.len() as _,
|
||||||
|
null_mut(),
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiGetDeviceRegistryPropertyW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let cur_hardware_id = String::from_utf16_lossy(&cur_hardware_id)
|
||||||
|
.trim_end_matches(char::from(0))
|
||||||
|
.to_string();
|
||||||
|
Ok(cur_hardware_id == hardware_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn uninstall_driver(
|
||||||
|
hardware_id: &str,
|
||||||
|
reboot_required: &mut bool,
|
||||||
|
) -> Result<(), DeviceError> {
|
||||||
|
let dev_info =
|
||||||
|
DeviceInfo::setup_di_get_class_devs_ex_w(null_mut(), DIGCF_ALLCLASSES | DIGCF_PRESENT)?;
|
||||||
|
|
||||||
|
let mut device_info_list_detail = SP_DEVINFO_LIST_DETAIL_DATA_W {
|
||||||
|
cbSize: std::mem::size_of::<SP_DEVINFO_LIST_DETAIL_DATA_W>() as _,
|
||||||
|
ClassGuid: std::mem::zeroed(),
|
||||||
|
RemoteMachineHandle: null_mut(),
|
||||||
|
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(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut devinfo_data = SP_DEVINFO_DATA {
|
||||||
|
cbSize: std::mem::size_of::<SP_DEVINFO_DATA>() as _,
|
||||||
|
ClassGuid: std::mem::zeroed(),
|
||||||
|
DevInst: 0,
|
||||||
|
Reserved: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut device_index = 0;
|
||||||
|
loop {
|
||||||
|
if SetupDiEnumDeviceInfo(*dev_info, device_index, &mut devinfo_data) == FALSE {
|
||||||
|
let err = io::Error::last_os_error();
|
||||||
|
if err.raw_os_error() == Some(ERROR_NO_MORE_ITEMS as _) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiEnumDeviceInfo".to_string(),
|
||||||
|
err,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
match is_same_hardware_id(&dev_info, &mut devinfo_data, hardware_id) {
|
||||||
|
Ok(false) => {
|
||||||
|
device_index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to call is_same_hardware_id, {:?}", e);
|
||||||
|
device_index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut remove_device_params = SP_REMOVEDEVICE_PARAMS {
|
||||||
|
ClassInstallHeader: SP_CLASSINSTALL_HEADER {
|
||||||
|
cbSize: std::mem::size_of::<SP_CLASSINSTALL_HEADER>() as _,
|
||||||
|
InstallFunction: DIF_REMOVE,
|
||||||
|
},
|
||||||
|
Scope: DI_REMOVEDEVICE_GLOBAL,
|
||||||
|
HwProfile: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if SetupDiSetClassInstallParamsW(
|
||||||
|
*dev_info,
|
||||||
|
&mut devinfo_data,
|
||||||
|
&mut remove_device_params.ClassInstallHeader,
|
||||||
|
std::mem::size_of::<SP_REMOVEDEVICE_PARAMS>() as _,
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiSetClassInstallParams".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetupDiCallClassInstaller(DIF_REMOVE, *dev_info, &mut devinfo_data) == FALSE {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiCallClassInstaller".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut device_params = SP_DEVINSTALL_PARAMS_W {
|
||||||
|
cbSize: std::mem::size_of::<SP_DEVINSTALL_PARAMS_W>() as _,
|
||||||
|
Flags: 0,
|
||||||
|
FlagsEx: 0,
|
||||||
|
hwndParent: null_mut(),
|
||||||
|
InstallMsgHandler: None,
|
||||||
|
InstallMsgHandlerContext: null_mut(),
|
||||||
|
FileQueue: null_mut(),
|
||||||
|
ClassInstallReserved: 0,
|
||||||
|
Reserved: 0,
|
||||||
|
DriverPath: [0; MAX_PATH],
|
||||||
|
};
|
||||||
|
|
||||||
|
if SetupDiGetDeviceInstallParamsW(*dev_info, &mut devinfo_data, &mut device_params) == FALSE
|
||||||
|
{
|
||||||
|
log::error!(
|
||||||
|
"Failed to call SetupDiGetDeviceInstallParamsW, {:?}",
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if device_params.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT) != 0 {
|
||||||
|
*reboot_required = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn device_io_control(
|
||||||
|
interface_guid: &GUID,
|
||||||
|
control_code: u32,
|
||||||
|
inbuf: &[u8],
|
||||||
|
outbuf_max_len: usize,
|
||||||
|
) -> Result<Vec<u8>, DeviceError> {
|
||||||
|
let h_device = open_device_handle(interface_guid)?;
|
||||||
|
let mut bytes_returned = 0;
|
||||||
|
let mut outbuf: Vec<u8> = vec![];
|
||||||
|
let outbuf_ptr = if outbuf_max_len > 0 {
|
||||||
|
outbuf.reserve(outbuf_max_len);
|
||||||
|
outbuf.as_mut_ptr()
|
||||||
|
} else {
|
||||||
|
null_mut()
|
||||||
|
};
|
||||||
|
let result = DeviceIoControl(
|
||||||
|
h_device,
|
||||||
|
control_code,
|
||||||
|
inbuf.as_ptr() as _,
|
||||||
|
inbuf.len() as _,
|
||||||
|
outbuf_ptr as _,
|
||||||
|
outbuf_max_len as _,
|
||||||
|
&mut bytes_returned,
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
CloseHandle(h_device);
|
||||||
|
if result == FALSE {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"DeviceIoControl".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if outbuf_max_len > 0 {
|
||||||
|
outbuf.set_len(bytes_returned as _);
|
||||||
|
Ok(outbuf)
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_device_path(interface_guid: &GUID) -> Result<Vec<u16>, DeviceError> {
|
||||||
|
let dev_info = DeviceInfo::setup_di_get_class_devs_ex_w(
|
||||||
|
interface_guid,
|
||||||
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,
|
||||||
|
)?;
|
||||||
|
let mut device_interface_data = SP_DEVICE_INTERFACE_DATA {
|
||||||
|
cbSize: std::mem::size_of::<SP_DEVICE_INTERFACE_DATA>() as _,
|
||||||
|
InterfaceClassGuid: *interface_guid,
|
||||||
|
Flags: 0,
|
||||||
|
Reserved: 0,
|
||||||
|
};
|
||||||
|
if SetupDiEnumDeviceInterfaces(
|
||||||
|
*dev_info,
|
||||||
|
null_mut(),
|
||||||
|
interface_guid,
|
||||||
|
0,
|
||||||
|
&mut device_interface_data,
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiEnumDeviceInterfaces".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut required_length = 0;
|
||||||
|
if SetupDiGetDeviceInterfaceDetailW(
|
||||||
|
*dev_info,
|
||||||
|
&mut device_interface_data,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut required_length,
|
||||||
|
null_mut(),
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
let err = io::Error::last_os_error();
|
||||||
|
if err.raw_os_error() != Some(ERROR_INSUFFICIENT_BUFFER as _) {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiGetDeviceInterfaceDetailW".to_string(),
|
||||||
|
err,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let predicted_length = required_length;
|
||||||
|
let mut vec_data: Vec<u8> = Vec::with_capacity(required_length as _);
|
||||||
|
let device_interface_detail_data = vec_data.as_mut_ptr();
|
||||||
|
let device_interface_detail_data =
|
||||||
|
device_interface_detail_data as *mut SP_DEVICE_INTERFACE_DETAIL_DATA_W;
|
||||||
|
(*device_interface_detail_data).cbSize =
|
||||||
|
std::mem::size_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>() as _;
|
||||||
|
if SetupDiGetDeviceInterfaceDetailW(
|
||||||
|
*dev_info,
|
||||||
|
&mut device_interface_data,
|
||||||
|
device_interface_detail_data,
|
||||||
|
predicted_length,
|
||||||
|
&mut required_length,
|
||||||
|
null_mut(),
|
||||||
|
) == FALSE
|
||||||
|
{
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"SetupDiGetDeviceInterfaceDetailW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = Vec::new();
|
||||||
|
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 {
|
||||||
|
path.push(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path.push(*device_path_ptr.offset(i as _));
|
||||||
|
}
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
0,
|
||||||
|
null_mut(),
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
if h_device == INVALID_HANDLE_VALUE || h_device == NULL {
|
||||||
|
return Err(DeviceError::WinApiLastErr(
|
||||||
|
"CreateFileW".to_string(),
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(h_device)
|
||||||
|
}
|
@ -42,7 +42,6 @@ use winapi::{
|
|||||||
},
|
},
|
||||||
securitybaseapi::GetTokenInformation,
|
securitybaseapi::GetTokenInformation,
|
||||||
shellapi::ShellExecuteW,
|
shellapi::ShellExecuteW,
|
||||||
sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO},
|
|
||||||
winbase::*,
|
winbase::*,
|
||||||
wingdi::*,
|
wingdi::*,
|
||||||
winnt::{
|
winnt::{
|
||||||
@ -2370,37 +2369,13 @@ impl Drop for WallPaperRemover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_amyuni_exe_name() -> Option<String> {
|
|
||||||
let mut sys_info = SYSTEM_INFO::default();
|
|
||||||
unsafe {
|
|
||||||
GetNativeSystemInfo(&mut sys_info as _);
|
|
||||||
}
|
|
||||||
const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0;
|
|
||||||
const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9;
|
|
||||||
|
|
||||||
let exe = match unsafe { sys_info.u.s().wProcessorArchitecture } {
|
|
||||||
PROCESSOR_ARCHITECTURE_INTEL => "deviceinstaller.exe",
|
|
||||||
PROCESSOR_ARCHITECTURE_AMD64 => "deviceinstaller64.exe",
|
|
||||||
_ => {
|
|
||||||
log::error!("Unsupported machine architecture");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(exe.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_uninstall_amyuni_idd(path: &str) -> String {
|
fn get_uninstall_amyuni_idd(path: &str) -> String {
|
||||||
let Some(exe) = get_amyuni_exe_name() else {
|
match std::env::current_exe() {
|
||||||
return "".to_string();
|
Ok(path) => format!("\"{}\" --uninstall-amyuni-idd", path.to_str().unwrap_or("")),
|
||||||
};
|
Err(e) => {
|
||||||
let work_dir = PathBuf::from(path).join("usbmmidd_v2");
|
log::warn!("Failed to get current exe path, cannot get command of uninstalling idd, Zzerror: {:?}", e);
|
||||||
if work_dir.join(&exe).exists() {
|
"".to_string()
|
||||||
format!(
|
}
|
||||||
"pushd {} && .\\{exe} remove usbmmidd && popd",
|
|
||||||
work_dir.to_string_lossy()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,7 @@ use crate::{
|
|||||||
display_service,
|
display_service,
|
||||||
ipc::{connect, Data},
|
ipc::{connect, Data},
|
||||||
};
|
};
|
||||||
use hbb_common::{
|
use hbb_common::{anyhow::anyhow, bail, lazy_static, tokio, ResultType};
|
||||||
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,
|
||||||
@ -56,8 +51,6 @@ 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>;
|
||||||
@ -207,41 +200,7 @@ fn get_supported_impl(impl_key: &str) -> String {
|
|||||||
cur_impl
|
cur_impl
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
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,10 +72,6 @@ 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,10 +360,6 @@ 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).await;
|
let turn_on_res = privacy_mode::turn_on_privacy(&impl_key, self.inner.id);
|
||||||
match turn_on_res {
|
match turn_on_res {
|
||||||
Some(Ok(res)) => {
|
Some(Ok(res)) => {
|
||||||
if res {
|
if res {
|
||||||
|
@ -402,58 +402,31 @@ pub mod rustdesk_idd {
|
|||||||
|
|
||||||
pub mod amyuni_idd {
|
pub mod amyuni_idd {
|
||||||
use super::windows;
|
use super::windows;
|
||||||
use crate::platform::windows::get_amyuni_exe_name;
|
use crate::platform::win_device;
|
||||||
use hbb_common::{bail, lazy_static, log, ResultType};
|
use hbb_common::{bail, lazy_static, log, ResultType};
|
||||||
use std::{
|
use std::sync::{Arc, Mutex};
|
||||||
ptr::null_mut,
|
use winapi::shared::guiddef::GUID;
|
||||||
sync::{Arc, Mutex},
|
|
||||||
|
const INF_PATH: &str = r#"usbmmidd_v2\usbmmIdd.inf"#;
|
||||||
|
const INTERFACE_GUID: GUID = GUID {
|
||||||
|
Data1: 0xb5ffd75f,
|
||||||
|
Data2: 0xda40,
|
||||||
|
Data3: 0x4353,
|
||||||
|
Data4: [0x8f, 0xf8, 0xb6, 0xda, 0xf6, 0xf1, 0xd8, 0xca],
|
||||||
};
|
};
|
||||||
use winapi::um::shellapi::ShellExecuteA;
|
const HARDWARE_ID: &str = "usbmmidd";
|
||||||
|
const PLUG_MONITOR_IO_CONTROL_CDOE: u32 = 2307084;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref LOCK: Arc<Mutex<()>> = Default::default();
|
static ref LOCK: Arc<Mutex<()>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_deviceinstaller(args: &str) -> ResultType<()> {
|
pub fn uninstall_driver() -> ResultType<()> {
|
||||||
let Some(exe_name) = get_amyuni_exe_name() else {
|
let mut reboot_required = false;
|
||||||
bail!("Cannot get amyuni exe name.")
|
|
||||||
};
|
|
||||||
|
|
||||||
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() {
|
|
||||||
bail!("usbmmidd_v2 does not exist.",);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
const SW_HIDE: i32 = 0;
|
win_device::uninstall_driver(HARDWARE_ID, &mut reboot_required)?;
|
||||||
let mut args = args.bytes().collect::<Vec<_>>();
|
|
||||||
args.push(0);
|
|
||||||
let mut exe_name = exe_name.bytes().collect::<Vec<_>>();
|
|
||||||
exe_name.push(0);
|
|
||||||
let hi = ShellExecuteA(
|
|
||||||
null_mut(),
|
|
||||||
"open\0".as_ptr() as _,
|
|
||||||
exe_name.as_ptr() as _,
|
|
||||||
args.as_ptr() as _,
|
|
||||||
work_dir2.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<()> {
|
fn check_install_driver() -> ResultType<()> {
|
||||||
@ -466,7 +439,32 @@ pub mod amyuni_idd {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
run_deviceinstaller("install usbmmidd.inf usbmmidd")
|
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();
|
||||||
|
|
||||||
|
let mut reboot_required = false;
|
||||||
|
unsafe {
|
||||||
|
win_device::install_driver(&inf_path, HARDWARE_ID, &mut reboot_required)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn plug_in_monitor_(add: bool) -> ResultType<()> {
|
||||||
|
let cmd = if add { 0x10 } else { 0x00 };
|
||||||
|
let cmd = [cmd, 0x00, 0x00, 0x00];
|
||||||
|
unsafe {
|
||||||
|
win_device::device_io_control(&INTERFACE_GUID, PLUG_MONITOR_IO_CONTROL_CDOE, &cmd, 0)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plug_in_headless() -> ResultType<()> {
|
pub fn plug_in_headless() -> ResultType<()> {
|
||||||
@ -479,7 +477,7 @@ pub mod amyuni_idd {
|
|||||||
bail!("Failed to install driver.");
|
bail!("Failed to install driver.");
|
||||||
}
|
}
|
||||||
|
|
||||||
run_deviceinstaller("enableidd 1")
|
plug_in_monitor_(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plug_in_monitor() -> ResultType<()> {
|
pub fn plug_in_monitor() -> ResultType<()> {
|
||||||
@ -492,7 +490,7 @@ pub mod amyuni_idd {
|
|||||||
bail!("There are already 4 monitors plugged in.");
|
bail!("There are already 4 monitors plugged in.");
|
||||||
}
|
}
|
||||||
|
|
||||||
run_deviceinstaller("enableidd 1")
|
plug_in_monitor_(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
||||||
@ -527,7 +525,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 _ = run_deviceinstaller(&format!("enableidd 0"));
|
let _ = plug_in_monitor_(false);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user