diff --git a/libs/virtual_display/dylib/src/win10/IddController.c b/libs/virtual_display/dylib/src/win10/IddController.c index 1b177d47b..43322edf2 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: Install the cert.\n", error, errorString == NULL ? "(NULL)\n" : errorString); + break; + case 0xe0000247: + SetLastMsg("Failed InstallUpdate UpdateDriverForPlugAndPlayDevicesW, error: 0x%x, %s Please try: \n1. Uninstall the driver first.\n2. Install the cert.\n3. Check the device manager and event viewer.\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,7 +289,7 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) 0, NULL, CreationCallback, - &hEvent, + &callbackContext, hSwDevice); if (FAILED(hr)) { @@ -259,6 +305,7 @@ 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); @@ -268,8 +315,17 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) } return FALSE; } - // printf("Device created\n\n"); - return TRUE; + + if (SUCCEEDED(callbackContext.hrCreateResult)) + { + // printf("Device created\n\n"); + return TRUE; + } + else + { + SetLastMsg("Failed DeviceCreate SwDeviceCreate, hrCreateResult 0x%lx\n", callbackContext.hrCreateResult); + return FALSE; + } } VOID DeviceClose(HSWDEVICE hSwDevice) @@ -278,8 +334,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) @@ -348,8 +434,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 +476,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); @@ -441,7 +540,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 +570,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); } @@ -611,7 +734,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 +756,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 +782,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 +812,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 +834,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 +851,7 @@ BOOLEAN GetDevicePath2( hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceDetailData->DevicePath); if (FAILED(hr)) { - SetLastMsg("Error: Failed GetDevicePath2 StringCchCopy HRESULT 0x%x", hr); + SetLastMsg("Failed GetDevicePath2 StringCchCopy, HRESULT 0x%x", hr); if (g_printMsg) { printf(g_lastMsg); @@ -759,7 +912,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 +940,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);