Try add sudovda driver support
This commit is contained in:
68
third-party/sudovda/sudovda-ioctl.h
vendored
Normal file
68
third-party/sudovda/sudovda-ioctl.h
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace SUDOVDA
|
||||
{
|
||||
#endif
|
||||
|
||||
#define IOCTL_ADD_VIRTUAL_DISPLAY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REMOVE_VIRTUAL_DISPLAY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SET_RENDER_ADAPTER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_GET_WATCHDOG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_DRIVER_PING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_GET_PROTOCOL_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x8FF, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
typedef struct _SUVDA_PROTOCAL_VERSION {
|
||||
uint8_t Major;
|
||||
uint8_t Minor;
|
||||
uint8_t Incremental;
|
||||
bool TestBuild;
|
||||
} SUVDA_PROTOCAL_VERSION, * PSUVDA_PROTOCAL_VERSION;
|
||||
|
||||
// Please update the version after ioctl changed
|
||||
static const SUVDA_PROTOCAL_VERSION VDAProtocolVersion = { 0, 2, 0, true };
|
||||
|
||||
static const char* SUVDA_HARDWARE_ID = "root\\sudomaker\\sudovda";
|
||||
|
||||
// DO NOT CHANGE
|
||||
// {4d36e968-e325-11ce-bfc1-08002be10318}
|
||||
static const GUID SUVDA_CLASS_GUID = { 0x4d36e968, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
|
||||
// {e5bcc234-1e0c-418a-a0d4-ef8b7501414d}
|
||||
static const GUID SUVDA_INTERFACE_GUID = { 0xe5bcc234, 0x1e0c, 0x418a, { 0xa0, 0xd4, 0xef, 0x8b, 0x75, 0x01, 0x41, 0x4d } };
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_ADD_PARAMS {
|
||||
UINT Width;
|
||||
UINT Height;
|
||||
UINT RefreshRate;
|
||||
GUID MonitorGuid;
|
||||
CHAR DeviceName[14];
|
||||
CHAR SerialNumber[14];
|
||||
} VIRTUAL_DISPLAY_ADD_PARAMS, * PVIRTUAL_DISPLAY_ADD_PARAMS;
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_REMOVE_PARAMS {
|
||||
GUID MonitorGuid;
|
||||
} VIRTUAL_DISPLAY_REMOVE_PARAMS, * PVIRTUAL_DISPLAY_REMOVE_PARAMS;
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_ADD_OUT {
|
||||
LUID AdapterLuid;
|
||||
UINT TargetId;
|
||||
} VIRTUAL_DISPLAY_ADD_OUT, * PVIRTUAL_DISPLAY_ADD_OUT;
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_SET_RENDER_ADAPTER_PARAMS {
|
||||
LUID AdapterLuid;
|
||||
} VIRTUAL_DISPLAY_SET_RENDER_ADAPTER_PARAMS, * PVIRTUAL_DISPLAY_SET_RENDER_ADAPTER_PARAMS;
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_GET_WATCHDOG_OUT {
|
||||
UINT Timeout;
|
||||
UINT Countdown;
|
||||
} VIRTUAL_DISPLAY_GET_WATCHDOG_OUT, * PVIRTUAL_DISPLAY_GET_WATCHDOG_OUT;
|
||||
|
||||
typedef struct _VIRTUAL_DISPLAY_GET_PROTOCOL_VERSION_OUT {
|
||||
SUVDA_PROTOCAL_VERSION Version;
|
||||
} VIRTUAL_DISPLAY_GET_PROTOCOL_VERSION_OUT, * PVIRTUAL_DISPLAY_GET_PROTOCOL_VERSION_OUT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // namespace SUDOVDA
|
||||
#endif
|
||||
247
third-party/sudovda/sudovda.h
vendored
Normal file
247
third-party/sudovda/sudovda.h
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <setupapi.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sudovda-ioctl.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "cfgmgr32.lib")
|
||||
#pragma comment(lib, "setupapi.lib")
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace SUDOVDA
|
||||
{
|
||||
#endif
|
||||
|
||||
static const HANDLE OpenDevice(const GUID* interfaceGuid) {
|
||||
// Get the device information set for the specified interface GUID
|
||||
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(interfaceGuid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
||||
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
||||
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
for (DWORD i = 0; SetupDiEnumDeviceInterfaces(deviceInfoSet, nullptr, interfaceGuid, i, &deviceInterfaceData); ++i)
|
||||
{
|
||||
DWORD detailSize = 0;
|
||||
SetupDiGetDeviceInterfaceDetailA(deviceInfoSet, &deviceInterfaceData, NULL, 0, &detailSize, NULL);
|
||||
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)calloc(1, detailSize);
|
||||
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
|
||||
|
||||
if (SetupDiGetDeviceInterfaceDetailA(deviceInfoSet, &deviceInterfaceData, detail, detailSize, &detailSize, NULL))
|
||||
{
|
||||
handle = CreateFileA(detail->DevicePath,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
|
||||
if (handle != NULL && handle != INVALID_HANDLE_VALUE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(detail);
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static const bool AddVirtualDisplay(HANDLE hDevice, UINT Width, UINT Height, UINT RefreshRate, const GUID& MonitorGuid, const CHAR* DeviceName, const CHAR* SerialNumber, VIRTUAL_DISPLAY_ADD_OUT& output) {
|
||||
VIRTUAL_DISPLAY_ADD_PARAMS params{Width, Height, RefreshRate, MonitorGuid, {}, {}};
|
||||
strncpy(params.DeviceName, DeviceName, 13);
|
||||
strncpy(params.SerialNumber, SerialNumber, 13);
|
||||
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_ADD_VIRTUAL_DISPLAY,
|
||||
(LPVOID)¶ms,
|
||||
sizeof(params),
|
||||
(LPVOID)&output,
|
||||
sizeof(output),
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "AddVirtualDisplay failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool RemoveVirtualDisplay(HANDLE hDevice, const GUID& MonitorGuid) {
|
||||
VIRTUAL_DISPLAY_REMOVE_PARAMS params{MonitorGuid};
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_REMOVE_VIRTUAL_DISPLAY,
|
||||
(LPVOID)¶ms,
|
||||
sizeof(params),
|
||||
nullptr,
|
||||
0,
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "RemoveVirtualDisplay failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool SetRenderAdapter(HANDLE hDevice, const LUID& AdapterLuid) {
|
||||
VIRTUAL_DISPLAY_SET_RENDER_ADAPTER_PARAMS params{AdapterLuid};
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_SET_RENDER_ADAPTER,
|
||||
(LPVOID)¶ms,
|
||||
sizeof(params),
|
||||
nullptr,
|
||||
0,
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "SetRenderAdapter failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool GetWatchdogTimeout(HANDLE hDevice, VIRTUAL_DISPLAY_GET_WATCHDOG_OUT& output) {
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_GET_WATCHDOG,
|
||||
nullptr,
|
||||
0,
|
||||
(LPVOID)&output,
|
||||
sizeof(output),
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "DeviceIoControl failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool GetProtocolVersion(HANDLE hDevice, VIRTUAL_DISPLAY_GET_PROTOCOL_VERSION_OUT& output) {
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_GET_PROTOCOL_VERSION,
|
||||
nullptr,
|
||||
0,
|
||||
(LPVOID)&output,
|
||||
sizeof(output),
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "DeviceIoControl failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool isProtocolCompatible(const SUVDA_PROTOCAL_VERSION& otherVersion) {
|
||||
// Changes to existing ioctl must be marked as major
|
||||
if (VDAProtocolVersion.Major != otherVersion.Major) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We shouldn't break compatibility with minor/incremental changes
|
||||
// e.g. add new ioctl in the driver
|
||||
// But if our minor version is newer than the driver version, break
|
||||
if (VDAProtocolVersion.Minor > otherVersion.Minor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
static const bool CheckProtocolCompatible(HANDLE hDevice) {
|
||||
VIRTUAL_DISPLAY_GET_PROTOCOL_VERSION_OUT protocolVersion;
|
||||
if (GetProtocolVersion(hDevice, protocolVersion)) {
|
||||
return isProtocolCompatible(protocolVersion.Version);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const bool PingDriver(HANDLE hDevice) {
|
||||
DWORD bytesReturned;
|
||||
BOOL success = DeviceIoControl(
|
||||
hDevice,
|
||||
IOCTL_DRIVER_PING,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
&bytesReturned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
std::cerr << "DeviceIoControl failed: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static const bool GetAddedDisplayName(const VIRTUAL_DISPLAY_ADD_OUT& addedDisplay, wchar_t* deviceName) {
|
||||
// get all paths
|
||||
UINT pathCount;
|
||||
UINT modeCount;
|
||||
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount))
|
||||
return 0;
|
||||
|
||||
std::vector<DISPLAYCONFIG_PATH_INFO> paths(pathCount);
|
||||
std::vector<DISPLAYCONFIG_MODE_INFO> modes(modeCount);
|
||||
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr))
|
||||
return 0;
|
||||
|
||||
auto path = std::find_if(paths.begin(), paths.end(), [&addedDisplay](DISPLAYCONFIG_PATH_INFO _path) {
|
||||
return _path.targetInfo.id == addedDisplay.TargetId;
|
||||
});
|
||||
|
||||
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {};
|
||||
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
||||
sourceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
|
||||
sourceName.header.adapterId = addedDisplay.AdapterLuid;
|
||||
sourceName.header.id = path->sourceInfo.id;
|
||||
if (DisplayConfigGetDeviceInfo((DISPLAYCONFIG_DEVICE_INFO_HEADER*)&sourceName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wcscpy_s(deviceName, CCHDEVICENAME, sourceName.viewGdiDeviceName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // namespace SUDOVDA
|
||||
#endif
|
||||
Reference in New Issue
Block a user