From e6bf858ae1b82cc62c0c53d9ec3c74775ed63fcc Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 11 Mar 2022 19:51:57 +0800 Subject: [PATCH] virtual display: compile example ok, not debug yet Signed-off-by: fufesou --- Cargo.lock | 12 + Cargo.toml | 3 +- libs/virtual_display/Cargo.toml | 15 + libs/virtual_display/README.md | 32 + libs/virtual_display/build.rs | 35 + .../examples/idd_controller.rs | 137 +++ libs/virtual_display/src/lib.rs | 2 + .../virtual_display/src/win10/IddController.c | 783 ++++++++++++++++++ .../virtual_display/src/win10/IddController.h | 141 ++++ libs/virtual_display/src/win10/Public.h | 50 ++ libs/virtual_display/src/win10/idd.rs | 215 +++++ libs/virtual_display/src/win10/mod.rs | 1 + 12 files changed, 1425 insertions(+), 1 deletion(-) create mode 100644 libs/virtual_display/Cargo.toml create mode 100644 libs/virtual_display/README.md create mode 100644 libs/virtual_display/build.rs create mode 100644 libs/virtual_display/examples/idd_controller.rs create mode 100644 libs/virtual_display/src/lib.rs create mode 100644 libs/virtual_display/src/win10/IddController.c create mode 100644 libs/virtual_display/src/win10/IddController.h create mode 100644 libs/virtual_display/src/win10/Public.h create mode 100644 libs/virtual_display/src/win10/idd.rs create mode 100644 libs/virtual_display/src/win10/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 4f1d53cd0..0c2daa406 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3444,6 +3444,7 @@ dependencies = [ "sysinfo", "systray", "uuid", + "virtual_display", "whoami", "winapi 0.3.9", "windows-service", @@ -4180,6 +4181,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtual_display" +version = "0.1.0" +dependencies = [ + "cc", + "lazy_static", + "serde 1.0.136", + "serde_derive", + "thiserror", +] + [[package]] name = "walkdir" version = "2.3.2" diff --git a/Cargo.toml b/Cargo.toml index 7cab6e7a6..7df6eca3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ scrap = { path = "libs/scrap" } hbb_common = { path = "libs/hbb_common" } enigo = { path = "libs/enigo" } clipboard = { path = "libs/clipboard" } +virtual_display = { path = "libs/virtual_display" } sys-locale = "0.1" serde_derive = "1.0" serde = "1.0" @@ -83,7 +84,7 @@ rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" } android_logger = "0.10" [workspace] -members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard"] +members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display"] [package.metadata.winres] LegalCopyright = "Copyright © 2020" diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml new file mode 100644 index 000000000..19da85222 --- /dev/null +++ b/libs/virtual_display/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "virtual_display" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +cc = "1.0" + +[dependencies] +thiserror = "1.0.30" +lazy_static = "1.4" +serde = "1.0" +serde_derive = "1.0" diff --git a/libs/virtual_display/README.md b/libs/virtual_display/README.md new file mode 100644 index 000000000..dbc4ac6bd --- /dev/null +++ b/libs/virtual_display/README.md @@ -0,0 +1,32 @@ +# virtual display + +Virtual display may be used on computers that do not have a monitor. + +[Development reference](https://github.com/pavlobu/deskreen/discussions/86) + +## windows + +### win10 + +Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx). + +This lib use [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver. + + +**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display). + + +#### tested platforms + +- [x] 19041 + + +### win7 + +TODO + +[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide). + +## X11 + +## OSX diff --git a/libs/virtual_display/build.rs b/libs/virtual_display/build.rs new file mode 100644 index 000000000..177d92371 --- /dev/null +++ b/libs/virtual_display/build.rs @@ -0,0 +1,35 @@ +use cc; + +fn build_c_impl() { + let mut build = cc::Build::new(); + + #[cfg(target_os = "windows")] + build.file("src/win10/IddController.c"); + + build.flag_if_supported("-Wno-c++0x-extensions"); + build.flag_if_supported("-Wno-return-type-c-linkage"); + build.flag_if_supported("-Wno-invalid-offsetof"); + build.flag_if_supported("-Wno-unused-parameter"); + + if build.get_compiler().is_like_msvc() { + build.define("WIN32", ""); + build.flag("-Zi"); + build.flag("-GR-"); + // build.flag("-std:c++11"); + } else { + build.flag("-fPIC"); + // build.flag("-std=c++11"); + // build.flag("-include"); + // build.flag(&confdefs_path.to_string_lossy()); + } + + #[cfg(target_os = "windows")] + build.compile("xxx"); + + #[cfg(target_os = "windows")] + println!("cargo:rerun-if-changed=src/win10/IddController.c"); +} + +fn main() { + build_c_impl(); +} diff --git a/libs/virtual_display/examples/idd_controller.rs b/libs/virtual_display/examples/idd_controller.rs new file mode 100644 index 000000000..a91b39181 --- /dev/null +++ b/libs/virtual_display/examples/idd_controller.rs @@ -0,0 +1,137 @@ +#[cfg(windows)] +use virtual_display::win10::idd; + +use std::{ + ffi::{CStr, CString}, + io::{self, Read}, + path::Path, +}; + +fn prompt_input() -> u8 { + println!("Press key execute:"); + println!(" 1. 'x' 1. exit"); + println!(" 2. 'i' 2. install or update driver"); + println!(" 3. 'u' 3. uninstall driver"); + println!(" 4. 'c' 4. create device"); + println!(" 5. 'd' 5. destroy device"); + println!(" 6. '1','2','3' 6. plug in monitor 0,1,2"); + println!(" 7. '4','5','6' 7. plug out monitor 0,1,2"); + + io::stdin() + .bytes() + .next() + .and_then(|result| result.ok()) + .unwrap_or(0) +} + +unsafe fn plug_in(index: idd::UINT) { + println!("Plug in monitor begin"); + if idd::FALSE == idd::MonitorPlugIn(index, 25) { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + } else { + println!("Plug in monitor done"); + + let mut modes: Vec = Vec::new(); + modes.push(idd::MonitorMode { + width: 1920 as idd::DWORD, + height: 1080 as idd::DWORD, + sync: 60 as idd::DWORD, + }); + modes.push(idd::MonitorMode { + width: 1024 as idd::DWORD, + height: 768 as idd::DWORD, + sync: 60 as idd::DWORD, + }); + if idd::FALSE == idd::MonitorModesUpdate(index, modes.len() as u32, modes.as_mut_ptr()) { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + } + } +} + +unsafe fn plug_out(index: idd::UINT) { + println!("Plug out monitor begin"); + if idd::FALSE == idd::MonitorPlugOut(index) { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + } else { + println!("Plug out monitor done"); + } +} + +fn main() { + let relative_path = "RustDeskIddDriver/RustDeskIddDriver.inf"; + let abs_path = Path::new(relative_path).canonicalize().unwrap(); + let full_inf_path = abs_path.to_str().unwrap(); + + unsafe { + let invalid_device = 0 as idd::HSWDEVICE; + let mut h_sw_device = invalid_device; + let full_inf_path = CString::new(full_inf_path).unwrap().into_raw(); + loop { + match prompt_input() as char { + 'x' => break, + 'i' => { + println!("Install or update driver begin"); + let mut reboot_required = idd::FALSE; + if idd::InstallUpdate(full_inf_path, &mut reboot_required) == idd::FALSE { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + } else { + println!( + "Install or update driver done, reboot is {} required", + if reboot_required == idd::FALSE { + "not" + } else { + "" + } + ); + } + } + 'u' => { + println!("Uninstall driver begin"); + let mut reboot_required = idd::FALSE; + if idd::Uninstall(full_inf_path, &mut reboot_required) == idd::FALSE { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + } else { + println!( + "Uninstall driver done, reboot is {} required", + if reboot_required == idd::FALSE { + "not" + } else { + "" + } + ); + } + } + 'c' => { + println!("Create device begin"); + if h_sw_device != invalid_device { + println!("Device created before"); + break; + } + if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) { + println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); + idd::DeviceClose(h_sw_device); + h_sw_device = invalid_device; + } else { + println!("Create device done"); + } + } + 'd' => { + println!("Close device begin"); + idd::DeviceClose(h_sw_device); + h_sw_device = invalid_device; + println!("Close device done"); + } + '1' => plug_in(0), + '2' => plug_in(1), + '3' => plug_in(2), + '4' => plug_out(0), + '5' => plug_out(1), + '6' => plug_out(2), + _ => {} + } + } + if !full_inf_path.is_null() { + let _ = CString::from_raw(full_inf_path); + } + } +} diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs new file mode 100644 index 000000000..425e873d5 --- /dev/null +++ b/libs/virtual_display/src/lib.rs @@ -0,0 +1,2 @@ +#[cfg(windows)] +pub mod win10; diff --git a/libs/virtual_display/src/win10/IddController.c b/libs/virtual_display/src/win10/IddController.c new file mode 100644 index 000000000..49f9beee0 --- /dev/null +++ b/libs/virtual_display/src/win10/IddController.c @@ -0,0 +1,783 @@ +#include "./IddController.h" +#include +#include +#include +#include +#include +#include +#include + +#include "./Public.h" + + +const GUID GUID_DEVINTERFACE_IDD_DRIVER_DEVICE = \ +{ 0x781EF630, 0x72B2, 0x11d2, { 0xB8, 0x52, 0x00, 0xC0, 0x4E, 0xAF, 0x52, 0x72 } }; +//{781EF630-72B2-11d2-B852-00C04EAF5272} + +BOOL g_printMsg = TRUE; +char g_lastMsg[1024]; +const char* g_msgHeader = "RustDeskIdd: "; + +VOID WINAPI +CreationCallback( + _In_ HSWDEVICE hSwDevice, + _In_ HRESULT hrCreateResult, + _In_opt_ PVOID pContext, + _In_opt_ PCWSTR pszDeviceInstanceId +); +// https://github.com/microsoft/Windows-driver-samples/blob/9f03207ae1e8df83325f067de84494ae55ab5e97/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_testapp/testapp.c#L88 +// Not a good way for this device, I don't not why. I'm not familiar with dirver. +BOOLEAN GetDevicePath( + _In_ LPCGUID InterfaceGuid, + _Out_writes_(BufLen) PTCHAR DevicePath, + _In_ size_t BufLen +); +// https://github.com/microsoft/Windows-driver-samples/blob/9f03207ae1e8df83325f067de84494ae55ab5e97/usb/umdf_fx2/exe/testapp.c#L90 +// Works good to check whether device is created before. +BOOLEAN GetDevicePath2( + _In_ LPCGUID InterfaceGuid, + _Out_writes_(BufLen) PTCHAR DevicePath, + _In_ size_t BufLen +); + +HANDLE DeviceOpenHandle(); +VOID DeviceCloseHandle(HANDLE handle); + +void SetLastMsg(const char* format, ...) +{ + memset(g_lastMsg, 0, sizeof(g_lastMsg)); + memcpy_s(g_lastMsg, sizeof(g_lastMsg), g_msgHeader, strlen(g_msgHeader)); + + va_list args; + va_start(args, format); + vsnprintf_s( + g_lastMsg + strlen(g_msgHeader), + sizeof(g_lastMsg) - strlen(g_msgHeader), + _TRUNCATE, + format, + args); + va_end(args); +} + +const char* GetLastMsg() +{ + return g_lastMsg; +} + +BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired) +{ + SetLastMsg("Sucess"); + + // UpdateDriverForPlugAndPlayDevices may return FALSE while driver was successfully installed... + if (FALSE == UpdateDriverForPlugAndPlayDevices( + NULL, + _T("RustDeskIddDriver"), // match hardware id in the inf file + fullInfPath, + INSTALLFLAG_FORCE + // | INSTALLFLAG_NONINTERACTIVE // INSTALLFLAG_NONINTERACTIVE may cause error 0xe0000247 + , + rebootRequired + )) + { + DWORD error = GetLastError(); + if (error != 0) + { + SetLastMsg("UpdateDriverForPlugAndPlayDevices failed, last error 0x%x\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + } + + return TRUE; +} + +BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired) +{ + SetLastMsg("Sucess"); + + if (FALSE == DiUninstallDriver( + NULL, + fullInfPath, + 0, + rebootRequired + )) + { + DWORD error = GetLastError(); + if (error != 0) + { + SetLastMsg("DiUninstallDriver failed, last error 0x%x\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + } + + return TRUE; +} + +BOOL IsDeviceCreated(PBOOL created) +{ + SetLastMsg("Sucess"); + + HDEVINFO hardwareDeviceInfo = SetupDiGetClassDevs( + &GUID_DEVINTERFACE_IDD_DRIVER_DEVICE, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + SetLastMsg("Idd device: SetupDiGetClassDevs failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + BOOL ret = FALSE; + do + { + if (TRUE == SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, + 0, // No care about specific PDOs + &GUID_DEVINTERFACE_IDD_DRIVER_DEVICE, + 0, // + &deviceInterfaceData)) + { + *created = TRUE; + ret = TRUE; + break; + } + + DWORD error = GetLastError(); + if (error == ERROR_NO_MORE_ITEMS) + { + *created = FALSE; + ret = TRUE; + break; + } + + SetLastMsg("Idd device: SetupDiEnumDeviceInterfaces failed, last error 0x%x\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + ret = FALSE; + break; + + } while (0); + + (VOID)SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + return ret; +} + +BOOL DeviceCreate(PHSWDEVICE hSwDevice) +{ + SetLastMsg("Sucess"); + + if (*hSwDevice != NULL) + { + SetLastMsg("Device handler is not NULL\n"); + return FALSE; + } + + BOOL created = TRUE; + if (FALSE == IsDeviceCreated(&created)) + { + return FALSE; + } + if (created == TRUE) + { + SetLastMsg("Device is created before, please uninstall it first\n"); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + + // create device + HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL) + { + DWORD error = GetLastError(); + SetLastMsg("CreateEvent failed 0x%lx\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + + return FALSE; + } + + SW_DEVICE_CREATE_INFO createInfo = { 0 }; + PCWSTR description = L"RustDesk Idd Driver"; + + // These match the Pnp id's in the inf file so OS will load the driver when the device is created + PCWSTR instanceId = L"RustDeskIddDriver"; + PCWSTR hardwareIds = L"RustDeskIddDriver\0\0"; + PCWSTR compatibleIds = L"RustDeskIddDriver\0\0"; + + createInfo.cbSize = sizeof(createInfo); + createInfo.pszzCompatibleIds = compatibleIds; + createInfo.pszInstanceId = instanceId; + createInfo.pszzHardwareIds = hardwareIds; + createInfo.pszDeviceDescription = description; + + createInfo.CapabilityFlags = SWDeviceCapabilitiesRemovable | + SWDeviceCapabilitiesSilentInstall | + SWDeviceCapabilitiesDriverRequired; + + // Create the device + HRESULT hr = SwDeviceCreate(L"RustDeskIddDriver", + L"HTREE\\ROOT\\0", + &createInfo, + 0, + NULL, + CreationCallback, + &hEvent, + hSwDevice); + if (FAILED(hr)) + { + SetLastMsg("SwDeviceCreate failed with 0x%lx\n", hr); + if (g_printMsg) + { + printf(g_lastMsg); + } + + return FALSE; + } + + // 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); + if (waitResult != WAIT_OBJECT_0) + { + SetLastMsg("Wait for device creation failed 0x%d\n", waitResult); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + // printf("Device created\n\n"); + return TRUE; +} + +VOID DeviceClose(HSWDEVICE hSwDevice) +{ + SetLastMsg("Sucess"); + + if (hSwDevice != INVALID_HANDLE_VALUE && hSwDevice != NULL) + { + SwDeviceClose(hSwDevice); + } +} + +BOOL MonitorPlugIn(UINT index, INT retries) +{ + SetLastMsg("Sucess"); + + if (retries < 0) + { + SetLastMsg("invalid tries %d\n", retries); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + + HANDLE hDevice = INVALID_HANDLE_VALUE; + for (; retries >= 0; --retries) + { + hDevice = DeviceOpenHandle(); + if (hDevice != INVALID_HANDLE_VALUE && hDevice != NULL) + { + break; + } + Sleep(1000); + } + if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) + { + return FALSE; + } + + BOOL ret = FALSE; + DWORD junk = 0; + CtlPlugIn plugIn; + plugIn.ConnectorIndex = index; + HRESULT hr = CoCreateGuid(&plugIn.ContainerId); + if (!SUCCEEDED(hr)) + { + SetLastMsg("CoCreateGuid failed %d\n", hr); + if (g_printMsg) + { + printf(g_lastMsg); + } + ret = FALSE; + } + else + { + ret = FALSE; + for (; retries >= 0; --retries) + { + if (TRUE == DeviceIoControl( + hDevice, + IOCTL_CHANGER_IDD_PLUG_IN, + &plugIn, // Ptr to InBuffer + sizeof(CtlPlugIn), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &junk, // BytesReturned + 0)) // Ptr to Overlapped structure + { + ret = TRUE; + break; + } + } + if (ret == FALSE) + { + DWORD error = GetLastError(); + SetLastMsg("DeviceIoControl failed 0x%lx\n", error); + printf(g_lastMsg); + } + } + + DeviceCloseHandle(hDevice); + return ret; +} + +BOOL MonitorPlugOut(UINT index) +{ + SetLastMsg("Sucess"); + + HANDLE hDevice = DeviceOpenHandle(); + if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) + { + return FALSE; + } + + BOOL ret = FALSE; + DWORD junk = 0; + CtlPlugOut plugOut; + plugOut.ConnectorIndex = index; + if (!DeviceIoControl( + hDevice, + IOCTL_CHANGER_IDD_PLUG_OUT, + &plugOut, // Ptr to InBuffer + sizeof(CtlPlugOut), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &junk, // BytesReturned + 0)) // Ptr to Overlapped structure + { + DWORD error = GetLastError(); + SetLastMsg("DeviceIoControl failed 0x%lx\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + ret = FALSE; + } + else + { + ret = TRUE; + } + + DeviceCloseHandle(hDevice); + return ret; +} + +BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes) +{ + SetLastMsg("Sucess"); + + HANDLE hDevice = DeviceOpenHandle(); + if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) + { + return FALSE; + } + + BOOL ret = FALSE; + DWORD junk = 0; + size_t buflen = sizeof(UINT) * 2 + modeCount * sizeof(MonitorMode); + PCtlMonitorModes pMonitorModes = (PCtlMonitorModes)malloc(buflen); + if (pMonitorModes == NULL) + { + SetLastMsg("CtlMonitorModes malloc failed 0x%lx\n"); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + + pMonitorModes->ConnectorIndex = index; + pMonitorModes->ModeCount = modeCount; + for (UINT i = 0; i < modeCount; ++i) + { + pMonitorModes->Modes[i].Width = modes[i].width; + pMonitorModes->Modes[i].Height = modes[i].height; + pMonitorModes->Modes[i].Sync = modes[i].sync; + } + if (!DeviceIoControl( + hDevice, + IOCTL_CHANGER_IDD_UPDATE_MONITOR_MODE, + pMonitorModes, // Ptr to InBuffer + buflen, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &junk, // BytesReturned + 0)) // Ptr to Overlapped structure + { + DWORD error = GetLastError(); + SetLastMsg("DeviceIoControl failed 0x%lx\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + ret = FALSE; + } + else + { + ret = TRUE; + } + + free(pMonitorModes); + DeviceCloseHandle(hDevice); + return ret; +} + +VOID WINAPI +CreationCallback( + _In_ HSWDEVICE hSwDevice, + _In_ HRESULT hrCreateResult, + _In_opt_ PVOID pContext, + _In_opt_ PCWSTR pszDeviceInstanceId +) +{ + HANDLE hEvent = *(HANDLE*)pContext; + + SetEvent(hEvent); + UNREFERENCED_PARAMETER(hSwDevice); + UNREFERENCED_PARAMETER(hrCreateResult); + // printf("Idd device %ls created\n", pszDeviceInstanceId); +} + +BOOLEAN +GetDevicePath( + _In_ LPCGUID InterfaceGuid, + _Out_writes_(BufLen) PTCHAR DevicePath, + _In_ size_t BufLen +) +{ + CONFIGRET cr = CR_SUCCESS; + PTSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PTSTR nextInterface; + HRESULT hr = E_FAIL; + BOOLEAN bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + (LPGUID)InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES); + if (cr != CR_SUCCESS) + { + SetLastMsg("Error GetDevicePath 0x%x retrieving device interface list size.\n", cr); + if (g_printMsg) + { + printf(g_lastMsg); + } + + goto clean0; + } + + // CAUTION: BUG here. deviceInterfaceListLength is greater than 1, even device was not created... + if (deviceInterfaceListLength <= 1) + { + SetLastMsg("Error: GetDevicePath No active device interfaces found. Is the sample driver loaded?\n"); + if (g_printMsg) + { + printf(g_lastMsg); + } + bRet = FALSE; + goto clean0; + } + + deviceInterfaceList = (PTSTR)malloc(deviceInterfaceListLength * sizeof(TCHAR)); + if (deviceInterfaceList == NULL) + { + SetLastMsg("Error GetDevicePath allocating memory for device interface list.\n"); + if (g_printMsg) + { + printf(g_lastMsg); + } + bRet = FALSE; + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(TCHAR)); + + for (int i = 0; i < 3 && _tcslen(deviceInterfaceList) == 0; i++) + { + // CAUTION: BUG here. deviceInterfaceList is NULL, even device was not created... + cr = CM_Get_Device_Interface_List( + (LPGUID)InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) + { + SetLastMsg("Error GetDevicePath 0x%x retrieving device interface list.\n", cr); + if (g_printMsg) + { + printf(g_lastMsg); + } + goto clean0; + } + _tprintf(_T("get deviceInterfaceList %s\n"), deviceInterfaceList); + Sleep(1000); + } + + nextInterface = deviceInterfaceList + _tcslen(deviceInterfaceList) + 1; +#ifdef UNICODE + if (*nextInterface != UNICODE_NULL) { +#else + if (*nextInterface != ANSI_NULL) { +#endif + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); + } + + printf("begin copy device path\n"); + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) + { + SetLastMsg("Error: GetDevicePath StringCchCopy failed with HRESULT 0x%x", hr); + if (g_printMsg) + { + printf(g_lastMsg); + } + bRet = FALSE; + goto clean0; + } + +clean0: + if (deviceInterfaceList != NULL) + { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) + { + bRet = FALSE; + } + + return bRet; +} + +BOOLEAN GetDevicePath2( + _In_ LPCGUID InterfaceGuid, + _Out_writes_(BufLen) PTCHAR DevicePath, + _In_ size_t BufLen +) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + ULONG bytes; + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + BOOLEAN status = FALSE; + HRESULT hr; + + hardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + SetLastMsg("Idd device: SetupDiGetClassDevs failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + return FALSE; + } + + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + if (!SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, + 0, // No care about specific PDOs + InterfaceGuid, + 0, // + &deviceInterfaceData)) + { + SetLastMsg("Idd device: SetupDiEnumDeviceInterfaces failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + goto Clean0; + } + + // + // Allocate a function class device data structure to receive the + // information about this particular device. + // + SetupDiGetDeviceInterfaceDetail( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL);//not interested in the specific dev-node + + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) + { + SetLastMsg("Idd device: SetupDiGetDeviceInterfaceDetail failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + goto Clean0; + } + + predictedLength = requiredLength; + deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + predictedLength + ); + + if (deviceInterfaceDetailData) + { + deviceInterfaceDetailData->cbSize = + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + } + else + { + SetLastMsg("Idd device: HeapAlloc failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + goto Clean0; + } + + if (!SetupDiGetDeviceInterfaceDetail( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) + { + SetLastMsg("Idd device: SetupDiGetDeviceInterfaceDetail failed, last error 0x%x\n", GetLastError()); + if (g_printMsg) + { + printf(g_lastMsg); + } + goto Clean1; + } + + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceDetailData->DevicePath); + if (FAILED(hr)) + { + SetLastMsg("Error: StringCchCopy failed with HRESULT 0x%x", hr); + if (g_printMsg) + { + printf(g_lastMsg); + } + status = FALSE; + goto Clean1; + } + else + { + status = TRUE; + } + +Clean1: + (VOID)HeapFree(GetProcessHeap(), 0, deviceInterfaceDetailData); +Clean0: + (VOID)SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + return status; +} + +// https://stackoverflow.com/questions/67164846/createfile-fails-unless-i-disable-enable-my-device +HANDLE DeviceOpenHandle() +{ + SetLastMsg("Sucess"); + + // const int maxDevPathLen = 256; + TCHAR devicePath[256] = { 0 }; + HANDLE hDevice = INVALID_HANDLE_VALUE; + do + { + if (FALSE == GetDevicePath2( + &GUID_DEVINTERFACE_IDD_DRIVER_DEVICE, + devicePath, + sizeof(devicePath) / sizeof(devicePath[0]))) + { + break; + } + if (_tcslen(devicePath) == 0) + { + SetLastMsg("GetDevicePath got empty device path\n"); + if (g_printMsg) + { + printf(g_lastMsg); + } + break; + } + + _tprintf(_T("Idd device: try open %s\n"), devicePath); + hDevice = CreateFile( + devicePath, + GENERIC_READ | GENERIC_WRITE, + // FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL + ); + if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) + { + DWORD error = GetLastError(); + SetLastMsg("CreateFile failed 0x%lx\n", error); + if (g_printMsg) + { + printf(g_lastMsg); + } + } + } while (0); + + return hDevice; +} + +VOID DeviceCloseHandle(HANDLE handle) +{ + if (handle != INVALID_HANDLE_VALUE && handle != NULL) + { + CloseHandle(handle); + } +} + +VOID SetPrintErrMsg(BOOL b) +{ + g_printMsg = (b == TRUE); +} diff --git a/libs/virtual_display/src/win10/IddController.h b/libs/virtual_display/src/win10/IddController.h new file mode 100644 index 000000000..90d6c4295 --- /dev/null +++ b/libs/virtual_display/src/win10/IddController.h @@ -0,0 +1,141 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Install or Update RustDeskIddDriver. + * + * @param fullInfPath [in] Full path of the driver inf file. + * @param rebootRequired [out] Indicates whether a restart is required. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + */ +BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired); + +/** + * @brief Uninstall RustDeskIddDriver. + * + * @param fullInfPath [in] Full path of the driver inf file. + * @param rebootRequired [out] Indicates whether a restart is required. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + */ +BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired); + +/** + * @brief Check if RustDeskIddDriver device is created before. + * The driver device(adapter) should be single instance. + * + * @param created [out] Indicates whether the device is created before. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + * + */ +BOOL IsDeviceCreated(PBOOL created); + +/** + * @brief Create device. + * Only one device should be created. + * If device is installed ealier, this function returns FALSE. + * + * @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 DeviceCreate(PHSWDEVICE hSwDevice); + +/** + * @brief Close device. + * + * @param hSwDevice Handler of software device, used by SwDeviceClose(). + * + */ +VOID DeviceClose(HSWDEVICE hSwDevice); + +/** + * @brief Plug in monitor. + * + * @param index [in] Monitor index, should be 0, 1, 2. + * @param retries [in] Retry times. Retry 1 time / sec. 25~30 seconds may be good choices. + * -1 is invalid. + * 0 means doing once and no retries. + * 1 means doing once and retry one time... + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + * + * @remark Plug in monitor may fail if device is created in a very short time. + * System need some time to prepare the device. + * + */ +BOOL MonitorPlugIn(UINT index, INT retries); + +/** + * @brief Plug out monitor. + * + * @param index [in] Monitor index, should be 0, 1, 2. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + * + */ +BOOL MonitorPlugOut(UINT index); + +typedef struct _MonitorMode { + DWORD width; + DWORD height; + // Sync affects frequency. + DWORD sync; +} MonitorMode, *PMonitorMode; + +/** + * @brief Update monitor mode. + * + * @param index [in] Monitor index, should be 0, 1, 2. + * @param modeCount [in] Monitor mode count. + * @param MonitorMode [in] Monitor mode data. + * + * @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg() + * + * @see GetLastMsg#GetLastMsg + * + */ +BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes); + +/** + * @brief Get last error message. + * + * @return Message string. The string is at most 1024 bytes. + * + */ +const char* GetLastMsg(); + +/** + * @brief Set if print error message when debug. + * + * @param b [in] TRUE to enable printing message. + * + * @remark For now, no need to read evironment variable to check if should print. + * + */ +VOID SetPrintErrMsg(BOOL b); + +#ifdef __cplusplus +} +#endif diff --git a/libs/virtual_display/src/win10/Public.h b/libs/virtual_display/src/win10/Public.h new file mode 100644 index 000000000..547cf4351 --- /dev/null +++ b/libs/virtual_display/src/win10/Public.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +#define IOCTL_CHANGER_IDD_PLUG_IN CTL_CODE(IOCTL_CHANGER_BASE, \ + 0x1001, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CHANGER_IDD_PLUG_OUT CTL_CODE(IOCTL_CHANGER_BASE, \ + 0x1002, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CHANGER_IDD_UPDATE_MONITOR_MODE CTL_CODE(IOCTL_CHANGER_BASE, \ + 0x1003, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + + +#define STATUS_ERROR_ADAPTER_NOT_INIT (3 << 30) + 11 +//#define STATUS_ERROR_IO_CTL_GET_INPUT (3 << 30) + 21 +//#define STATUS_ERROR_IO_CTL_GET_OUTPUT (3 << 30) + 22 +#define STATUS_ERROR_MONITOR_EXISTS (3 << 30) + 51 +#define STATUS_ERROR_MONITOR_NOT_EXISTS (3 << 30) + 52 +#define STATUS_ERROR_MONITOR_INVALID_PARAM (3 << 30) + 53 +#define STATUS_ERROR_MONITOR_OOM (3 << 30) + 54 + +typedef struct _CtlPlugIn { + UINT ConnectorIndex; + GUID ContainerId; +} CtlPlugIn, *PCtlPlugIn; + +typedef struct _CtlPlugOut { + UINT ConnectorIndex; +} CtlPlugOut, *PCtlPlugOut; + +typedef struct _CtlMonitorModes { + UINT ConnectorIndex; + UINT ModeCount; + struct { + DWORD Width; + DWORD Height; + DWORD Sync; + } Modes[1]; +} CtlMonitorModes, *PCtlMonitorModes; + + +#define SYMBOLIC_LINK_NAME L"\\Device\\RustDeskIddDriver" + diff --git a/libs/virtual_display/src/win10/idd.rs b/libs/virtual_display/src/win10/idd.rs new file mode 100644 index 000000000..66a90b059 --- /dev/null +++ b/libs/virtual_display/src/win10/idd.rs @@ -0,0 +1,215 @@ +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(unused_variables)] +#![allow(non_snake_case)] +#![allow(deref_nullptr)] + +pub type size_t = ::std::os::raw::c_ulonglong; +pub type __vcrt_bool = bool; +pub type wchar_t = ::std::os::raw::c_ushort; + +pub type POINTER_64_INT = ::std::os::raw::c_ulonglong; +pub type INT8 = ::std::os::raw::c_schar; +pub type PINT8 = *mut ::std::os::raw::c_schar; +pub type INT16 = ::std::os::raw::c_short; +pub type PINT16 = *mut ::std::os::raw::c_short; +pub type INT32 = ::std::os::raw::c_int; +pub type PINT32 = *mut ::std::os::raw::c_int; +pub type INT64 = ::std::os::raw::c_longlong; +pub type PINT64 = *mut ::std::os::raw::c_longlong; +pub type UINT8 = ::std::os::raw::c_uchar; +pub type PUINT8 = *mut ::std::os::raw::c_uchar; +pub type UINT16 = ::std::os::raw::c_ushort; +pub type PUINT16 = *mut ::std::os::raw::c_ushort; +pub type UINT32 = ::std::os::raw::c_uint; +pub type PUINT32 = *mut ::std::os::raw::c_uint; +pub type UINT64 = ::std::os::raw::c_ulonglong; +pub type PUINT64 = *mut ::std::os::raw::c_ulonglong; +pub type LONG32 = ::std::os::raw::c_int; +pub type PLONG32 = *mut ::std::os::raw::c_int; +pub type ULONG32 = ::std::os::raw::c_uint; +pub type PULONG32 = *mut ::std::os::raw::c_uint; +pub type DWORD32 = ::std::os::raw::c_uint; +pub type PDWORD32 = *mut ::std::os::raw::c_uint; +pub type INT_PTR = ::std::os::raw::c_longlong; +pub type PINT_PTR = *mut ::std::os::raw::c_longlong; +pub type UINT_PTR = ::std::os::raw::c_ulonglong; +pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong; +pub type LONG_PTR = ::std::os::raw::c_longlong; +pub type PLONG_PTR = *mut ::std::os::raw::c_longlong; +pub type ULONG_PTR = ::std::os::raw::c_ulonglong; +pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong; +pub type SHANDLE_PTR = ::std::os::raw::c_longlong; +pub type HANDLE_PTR = ::std::os::raw::c_ulonglong; +pub type UHALF_PTR = ::std::os::raw::c_uint; +pub type PUHALF_PTR = *mut ::std::os::raw::c_uint; +pub type HALF_PTR = ::std::os::raw::c_int; +pub type PHALF_PTR = *mut ::std::os::raw::c_int; +pub type SIZE_T = ULONG_PTR; +pub type PSIZE_T = *mut ULONG_PTR; +pub type SSIZE_T = LONG_PTR; +pub type PSSIZE_T = *mut LONG_PTR; +pub type DWORD_PTR = ULONG_PTR; +pub type PDWORD_PTR = *mut ULONG_PTR; +pub type LONG64 = ::std::os::raw::c_longlong; +pub type PLONG64 = *mut ::std::os::raw::c_longlong; +pub type ULONG64 = ::std::os::raw::c_ulonglong; +pub type PULONG64 = *mut ::std::os::raw::c_ulonglong; +pub type DWORD64 = ::std::os::raw::c_ulonglong; +pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong; +pub type KAFFINITY = ULONG_PTR; +pub type PKAFFINITY = *mut KAFFINITY; +pub type PVOID = *mut ::std::os::raw::c_void; +pub type CHAR = ::std::os::raw::c_char; +pub type SHORT = ::std::os::raw::c_short; +pub type LONG = ::std::os::raw::c_long; +pub type WCHAR = wchar_t; +pub type PWCHAR = *mut WCHAR; +pub type LPWCH = *mut WCHAR; +pub type PWCH = *mut WCHAR; +pub type LPCWCH = *const WCHAR; +pub type PCWCH = *const WCHAR; +pub type NWPSTR = *mut WCHAR; +pub type LPWSTR = *mut WCHAR; +pub type PWSTR = *mut WCHAR; +pub type PZPWSTR = *mut PWSTR; +pub type PCZPWSTR = *const PWSTR; +pub type LPUWSTR = *mut WCHAR; +pub type PUWSTR = *mut WCHAR; +pub type LPCWSTR = *const WCHAR; +pub type PCWSTR = *const WCHAR; +pub type PZPCWSTR = *mut PCWSTR; +pub type PCZPCWSTR = *const PCWSTR; +pub type LPCUWSTR = *const WCHAR; +pub type PCUWSTR = *const WCHAR; +pub type PZZWSTR = *mut WCHAR; +pub type PCZZWSTR = *const WCHAR; +pub type PUZZWSTR = *mut WCHAR; +pub type PCUZZWSTR = *const WCHAR; +pub type PNZWCH = *mut WCHAR; +pub type PCNZWCH = *const WCHAR; +pub type PUNZWCH = *mut WCHAR; +pub type PCUNZWCH = *const WCHAR; +pub type PCHAR = *mut CHAR; +pub type LPCH = *mut CHAR; +pub type PCH = *mut CHAR; +pub type LPCCH = *const CHAR; +pub type PCCH = *const CHAR; +pub type NPSTR = *mut CHAR; +pub type LPSTR = *mut CHAR; +pub type PSTR = *mut CHAR; +pub type PZPSTR = *mut PSTR; +pub type PCZPSTR = *const PSTR; +pub type LPCSTR = *const CHAR; +pub type PCSTR = *const CHAR; +pub type PZPCSTR = *mut PCSTR; +pub type PCZPCSTR = *const PCSTR; +pub type PZZSTR = *mut CHAR; +pub type PCZZSTR = *const CHAR; +pub type PNZCH = *mut CHAR; +pub type PCNZCH = *const CHAR; +pub type TCHAR = ::std::os::raw::c_char; +pub type PTCHAR = *mut ::std::os::raw::c_char; +pub type TBYTE = ::std::os::raw::c_uchar; +pub type PTBYTE = *mut ::std::os::raw::c_uchar; +pub type LPTCH = LPCH; +pub type PTCH = LPCH; +pub type LPCTCH = LPCCH; +pub type PCTCH = LPCCH; +pub type PTSTR = LPSTR; +pub type LPTSTR = LPSTR; +pub type PUTSTR = LPSTR; +pub type LPUTSTR = LPSTR; +pub type PCTSTR = LPCSTR; +pub type LPCTSTR = LPCSTR; +pub type PCUTSTR = LPCSTR; +pub type LPCUTSTR = LPCSTR; +pub type PZZTSTR = PZZSTR; +pub type PUZZTSTR = PZZSTR; +pub type PCZZTSTR = PCZZSTR; +pub type PCUZZTSTR = PCZZSTR; +pub type PZPTSTR = PZPSTR; +pub type PNZTCH = PNZCH; +pub type PUNZTCH = PNZCH; +pub type PCNZTCH = PCNZCH; +pub type PCUNZTCH = PCNZCH; +pub type PSHORT = *mut SHORT; +pub type PLONG = *mut LONG; +pub type ULONG = ::std::os::raw::c_ulong; +pub type PULONG = *mut ULONG; +pub type USHORT = ::std::os::raw::c_ushort; +pub type PUSHORT = *mut USHORT; +pub type UCHAR = ::std::os::raw::c_uchar; +pub type PUCHAR = *mut UCHAR; +pub type PSZ = *mut ::std::os::raw::c_char; +pub type DWORD = ::std::os::raw::c_ulong; +pub type BOOL = ::std::os::raw::c_int; +pub type BYTE = ::std::os::raw::c_uchar; +pub type WORD = ::std::os::raw::c_ushort; +pub type FLOAT = f32; +pub type PFLOAT = *mut FLOAT; +pub type PBOOL = *mut BOOL; +pub type LPBOOL = *mut BOOL; +pub type PBYTE = *mut BYTE; +pub type LPBYTE = *mut BYTE; +pub type PINT = *mut ::std::os::raw::c_int; +pub type LPINT = *mut ::std::os::raw::c_int; +pub type PWORD = *mut WORD; +pub type LPWORD = *mut WORD; +pub type LPLONG = *mut ::std::os::raw::c_long; +pub type PDWORD = *mut DWORD; +pub type LPDWORD = *mut DWORD; +pub type LPVOID = *mut ::std::os::raw::c_void; +pub type LPCVOID = *const ::std::os::raw::c_void; +pub type INT = ::std::os::raw::c_int; +pub type UINT = ::std::os::raw::c_uint; +pub type PUINT = *mut ::std::os::raw::c_uint; +pub type va_list = *mut ::std::os::raw::c_char; + +pub const TRUE: ::std::os::raw::c_int = 1; +pub const FALSE: ::std::os::raw::c_int = 0; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _MonitorMode { + pub width: DWORD, + pub height: DWORD, + pub sync: DWORD, +} +pub type MonitorMode = _MonitorMode; +pub type PMonitorMode = *mut MonitorMode; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct HSWDEVICE__ { + pub unused: ::std::os::raw::c_int, +} +pub type HSWDEVICE = *mut HSWDEVICE__; +pub type PHSWDEVICE = *mut HSWDEVICE; + +#[link(name = "Newdev")] +extern "C" { + pub fn InstallUpdate(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL; +} + +#[link(name = "Setupapi")] +extern "C" { + pub fn IsDeviceCreated(created: PBOOL) -> BOOL; +} + +#[link(name = "Swdevice")] +#[link(name = "OneCoreUAP")] +extern "C" { + pub fn DeviceCreate(hSwDevice: PHSWDEVICE) -> BOOL; + pub fn DeviceClose(hSwDevice: HSWDEVICE); +} + +extern "C" { + pub fn Uninstall(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL; + pub fn MonitorPlugIn(index: UINT, retries: INT) -> BOOL; + pub fn MonitorPlugOut(index: UINT) -> BOOL; + pub fn MonitorModesUpdate(index: UINT, modeCount: UINT, modes: PMonitorMode) -> BOOL; + + pub fn GetLastMsg() -> PCHAR; + pub fn SetPrintErrMsg(b: BOOL); +} diff --git a/libs/virtual_display/src/win10/mod.rs b/libs/virtual_display/src/win10/mod.rs new file mode 100644 index 000000000..d8797d709 --- /dev/null +++ b/libs/virtual_display/src/win10/mod.rs @@ -0,0 +1 @@ +pub mod idd; \ No newline at end of file