| // Copyright (c) Microsoft Corporation |
| |
| #include "third_party/win_virtual_display/controller/display_driver_controller.h" |
| |
| #include <windows.h> |
| |
| #include <devguid.h> |
| #include <setupapi.h> |
| #include <swdevice.h> |
| #include <wrl.h> |
| #include <cstdio> |
| #include "base/logging.h" |
| |
| namespace display::test { |
| namespace { |
| |
| // These values should match the corresponding values in the driver .inf file. |
| constexpr wchar_t kDriverName[] = L"ChromiumVirtualDisplayDriver"; |
| // Dual null terminated for win32 API list. |
| constexpr wchar_t kDriverNameList[] = L"ChromiumVirtualDisplayDriver\0\0"; |
| constexpr wchar_t kDriverDeviceName[] = L"ChromiumVirtualDisplayDriver Device"; |
| constexpr wchar_t kDriverManufacturer[] = L"Chromium"; |
| constexpr wchar_t kDriverDescription[] = L"Chromium Virtual Display Driver"; |
| |
| VOID WINAPI CreationCallback(_In_ HSWDEVICE hSwDevice, |
| _In_ HRESULT hrCreateResult, |
| _In_opt_ PVOID pContext, |
| _In_opt_ PCWSTR pszDeviceInstanceId) { |
| HANDLE hEvent = *(HANDLE*)pContext; |
| if (!SetEvent(hEvent)) { |
| LOG(ERROR) << "SetEvent failed: " << GetLastError(); |
| } |
| } |
| |
| // Builds an array of DEVPROPERTY based off the specified config. |
| std::array<DEVPROPERTY, 1> BuildDevProperties(DriverProperties& config) { |
| std::array<DEVPROPERTY, 1> properties; |
| DEVPROPERTY& property = properties[0]; |
| property.Type = DEVPROP_TYPE_BINARY; |
| property.CompKey.Store = DEVPROP_STORE_SYSTEM; |
| property.CompKey.Key = DisplayConfigurationProperty; |
| property.CompKey.LocaleName = NULL; |
| property.BufferSize = sizeof(DriverProperties); |
| property.Buffer = &config; |
| return properties; |
| } |
| |
| } // namespace |
| |
| DisplayDriverController::~DisplayDriverController() { |
| Reset(); |
| } |
| |
| // static |
| bool DisplayDriverController::IsDriverInstalled() { |
| HDEVINFO hdevinfo = |
| SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0); |
| if (hdevinfo == INVALID_HANDLE_VALUE) { |
| LOG(ERROR) << "SetupDiGetClassDevsW failed: " << hdevinfo; |
| return false; |
| } |
| if (!SetupDiBuildDriverInfoList(hdevinfo, NULL, SPDIT_CLASSDRIVER)) { |
| LOG(ERROR) << "SetupDiBuildDriverInfoList failed: " << GetLastError(); |
| } |
| SP_DRVINFO_DATA_W drvdata; |
| drvdata.cbSize = sizeof(SP_DRVINFO_DATA_W); |
| for (DWORD index = 0; SetupDiEnumDriverInfoW( |
| hdevinfo, NULL, SPDIT_CLASSDRIVER, index++, &drvdata);) { |
| if (std::wstring(drvdata.Description) == kDriverDeviceName && |
| std::wstring(drvdata.MfgName) == kDriverManufacturer) { |
| SetupDiDestroyDeviceInfoList(hdevinfo); |
| return true; |
| } |
| } |
| DWORD error = GetLastError(); |
| LOG_IF(ERROR, error != ERROR_NO_MORE_ITEMS && error != ERROR_SUCCESS) |
| << "SetupDiEnumDriverInfoW failed: " << error; |
| SetupDiDestroyDeviceInfoList(hdevinfo); |
| return false; |
| } |
| |
| bool DisplayDriverController::SetDisplayConfig(DriverProperties config) { |
| if (device_handle_ == nullptr) { |
| return Initialize(config); |
| } |
| std::array<DEVPROPERTY, 1> properties = BuildDevProperties(config); |
| HRESULT hr = |
| SwDevicePropertySet(device_handle_, properties.size(), properties.data()); |
| return !FAILED(hr); |
| } |
| |
| void DisplayDriverController::Reset() { |
| if (device_handle_ != nullptr) { |
| SwDeviceClose(device_handle_); |
| device_handle_ = nullptr; |
| } |
| } |
| |
| bool DisplayDriverController::Initialize(DriverProperties config) { |
| HANDLE hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); |
| HSWDEVICE hSwDevice; |
| SW_DEVICE_CREATE_INFO createInfo = {0}; |
| |
| createInfo.cbSize = sizeof(createInfo); |
| createInfo.pszzCompatibleIds = kDriverNameList; |
| createInfo.pszInstanceId = kDriverName; |
| createInfo.pszzHardwareIds = kDriverNameList; |
| createInfo.pszDeviceDescription = kDriverDescription; |
| |
| createInfo.CapabilityFlags = SWDeviceCapabilitiesRemovable | |
| SWDeviceCapabilitiesSilentInstall | |
| SWDeviceCapabilitiesDriverRequired; |
| |
| std::array<DEVPROPERTY, 1> properties = BuildDevProperties(config); |
| // Create the device |
| HRESULT hr = SwDeviceCreate(kDriverName, L"HTREE\\ROOT\\0", &createInfo, |
| properties.size(), properties.data(), |
| CreationCallback, &hEvent, &hSwDevice); |
| if (FAILED(hr)) { |
| LOG(ERROR) << "SwDeviceCreate failed: " << std::hex << hr; |
| return false; |
| } |
| // Wait for callback to signal that the device has been created |
| DWORD waitResult = WaitForSingleObject(hEvent, 10 * 1000); |
| if (waitResult != WAIT_OBJECT_0) { |
| LOG(ERROR) << "WaitForSingleObject failed: " << waitResult; |
| return false; |
| } |
| device_handle_ = hSwDevice; |
| return true; |
| } |
| |
| } // namespace display::test |