diff --git a/libs/scrap/src/dxgi/mag.rs b/libs/scrap/src/dxgi/mag.rs index 188cf2c9c..923606a82 100644 --- a/libs/scrap/src/dxgi/mag.rs +++ b/libs/scrap/src/dxgi/mag.rs @@ -139,9 +139,9 @@ impl MagInterface { return Err(Error::new( ErrorKind::Other, format!( - "Failed to LoadLibraryExA {}, error: {}", + "Failed to LoadLibraryExA {}, error {}", lib_file_name, - GetLastError() + Error::last_os_error() ), )); }; @@ -173,7 +173,7 @@ impl MagInterface { if FALSE == init_func() { return Err(Error::new( ErrorKind::Other, - format!("Failed to MagInitialize, error: {}", GetLastError()), + format!("Failed to MagInitialize, error {}", Error::last_os_error()), )); } else { s.init_succeeded = true; @@ -195,9 +195,9 @@ impl MagInterface { return Err(Error::new( ErrorKind::Other, format!( - "Failed to GetProcAddress {}, error: {}", + "Failed to GetProcAddress {}, error {}", func_name, - GetLastError() + Error::last_os_error() ), )); } @@ -209,14 +209,14 @@ impl MagInterface { if let Some(uninit_func) = self.mag_uninitialize_func { unsafe { if FALSE == uninit_func() { - println!("Failed MagUninitialize {}", GetLastError()) + println!("Failed MagUninitialize, error {}", Error::last_os_error()) } } } if !self.lib_handle.is_null() { unsafe { if FALSE == FreeLibrary(self.lib_handle) { - println!("Failed FreeLibrary {}", GetLastError()) + println!("Failed FreeLibrary, error {}", Error::last_os_error()) } } self.lib_handle = NULL as _; @@ -315,7 +315,10 @@ impl CapturerMag { ) { return Err(Error::new( ErrorKind::Other, - format!("Failed to GetModuleHandleExA, error: {}", GetLastError()), + format!( + "Failed to GetModuleHandleExA, error {}", + Error::last_os_error() + ), )); } @@ -342,7 +345,10 @@ impl CapturerMag { if code != ERROR_CLASS_ALREADY_EXISTS { return Err(Error::new( ErrorKind::Other, - format!("Failed to RegisterClassExA, error: {}", code), + format!( + "Failed to RegisterClassExA, error {}", + Error::from_raw_os_error(code as _) + ), )); } } @@ -366,8 +372,8 @@ impl CapturerMag { return Err(Error::new( ErrorKind::Other, format!( - "Failed to CreateWindowExA host_window, error: {}", - GetLastError() + "Failed to CreateWindowExA host_window, error {}", + Error::last_os_error() ), )); } @@ -391,8 +397,8 @@ impl CapturerMag { return Err(Error::new( ErrorKind::Other, format!( - "Failed CreateWindowA magnifier_window, error: {}", - GetLastError() + "Failed CreateWindowA magnifier_window, error {}", + Error::last_os_error() ), )); } @@ -411,8 +417,8 @@ impl CapturerMag { return Err(Error::new( ErrorKind::Other, format!( - "Failed to MagSetImageScalingCallback, error: {}", - GetLastError() + "Failed to MagSetImageScalingCallback, error {}", + Error::last_os_error() ), )); } @@ -455,10 +461,10 @@ impl CapturerMag { return Err(Error::new( ErrorKind::Other, format!( - "Failed MagSetWindowFilterList for cls {} name {}, err: {}", + "Failed MagSetWindowFilterList for cls {} name {}, error {}", cls, name, - GetLastError() + Error::last_os_error() ), )); } @@ -535,7 +541,7 @@ impl CapturerMag { self.rect.top, self.rect.right - self.rect.left, self.rect.bottom - self.rect.top, - GetLastError() + Error::last_os_error() ), )); } @@ -546,7 +552,10 @@ impl CapturerMag { if FALSE == set_window_source_func(self.magnifier_window, self.rect) { return Err(Error::new( ErrorKind::Other, - format!("Failed to MagSetWindowSource, error: {}", GetLastError()), + format!( + "Failed to MagSetWindowSource, error {}", + Error::last_os_error() + ), )); } } else { @@ -578,7 +587,10 @@ impl CapturerMag { unsafe { if FALSE == DestroyWindow(self.magnifier_window) { // - println!("Failed DestroyWindow magnifier window {}", GetLastError()) + println!( + "Failed DestroyWindow magnifier window, error {}", + Error::last_os_error() + ) } } } @@ -588,7 +600,10 @@ impl CapturerMag { unsafe { if FALSE == DestroyWindow(self.host_window) { // - println!("Failed DestroyWindow host window {}", GetLastError()) + println!( + "Failed DestroyWindow host window, error {}", + Error::last_os_error() + ) } } } diff --git a/libs/virtual_display/dylib/src/win10/IddController.c b/libs/virtual_display/dylib/src/win10/IddController.c index 1b177d47b..0c6d06799 100644 --- a/libs/virtual_display/dylib/src/win10/IddController.c +++ b/libs/virtual_display/dylib/src/win10/IddController.c @@ -9,6 +9,12 @@ #include "./Public.h" +typedef struct DeviceCreateCallbackContext +{ + HANDLE hEvent; + SW_DEVICE_LIFETIME* lifetime; + HRESULT hrCreateResult; +} DeviceCreateCallbackContext; const GUID GUID_DEVINTERFACE_IDD_DRIVER_DEVICE = \ { 0x781EF630, 0x72B2, 0x11d2, { 0xB8, 0x52, 0x00, 0xC0, 0x4E, 0xAF, 0x52, 0x72 } }; @@ -43,6 +49,8 @@ BOOLEAN GetDevicePath2( HANDLE DeviceOpenHandle(); VOID DeviceCloseHandle(HANDLE handle); +LPSTR formatErrorString(DWORD error); + void SetLastMsg(const char* format, ...) { memset(g_lastMsg, 0, sizeof(g_lastMsg)); @@ -82,7 +90,23 @@ BOOL InstallUpdate(LPCWSTR fullInfPath, PBOOL rebootRequired) DWORD error = GetLastError(); if (error != 0) { - SetLastMsg("Failed InstallUpdate UpdateDriverForPlugAndPlayDevicesW, last error 0x%x\n", error); + LPSTR errorString = formatErrorString(error); + switch (error) + { + case 0x109: + SetLastMsg("Failed InstallUpdate UpdateDriverForPlugAndPlayDevicesW, error: 0x%x, %s Please try: Reinstall RustDesk with the cert option.\n", error, errorString == NULL ? "(NULL)\n" : errorString); + break; + case 0xe0000247: + SetLastMsg("Failed InstallUpdate UpdateDriverForPlugAndPlayDevicesW, error: 0x%x, %s Please try: \n1. Check the device manager and event viewer.\n2. Uninstall \"RustDeskIddDriver Device\" in device manager, then reinstall RustDesk with the cert option.\n", error, errorString == NULL ? "(NULL)\n" : errorString); + break; + default: + SetLastMsg("Failed InstallUpdate UpdateDriverForPlugAndPlayDevicesW, error: 0x%x, %s Please try: Check the device manager and event viewer.\n", error, errorString == NULL ? "(NULL)\n" : errorString); + break; + } + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -108,7 +132,12 @@ BOOL Uninstall(LPCWSTR fullInfPath, PBOOL rebootRequired) DWORD error = GetLastError(); if (error != 0) { - SetLastMsg("Failed Uninstall DiUninstallDriverW, last error 0x%x\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed Uninstall DiUninstallDriverW, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -132,7 +161,13 @@ BOOL IsDeviceCreated(PBOOL created) DIGCF_DEVICEINTERFACE)); // Function class devices. if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) { - SetLastMsg("Idd device: Failed IsDeviceCreated SetupDiGetClassDevs, last error 0x%x\n", GetLastError()); + DWORD error = GetLastError(); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Idd device: Failed IsDeviceCreated SetupDiGetClassDevs, error 0x%x (%s)\n", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -165,7 +200,12 @@ BOOL IsDeviceCreated(PBOOL created) break; } - SetLastMsg("Idd device: Failed IsDeviceCreated SetupDiEnumDeviceInterfaces, last error 0x%x\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Idd device: Failed IsDeviceCreated SetupDiEnumDeviceInterfaces, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -180,36 +220,40 @@ BOOL IsDeviceCreated(PBOOL created) } BOOL DeviceCreate(PHSWDEVICE hSwDevice) +{ + SW_DEVICE_LIFETIME lifetime = SWDeviceLifetimeHandle; + return DeviceCreateWithLifetime(&lifetime, hSwDevice); +} + +BOOL DeviceCreateWithLifetime(SW_DEVICE_LIFETIME *lifetime, PHSWDEVICE hSwDevice) { SetLastMsg("Success"); if (*hSwDevice != NULL) { - SetLastMsg("Device handler is not NULL\n"); + SetLastMsg("Device handle is not NULL\n"); return FALSE; } - BOOL created = TRUE; - if (FALSE == IsDeviceCreated(&created)) - { - return FALSE; - } - if (created == TRUE) - { - SetLastMsg("Device is already created, please destroy it first\n"); - if (g_printMsg) - { - printf(g_lastMsg); - } - return FALSE; - } + // No need to check if the device is previous created. + // https://learn.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicesetlifetime + // When a client app calls SwDeviceCreate for a software device that was previously marked for + // SwDeviceLifetimeParentPresent, SwDeviceCreate succeeds if there are no open software device handles for the device + // (only one handle can be open for a device). A client app can then regain control over a persistent software device + // for the purposes of updating properties and interfaces or changing the lifetime. + // // create device HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL) { DWORD error = GetLastError(); - SetLastMsg("Failed DeviceCreate CreateEvent 0x%lx\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed DeviceCreate CreateEvent, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -218,6 +262,8 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) return FALSE; } + DeviceCreateCallbackContext callbackContext = { hEvent, lifetime, E_FAIL, }; + SW_DEVICE_CREATE_INFO createInfo = { 0 }; PCWSTR description = L"RustDesk Idd Driver"; @@ -243,11 +289,16 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) 0, NULL, CreationCallback, - &hEvent, + &callbackContext, hSwDevice); if (FAILED(hr)) { - SetLastMsg("Failed DeviceCreate SwDeviceCreate 0x%lx\n", hr); + LPSTR errorString = formatErrorString((DWORD)hr); + SetLastMsg("Failed DeviceCreate SwDeviceCreate, hresult 0x%lx, %s", hr, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -259,17 +310,54 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) // Wait for callback to signal that the device has been created printf("Waiting for device to be created....\n"); DWORD waitResult = WaitForSingleObject(hEvent, 10 * 1000); + CloseHandle(hEvent); if (waitResult != WAIT_OBJECT_0) { - SetLastMsg("Failed DeviceCreate wait for device creation 0x%d\n", waitResult); + DWORD error = 0; + LPSTR errorString = NULL; + switch (waitResult) + { + case WAIT_ABANDONED: + SetLastMsg("Failed DeviceCreate wait for device creation 0x%d, WAIT_ABANDONED\n", waitResult); + break; + case WAIT_TIMEOUT: + SetLastMsg("Failed DeviceCreate wait for device creation 0x%d, WAIT_TIMEOUT\n", waitResult); + break; + default: + error = GetLastError(); + if (error != 0) + { + errorString = formatErrorString(error); + SetLastMsg("Failed DeviceCreate wait for device creation, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } + } + break; + } if (g_printMsg) { printf(g_lastMsg); } return FALSE; } - // printf("Device created\n\n"); - return TRUE; + + if (SUCCEEDED(callbackContext.hrCreateResult)) + { + // printf("Device created\n\n"); + return TRUE; + } + else + { + LPSTR errorString = formatErrorString((DWORD)callbackContext.hrCreateResult); + SetLastMsg("Failed DeviceCreate SwDeviceCreate, hrCreateResult 0x%lx, %s", callbackContext.hrCreateResult, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } + return FALSE; + } } VOID DeviceClose(HSWDEVICE hSwDevice) @@ -278,8 +366,38 @@ VOID DeviceClose(HSWDEVICE hSwDevice) if (hSwDevice != INVALID_HANDLE_VALUE && hSwDevice != NULL) { + HRESULT result = SwDeviceSetLifetime(hSwDevice, SWDeviceLifetimeHandle); SwDeviceClose(hSwDevice); } + else + { + BOOL created = TRUE; + if (TRUE == IsDeviceCreated(&created)) + { + if (created == FALSE) + { + return; + } + } + else + { + // Try crete sw device, and close + } + + HSWDEVICE hSwDevice2 = NULL; + if (DeviceCreateWithLifetime(NULL, &hSwDevice2)) + { + if (hSwDevice2 != NULL) + { + HRESULT result = SwDeviceSetLifetime(hSwDevice2, SWDeviceLifetimeHandle); + SwDeviceClose(hSwDevice2); + } + } + else + { + // + } + } } BOOL MonitorPlugIn(UINT index, UINT edid, INT retries) @@ -319,7 +437,12 @@ BOOL MonitorPlugIn(UINT index, UINT edid, INT retries) HRESULT hr = CoCreateGuid(&plugIn.ContainerId); if (!SUCCEEDED(hr)) { - SetLastMsg("Failed MonitorPlugIn CoCreateGuid %d\n", hr); + LPSTR errorString = formatErrorString((DWORD)hr); + SetLastMsg("Failed MonitorPlugIn CoCreateGuid, hresult 0x%lx, %s", hr, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -348,8 +471,16 @@ BOOL MonitorPlugIn(UINT index, UINT edid, INT retries) if (ret == FALSE) { DWORD error = GetLastError(); - SetLastMsg("Failed MonitorPlugIn DeviceIoControl 0x%lx\n", error); - printf(g_lastMsg); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed MonitorPlugIn DeviceIoControl, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } + if (g_printMsg) + { + printf(g_lastMsg); + } } } @@ -382,7 +513,12 @@ BOOL MonitorPlugOut(UINT index) 0)) // Ptr to Overlapped structure { DWORD error = GetLastError(); - SetLastMsg("Failed MonitorPlugOut DeviceIoControl 0x%lx\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed MonitorPlugOut DeviceIoControl, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -414,7 +550,7 @@ BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes) PCtlMonitorModes pMonitorModes = (PCtlMonitorModes)malloc(buflen); if (pMonitorModes == NULL) { - SetLastMsg("Failed MonitorModesUpdate CtlMonitorModes malloc 0x%lx\n"); + SetLastMsg("Failed MonitorModesUpdate CtlMonitorModes malloc\n"); if (g_printMsg) { printf(g_lastMsg); @@ -441,7 +577,12 @@ BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes) 0)) // Ptr to Overlapped structure { DWORD error = GetLastError(); - SetLastMsg("Failed MonitorModesUpdate DeviceIoControl 0x%lx\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed MonitorModesUpdate DeviceIoControl, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -466,11 +607,30 @@ CreationCallback( _In_opt_ PCWSTR pszDeviceInstanceId ) { - HANDLE hEvent = *(HANDLE*)pContext; + DeviceCreateCallbackContext* callbackContext = NULL; + + if (pContext != NULL) + { + callbackContext = (DeviceCreateCallbackContext*)pContext; + callbackContext->hrCreateResult = hrCreateResult; + if (SUCCEEDED(hrCreateResult)) + { + if (callbackContext->lifetime) + { + HRESULT result = SwDeviceSetLifetime(hSwDevice, *callbackContext->lifetime); + if (FAILED(result)) + { + // TODO: debug log error here + } + } + } + + if (callbackContext->hEvent != NULL) + { + SetEvent(callbackContext->hEvent); + } + } - SetEvent(hEvent); - UNREFERENCED_PARAMETER(hSwDevice); - UNREFERENCED_PARAMETER(hrCreateResult); // printf("Idd device %ls created\n", pszDeviceInstanceId); } @@ -495,7 +655,7 @@ GetDevicePath( CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES); if (cr != CR_SUCCESS) { - SetLastMsg("Failed GetDevicePath 0x%x retrieving device interface list size.\n", cr); + SetLastMsg("Failed GetDevicePath 0x%x, retrieving device interface list size.\n", cr); if (g_printMsg) { printf(g_lastMsg); @@ -565,7 +725,12 @@ GetDevicePath( hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); if (FAILED(hr)) { - SetLastMsg("Error: GetDevicePath StringCchCopy failed with HRESULT 0x%x", hr); + LPSTR errorString = formatErrorString((DWORD)hr); + SetLastMsg("Failed GetDevicePath StringCchCopy, hresult 0x%lx, %s", hr, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -611,7 +776,13 @@ BOOLEAN GetDevicePath2( DIGCF_DEVICEINTERFACE)); // Function class devices. if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) { - SetLastMsg("Idd device: GetDevicePath2 SetupDiGetClassDevs failed, last error 0x%x\n", GetLastError()); + DWORD error = GetLastError(); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed GetDevicePath2 SetupDiGetClassDevs, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -627,7 +798,13 @@ BOOLEAN GetDevicePath2( 0, // &deviceInterfaceData)) { - SetLastMsg("Idd device: GetDevicePath2 SetupDiEnumDeviceInterfaces failed, last error 0x%x\n", GetLastError()); + DWORD error = GetLastError(); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed GetDevicePath2 SetupDiEnumDeviceInterfaces, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -647,9 +824,15 @@ BOOLEAN GetDevicePath2( &requiredLength, NULL);//not interested in the specific dev-node - if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) + DWORD error = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER != error) { - SetLastMsg("Idd device: GetDevicePath2 SetupDiGetDeviceInterfaceDetail failed, last error 0x%x\n", GetLastError()); + LPSTR errorString = formatErrorString(error); + SetLastMsg("GetDevicePath2 SetupDiGetDeviceInterfaceDetail failed, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -671,7 +854,13 @@ BOOLEAN GetDevicePath2( } else { - SetLastMsg("Idd device: Failed GetDevicePath2 HeapAlloc, last error 0x%x\n", GetLastError()); + DWORD error = GetLastError(); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed GetDevicePath2 HeapAlloc, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -687,7 +876,13 @@ BOOLEAN GetDevicePath2( &requiredLength, NULL)) { - SetLastMsg("Idd device: Failed GetDevicePath2 SetupDiGetDeviceInterfaceDetail, last error 0x%x\n", GetLastError()); + DWORD error = GetLastError(); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed GetDevicePath2 SetupDiGetDeviceInterfaceDetail, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -698,7 +893,12 @@ BOOLEAN GetDevicePath2( hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceDetailData->DevicePath); if (FAILED(hr)) { - SetLastMsg("Error: Failed GetDevicePath2 StringCchCopy HRESULT 0x%x", hr); + LPSTR errorString = formatErrorString((DWORD)hr); + SetLastMsg("Failed GetDevicePath2 StringCchCopy, hresult 0x%lx, %s", hr, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -759,7 +959,12 @@ HANDLE DeviceOpenHandle() if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) { DWORD error = GetLastError(); - SetLastMsg("Failed DeviceOpenHandle CreateFile 0x%lx\n", error); + LPSTR errorString = formatErrorString(error); + SetLastMsg("Failed DeviceOpenHandle CreateFile, error: 0x%x, %s", error, errorString == NULL ? "(NULL)\n" : errorString); + if (errorString != NULL) + { + LocalFree(errorString); + } if (g_printMsg) { printf(g_lastMsg); @@ -782,3 +987,20 @@ VOID SetPrintErrMsg(BOOL b) { g_printMsg = (b == TRUE); } + +// Use en-us for simple, or we may need to handle wide string. +LPSTR formatErrorString(DWORD error) +{ + LPSTR errorString = NULL; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&errorString, + 0, + NULL + ); + return errorString; +} + diff --git a/libs/virtual_display/dylib/src/win10/IddController.h b/libs/virtual_display/dylib/src/win10/IddController.h index 909f17423..6e87a78df 100644 --- a/libs/virtual_display/dylib/src/win10/IddController.h +++ b/libs/virtual_display/dylib/src/win10/IddController.h @@ -58,10 +58,27 @@ BOOL IsDeviceCreated(PBOOL created); */ BOOL DeviceCreate(PHSWDEVICE hSwDevice); +/** + * @brief Create device and set the lifetime. + * Only one device should be created. + * If device is installed ealier, this function returns FALSE. + * + * @param lifetime [in] The lifetime to set after creating the device. NULL means do not set the lifetime. + * https://learn.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicesetlifetime + * @param hSwDevice [out] Handler of software device, used by DeviceCreate(). Should be **NULL**. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + * + */ +BOOL DeviceCreateWithLifetime(SW_DEVICE_LIFETIME * lifetime, PHSWDEVICE hSwDevice); + /** * @brief Close device. * * @param hSwDevice Handler of software device, used by SwDeviceClose(). + * If hSwDevice is INVALID_HANDLE_VALUE or NULL, try find and close the device. * */ VOID DeviceClose(HSWDEVICE hSwDevice); diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 4e88ea99c..3a726c2a1 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -319,7 +319,7 @@ fn get_rich_cursor_data( let dc = DC::new()?; let bitmap_dc = BitmapDC::new(dc.0, hbm_color)?; if get_di_bits(out.as_mut_ptr(), bitmap_dc.dc(), hbm_color, width, height) > 0 { - bail!("Failed to get di bits: {}", get_error()); + bail!("Failed to get di bits: {}", io::Error::last_os_error()); } } Ok(()) @@ -603,7 +603,7 @@ async fn launch_server(session_id: DWORD, close_first: bool) -> ResultType) -> ResultType> { "Failed to launch {:?} with session id {}: {}", arg, session_id, - get_error() + io::Error::last_os_error() ); } Ok(None) @@ -676,7 +676,7 @@ pub fn try_change_desktop() -> bool { if !res { let mut s = SUPPRESS.lock().unwrap(); if s.elapsed() > std::time::Duration::from_secs(3) { - log::error!("Failed to switch desktop: {}", get_error()); + log::error!("Failed to switch desktop: {}", io::Error::last_os_error()); *s = Instant::now(); } } else { @@ -688,41 +688,6 @@ pub fn try_change_desktop() -> bool { return false; } -fn get_error() -> String { - unsafe { - let buff_size = 256; - let mut buff: Vec = Vec::with_capacity(buff_size); - buff.resize(buff_size, 0); - let errno = GetLastError(); - let chars_copied = FormatMessageW( - FORMAT_MESSAGE_IGNORE_INSERTS - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - std::ptr::null(), - errno, - 0, - buff.as_mut_ptr(), - (buff_size + 1) as u32, - std::ptr::null_mut(), - ); - if chars_copied == 0 { - return "".to_owned(); - } - let mut curr_char: usize = chars_copied as usize; - while curr_char > 0 { - let ch = buff[curr_char]; - - if ch >= ' ' as u16 { - break; - } - curr_char -= 1; - } - let sl = std::slice::from_raw_parts(buff.as_ptr(), curr_char); - let err_msg = String::from_utf16(sl); - return err_msg.unwrap_or("".to_owned()); - } -} - fn share_rdp() -> BOOL { if get_reg("share_rdp") != "true" { FALSE @@ -1285,7 +1250,7 @@ pub fn block_input(v: bool) -> (bool, String) { if BlockInput(v) == TRUE { (true, "".to_owned()) } else { - (false, format!("Error code: {}", GetLastError())) + (false, format!("Error: {}", io::Error::last_os_error())) } } } @@ -1559,9 +1524,10 @@ pub fn elevate_or_run_as_system(is_setup: bool, is_elevate: bool, is_run_as_syst if run_as_system(arg_run_as_system).is_ok() { std::process::exit(0); } else { - unsafe { - log::error!("Failed to run as system, errno = {}", GetLastError()); - } + log::error!( + "Failed to run as system, error {}", + io::Error::last_os_error() + ); } } } else { @@ -1569,16 +1535,15 @@ pub fn elevate_or_run_as_system(is_setup: bool, is_elevate: bool, is_run_as_syst if let Ok(true) = elevate(arg_elevate) { std::process::exit(0); } else { - unsafe { - log::error!("Failed to elevate, errno = {}", GetLastError()); - } + log::error!("Failed to elevate, error {}", io::Error::last_os_error()); } } } } - Err(_) => unsafe { - log::error!("Failed to get elevation status, errno = {}", GetLastError()); - }, + Err(_) => log::error!( + "Failed to get elevation status, error {}", + io::Error::last_os_error() + ), } } } @@ -1591,12 +1556,18 @@ pub fn is_elevated(process_id: Option) -> ResultType { None => GetCurrentProcess(), }; if handle == NULL { - bail!("Failed to open process, errno {}", GetLastError()) + bail!( + "Failed to open process, error {}", + io::Error::last_os_error() + ) } let _handle = RAIIHandle(handle); let mut token: HANDLE = mem::zeroed(); if OpenProcessToken(handle, TOKEN_QUERY, &mut token) == FALSE { - bail!("Failed to open process token, errno {}", GetLastError()) + bail!( + "Failed to open process token, error {}", + io::Error::last_os_error() + ) } let _token = RAIIHandle(token); let mut token_elevation: TOKEN_ELEVATION = mem::zeroed(); @@ -1609,7 +1580,10 @@ pub fn is_elevated(process_id: Option) -> ResultType { &mut size, ) == FALSE { - bail!("Failed to get token information, errno {}", GetLastError()) + bail!( + "Failed to get token information, error {}", + io::Error::last_os_error() + ) } Ok(token_elevation.TokenIsElevated != 0) @@ -1621,7 +1595,10 @@ pub fn is_foreground_window_elevated() -> ResultType { let mut process_id: DWORD = 0; GetWindowThreadProcessId(GetForegroundWindow(), &mut process_id); if process_id == 0 { - bail!("Failed to get processId, errno {}", GetLastError()) + bail!( + "Failed to get processId, error {}", + io::Error::last_os_error() + ) } is_elevated(Some(process_id)) } @@ -1723,11 +1700,11 @@ pub fn create_process_with_logon(user: &str, pwd: &str, exe: &str, arg: &str) -> { let last_error = GetLastError(); bail!( - "CreateProcessWithLogonW failed : \"{}\", errno={}", + "CreateProcessWithLogonW failed : \"{}\", error {}", last_error_table .get(&last_error) .unwrap_or(&"Unknown error"), - last_error + io::Error::from_raw_os_error(last_error as _) ); } } @@ -1786,8 +1763,8 @@ pub fn current_resolution(name: &str) -> ResultType { dm.dmSize = std::mem::size_of::() as _; if EnumDisplaySettingsW(device_name.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) == 0 { bail!( - "failed to get currrent resolution, errno={}", - GetLastError() + "failed to get currrent resolution, error {}", + io::Error::last_os_error() ); } let r = Resolution { @@ -1820,9 +1797,9 @@ pub(super) fn change_resolution_directly( ); if res != DISP_CHANGE_SUCCESSFUL { bail!( - "ChangeDisplaySettingsExW failed, res={}, errno={}", + "ChangeDisplaySettingsExW failed, res={}, error {}", res, - GetLastError() + io::Error::last_os_error() ); } Ok(()) diff --git a/src/privacy_mode/win_input.rs b/src/privacy_mode/win_input.rs index 486f3b5e4..29c87dc18 100644 --- a/src/privacy_mode/win_input.rs +++ b/src/privacy_mode/win_input.rs @@ -1,7 +1,10 @@ use hbb_common::{allow_err, bail, lazy_static, log, ResultType}; -use std::sync::{ - mpsc::{channel, Sender}, - Mutex, +use std::{ + io::Error, + sync::{ + mpsc::{channel, Sender}, + Mutex, + }, }; use winapi::{ ctypes::c_int, @@ -10,10 +13,7 @@ use winapi::{ ntdef::NULL, windef::{HHOOK, POINT}, }, - um::{ - errhandlingapi::GetLastError, libloaderapi::GetModuleHandleExA, - processthreadsapi::GetCurrentThreadId, winuser::*, - }, + um::{libloaderapi::GetModuleHandleExA, processthreadsapi::GetCurrentThreadId, winuser::*}, }; const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2; @@ -44,7 +44,7 @@ fn do_hook(tx: Sender) -> ResultType<(HHOOK, HHOOK)> { ) { tx.send(format!( "Failed to GetModuleHandleExA, error: {}", - GetLastError() + Error::last_os_error() ))?; return Ok(invalid_ret); } @@ -56,7 +56,7 @@ fn do_hook(tx: Sender) -> ResultType<(HHOOK, HHOOK)> { ) { tx.send(format!( "Failed to GetModuleHandleExA, error: {}", - GetLastError() + Error::last_os_error() ))?; return Ok(invalid_ret); } @@ -68,7 +68,10 @@ fn do_hook(tx: Sender) -> ResultType<(HHOOK, HHOOK)> { 0, ); if hook_keyboard.is_null() { - tx.send(format!(" SetWindowsHookExA keyboard {}", GetLastError()))?; + tx.send(format!( + " SetWindowsHookExA keyboard, error {}", + Error::last_os_error() + ))?; return Ok(invalid_ret); } @@ -76,9 +79,15 @@ fn do_hook(tx: Sender) -> ResultType<(HHOOK, HHOOK)> { if hook_mouse.is_null() { if FALSE == UnhookWindowsHookEx(hook_keyboard) { // Fatal error - log::error!(" UnhookWindowsHookEx keyboard {}", GetLastError()); + log::error!( + " UnhookWindowsHookEx keyboard, error {}", + Error::last_os_error() + ); } - tx.send(format!(" SetWindowsHookExA mouse {}", GetLastError()))?; + tx.send(format!( + " SetWindowsHookExA mouse, error {}", + Error::last_os_error() + ))?; return Ok(invalid_ret); } @@ -131,12 +140,18 @@ pub fn hook() -> ResultType<()> { if FALSE == UnhookWindowsHookEx(hook_keyboard as _) { // Fatal error - log::error!("Failed UnhookWindowsHookEx keyboard {}", GetLastError()); + log::error!( + "Failed UnhookWindowsHookEx keyboard, error {}", + Error::last_os_error() + ); } if FALSE == UnhookWindowsHookEx(hook_mouse as _) { // Fatal error - log::error!("Failed UnhookWindowsHookEx mouse {}", GetLastError()); + log::error!( + "Failed UnhookWindowsHookEx mouse, error {}", + Error::last_os_error() + ); } *CUR_HOOK_THREAD_ID.lock().unwrap() = 0; @@ -162,7 +177,10 @@ pub fn unhook() -> ResultType<()> { let cur_hook_thread_id = CUR_HOOK_THREAD_ID.lock().unwrap(); if *cur_hook_thread_id != 0 { if FALSE == PostThreadMessageA(*cur_hook_thread_id, WM_USER_EXIT_HOOK, 0, 0) { - bail!("Failed to post message to exit hook, {}", GetLastError()); + bail!( + "Failed to post message to exit hook, error {}", + Error::last_os_error() + ); } } } diff --git a/src/privacy_mode/win_topmost_window.rs b/src/privacy_mode/win_topmost_window.rs index 687f59155..7fd27b60b 100644 --- a/src/privacy_mode/win_topmost_window.rs +++ b/src/privacy_mode/win_topmost_window.rs @@ -3,6 +3,7 @@ use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState}; use hbb_common::{allow_err, bail, log, ResultType}; use std::{ ffi::CString, + io::Error, time::{Duration, Instant}, }; use winapi::{ @@ -12,7 +13,6 @@ use winapi::{ windef::HWND, }, um::{ - errhandlingapi::GetLastError, handleapi::CloseHandle, libloaderapi::{GetModuleHandleA, GetProcAddress}, memoryapi::{VirtualAllocEx, WriteProcessMemory}, @@ -266,9 +266,9 @@ impl PrivacyModeImpl { CloseHandle(token); if 0 == create_res { bail!( - "Failed to create privacy window process {}, code {}", + "Failed to create privacy window process {}, error {}", cmdline, - GetLastError() + Error::last_os_error() ); }; @@ -284,8 +284,8 @@ impl PrivacyModeImpl { CloseHandle(proc_info.hProcess); bail!( - "Failed to create privacy window process, {}", - GetLastError() + "Failed to create privacy window process, error {}", + Error::last_os_error() ); } diff --git a/src/privacy_mode/win_virtual_display.rs b/src/privacy_mode/win_virtual_display.rs index 8183d3275..372479b5d 100644 --- a/src/privacy_mode/win_virtual_display.rs +++ b/src/privacy_mode/win_virtual_display.rs @@ -1,7 +1,10 @@ use super::{PrivacyMode, PrivacyModeState, INVALID_PRIVACY_MODE_CONN_ID, NO_DISPLAYS}; use crate::virtual_display_manager; use hbb_common::{allow_err, bail, config::Config, log, ResultType}; -use std::ops::{Deref, DerefMut}; +use std::{ + io::Error, + ops::{Deref, DerefMut}, +}; use virtual_display::MonitorMode; use winapi::{ shared::{ @@ -9,7 +12,6 @@ use winapi::{ ntdef::{NULL, WCHAR}, }, um::{ - errhandlingapi::GetLastError, wingdi::{ DEVMODEW, DISPLAY_DEVICEW, DISPLAY_DEVICE_ACTIVE, DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, DISPLAY_DEVICE_MIRRORING_DRIVER, DISPLAY_DEVICE_PRIMARY_DEVICE, DM_POSITION, @@ -193,9 +195,9 @@ impl PrivacyModeImpl { ) { bail!( - "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", + "Failed EnumDisplaySettingsW, device name: {:?}, error: {}", std::string::String::from_utf16(&display.name), - GetLastError() + Error::last_os_error() ); } @@ -227,9 +229,9 @@ impl PrivacyModeImpl { == EnumDisplaySettingsW(dd.DeviceName.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) { bail!( - "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", + "Failed EnumDisplaySettingsW, device name: {:?}, error: {}", std::string::String::from_utf16(&dd.DeviceName), - GetLastError() + Error::last_os_error() ); } diff --git a/src/server/connection.rs b/src/server/connection.rs index 12e52afba..464edfb37 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2357,10 +2357,28 @@ impl Connection { #[cfg(all(windows, feature = "virtual_display_driver"))] async fn toggle_virtual_display(&mut self, t: ToggleVirtualDisplay) { + let make_msg = |text: String| { + let mut msg_out = Message::new(); + let res = MessageBox { + msgtype: "nook-nocancel-hasclose".to_owned(), + title: "Virtual display".to_owned(), + text, + link: "".to_owned(), + ..Default::default() + }; + msg_out.set_message_box(res); + msg_out + }; + if t.on { if let Err(e) = virtual_display_manager::plug_in_index_modes(t.display as _, Vec::new()) { log::error!("Failed to plug in virtual display: {}", e); + self.send(make_msg(format!( + "Failed to plug in virtual display: {}", + e + ))) + .await; } } else { let indices = if t.display == -1 { @@ -2370,6 +2388,11 @@ impl Connection { }; if let Err(e) = virtual_display_manager::plug_out_peer_request(&indices) { log::error!("Failed to plug out virtual display {:?}: {}", &indices, e); + self.send(make_msg(format!( + "Failed to plug out virtual displays: {}", + e + ))) + .await; } } }