chromium/third_party/win_virtual_display/controller/display_driver_controller.cc

// 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