From: Sandy Stutsman <sstutsma@xxxxxxxxxx> --- Spice.props | 38 ++ vdagent.sln | 94 ++-- vdagent/CCD.h | 259 +++++++++++ vdagent/D3Dkmt.h | 134 ++++++ vdagent/desktop_layout.cpp | 152 ++----- vdagent/desktop_layout.h | 9 +- vdagent/display_configuration.cpp | 889 ++++++++++++++++++++++++++++++++++++++ vdagent/display_configuration.h | 192 ++++++++ vdagent/vdagent.vcxproj | 380 ++++++++++++++++ vdservice/vdservice.vcxproj | 197 +++++++++ 10 files changed, 2185 insertions(+), 159 deletions(-) create mode 100644 Spice.props create mode 100644 vdagent/CCD.h create mode 100644 vdagent/D3Dkmt.h create mode 100644 vdagent/display_configuration.cpp create mode 100644 vdagent/display_configuration.h create mode 100644 vdagent/vdagent.vcxproj create mode 100644 vdservice/vdservice.vcxproj diff --git a/Spice.props b/Spice.props new file mode 100644 index 0000000..217bfc7 --- /dev/null +++ b/Spice.props @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup Label="UserMacros"> + <SPICE_PROTOCOL_DIR>D:\SANDBOX\Master\spice-protocol</SPICE_PROTOCOL_DIR> + <SPICE_LIBS>D:\Sandbox\WSpice\</SPICE_LIBS> + <SPICE_LIB_LIST>cximage.lib;jasper.lib;jbig.lib;jpeg.lib;libdcr.lib;mng.lib;png.lib;tiff.lib;zlib.lib</SPICE_LIB_LIST> + <SPICE_DEBUG_LIB_LIST>cximage.lib;jasper.lib;jbig.lib;jpeg.lib;libdcr.lib;mng.lib;png.lib;tiff.lib;zlib.lib</SPICE_DEBUG_LIB_LIST> + <SPICE_LIBS_DIR>$(SPICE_LIBS)\$(Platform)\Release</SPICE_LIBS_DIR> + <SPICE_DEBUG_LIBS_DIR>$(SPICE_LIBS)\$(Platform)\Debug</SPICE_DEBUG_LIBS_DIR> + </PropertyGroup> + <PropertyGroup /> + <ItemDefinitionGroup /> + <ItemGroup> + <BuildMacro Include="SPICE_PROTOCOL_DIR"> + <Value>$(SPICE_PROTOCOL_DIR)</Value> + <EnvironmentVariable>true</EnvironmentVariable> + </BuildMacro> + <BuildMacro Include="SPICE_LIBS"> + <Value>$(SPICE_LIBS)</Value> + <EnvironmentVariable>true</EnvironmentVariable> + </BuildMacro> + <BuildMacro Include="SPICE_LIB_LIST"> + <Value>$(SPICE_LIB_LIST)</Value> + <EnvironmentVariable>true</EnvironmentVariable> + </BuildMacro> + <BuildMacro Include="SPICE_DEBUG_LIB_LIST"> + <Value>$(SPICE_DEBUG_LIB_LIST)</Value> + <EnvironmentVariable>true</EnvironmentVariable> + </BuildMacro> + <BuildMacro Include="SPICE_LIBS_DIR"> + <Value>$(SPICE_LIBS_DIR)</Value> + </BuildMacro> + <BuildMacro Include="SPICE_DEBUG_LIBS_DIR"> + <Value>$(SPICE_DEBUG_LIBS_DIR)</Value> + </BuildMacro> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/vdagent.sln b/vdagent.sln index 2622f2e..1c29664 100644 --- a/vdagent.sln +++ b/vdagent.sln @@ -1,36 +1,58 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdagent", "vdagent\vdagent.vcproj", "{CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdservice", "vdservice\vdservice.vcproj", "{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|Win32.ActiveCfg = Debug|Win32 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|Win32.Build.0 = Debug|Win32 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|x64.ActiveCfg = Debug|x64 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|x64.Build.0 = Debug|x64 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|Win32.ActiveCfg = Release|Win32 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|Win32.Build.0 = Release|Win32 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|x64.ActiveCfg = Release|x64 - {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|x64.Build.0 = Release|x64 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|Win32.ActiveCfg = Debug|Win32 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|Win32.Build.0 = Debug|Win32 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|x64.ActiveCfg = Debug|x64 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|x64.Build.0 = Debug|x64 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|Win32.ActiveCfg = Release|Win32 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|Win32.Build.0 = Release|Win32 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.ActiveCfg = Release|x64 - {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdagent", "vdagent\vdagent.vcxproj", "{CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdservice", "vdservice\vdservice.vcxproj", "{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Win10 Debug|Win32 = Win10 Debug|Win32 + Win10 Debug|x64 = Win10 Debug|x64 + Win10 Release|Win32 = Win10 Release|Win32 + Win10 Release|x64 = Win10 Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|Win32.ActiveCfg = Debug|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|Win32.Build.0 = Debug|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|x64.ActiveCfg = Debug|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Debug|x64.Build.0 = Debug|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|Win32.ActiveCfg = Release|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|Win32.Build.0 = Release|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|x64.ActiveCfg = Release|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Release|x64.Build.0 = Release|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Debug|x64.Build.0 = Win10 Debug|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Release|Win32.Build.0 = Win10 Release|Win32 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Release|x64.ActiveCfg = Win10 Release|x64 + {CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}.Win10 Release|x64.Build.0 = Win10 Release|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|Win32.Build.0 = Debug|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|x64.ActiveCfg = Debug|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Debug|x64.Build.0 = Debug|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|Win32.ActiveCfg = Release|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|Win32.Build.0 = Release|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.ActiveCfg = Release|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.Build.0 = Release|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Debug|Win32.ActiveCfg = Debug|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Debug|Win32.Build.0 = Debug|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Debug|x64.ActiveCfg = Debug|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Debug|x64.Build.0 = Debug|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Release|Win32.ActiveCfg = Release|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Release|Win32.Build.0 = Release|Win32 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Release|x64.ActiveCfg = Release|x64 + {ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Win10 Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/vdagent/CCD.h b/vdagent/CCD.h new file mode 100644 index 0000000..a457fc1 --- /dev/null +++ b/vdagent/CCD.h @@ -0,0 +1,259 @@ +/* +Copyright (C) 2015 Red Hat, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +//This file provides defines and structures required by Windows CCD API and +//not currently supplied by the MINGW32 header files. +#pragma once + +// +// Definitions used by QueryDisplayConfig. +// + +#if (_WIN32_WINNT < 0X0601) +#define QDC_ALL_PATHS 0x00000001 +#define QDC_ONLY_ACTIVE_PATHS 0x00000002 +#define QDC_DATABASE_CURRENT 0x00000004 +#define QDC_VIRTUAL_MODE_AWARE 0x00000010 + +// +// Definitions used by SetDisplayConfig. +// + +#define SDC_TOPOLOGY_INTERNAL 0x00000001 +#define SDC_TOPOLOGY_CLONE 0x00000002 +#define SDC_TOPOLOGY_EXTEND 0x00000004 +#define SDC_TOPOLOGY_EXTERNAL 0x00000008 +#define SDC_TOPOLOGY_SUPPLIED 0x00000010 +#define SDC_USE_DATABASE_CURRENT (SDC_TOPOLOGY_INTERNAL | SDC_TOPOLOGY_CLONE | SDC_TOPOLOGY_EXTEND | SDC_TOPOLOGY_EXTERNAL) + +#define SDC_USE_SUPPLIED_DISPLAY_CONFIG 0x00000020 +#define SDC_VALIDATE 0x00000040 +#define SDC_APPLY 0x00000080 +#define SDC_NO_OPTIMIZATION 0x00000100 +#define SDC_SAVE_TO_DATABASE 0x00000200 +#define SDC_ALLOW_CHANGES 0x00000400 +#define SDC_PATH_PERSIST_IF_REQUIRED 0x00000800 +#define SDC_FORCE_MODE_ENUMERATION 0x00001000 +#define SDC_ALLOW_PATH_ORDER_CHANGES 0x00002000 +#define SDC_VIRTUAL_MODE_AWARE 0x00008000 + +#define DISPLAYCONFIG_PATH_ACTIVE 0x00000001 +#define DISPLAYCONFIG_PATH_MODE_IDX_INVALID 0xffffffff + +typedef enum { + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, + DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, + DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, + DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7, + DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8, + DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_DEVICE_INFO_TYPE; + + +typedef enum { + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY; + + +typedef enum { + DISPLAYCONFIG_ROTATION_IDENTITY = 1, + DISPLAYCONFIG_ROTATION_ROTATE90 = 2, + DISPLAYCONFIG_ROTATION_ROTATE180 = 3, + DISPLAYCONFIG_ROTATION_ROTATE270 = 4, + DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_ROTATION; + +typedef enum { + DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, + DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, + DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_SCANLINE_ORDERING; + + +typedef enum { + DISPLAYCONFIG_SCALING_IDENTITY = 1, + DISPLAYCONFIG_SCALING_CENTERED = 2, + DISPLAYCONFIG_SCALING_STRETCHED = 3, + DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, + DISPLAYCONFIG_SCALING_CUSTOM = 5, + DISPLAYCONFIG_SCALING_PREFERRED = 128, + DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_SCALING; + + +typedef enum { + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, + DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, + DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3, + DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_MODE_INFO_TYPE; + + +typedef enum { + DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, + DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, + DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, + DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, + DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, + DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff +} DISPLAYCONFIG_PIXELFORMAT; + +typedef enum { + DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001, + DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002, + DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004, + DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008, + DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFFF +} DISPLAYCONFIG_TOPOLOGY_ID; + + +typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER { + DISPLAYCONFIG_DEVICE_INFO_TYPE type; + UINT32 size; + LUID adapterId; + UINT32 id; +} DISPLAYCONFIG_DEVICE_INFO_HEADER; + +typedef struct DISPLAYCONFIG_SOURCE_DEVICE_NAME { + DISPLAYCONFIG_DEVICE_INFO_HEADER header; + WCHAR viewGdiDeviceName[CCHDEVICENAME]; +} DISPLAYCONFIG_SOURCE_DEVICE_NAME; + +typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO { + POINTL PathSourceSize; + RECTL DesktopImageRegion; + RECTL DesktopImageClip; +} DISPLAYCONFIG_DESKTOP_IMAGE_INFO; + +typedef struct DISPLAYCONFIG_RATIONAL { + UINT32 Numerator; + UINT32 Denominator; +} DISPLAYCONFIG_RATIONAL; + +typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO { + LUID adapterId; + UINT32 id; + union { + UINT32 modeInfoIdx; + struct { + UINT32 cloneGroupId : 16; + UINT32 sourceModeInfoIdx : 16; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + + UINT32 statusFlags; +} DISPLAYCONFIG_PATH_SOURCE_INFO; + + +typedef struct DISPLAYCONFIG_PATH_TARGET_INFO { + LUID adapterId; + UINT32 id; + union { + UINT32 modeInfoIdx; + struct { + UINT32 desktopModeInfoIdx : 16; + UINT32 targetModeInfoIdx : 16; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + DISPLAYCONFIG_ROTATION rotation; + DISPLAYCONFIG_SCALING scaling; + DISPLAYCONFIG_RATIONAL refreshRate; + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + BOOL targetAvailable; + UINT32 statusFlags; +} DISPLAYCONFIG_PATH_TARGET_INFO; + +typedef struct DISPLAYCONFIG_PATH_INFO { + DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo; + DISPLAYCONFIG_PATH_TARGET_INFO targetInfo; + UINT32 flags; +} DISPLAYCONFIG_PATH_INFO; + +typedef struct DISPLAYCONFIG_2DREGION { + UINT32 cx; + UINT32 cy; +} DISPLAYCONFIG_2DREGION; + +typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO { + UINT64 pixelRate; + DISPLAYCONFIG_RATIONAL hSyncFreq; + DISPLAYCONFIG_RATIONAL vSyncFreq; + DISPLAYCONFIG_2DREGION activeSize; + DISPLAYCONFIG_2DREGION totalSize; + + union { + struct { + UINT32 videoStandard : 16; + + UINT32 vSyncFreqDivider : 6; + + UINT32 reserved : 10; + } AdditionalSignalInfo; + + UINT32 videoStandard; + } DUMMYUNIONNAME; + + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; +} DISPLAYCONFIG_VIDEO_SIGNAL_INFO; + +typedef struct DISPLAYCONFIG_TARGET_MODE { + DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo; +} DISPLAYCONFIG_TARGET_MODE; + +typedef struct DISPLAYCONFIG_SOURCE_MODE { + UINT32 width; + UINT32 height; + DISPLAYCONFIG_PIXELFORMAT pixelFormat; + POINTL position; +} DISPLAYCONFIG_SOURCE_MODE; + +typedef struct DISPLAYCONFIG_MODE_INFO { + DISPLAYCONFIG_MODE_INFO_TYPE infoType; + UINT32 id; + LUID adapterId; + union { + DISPLAYCONFIG_TARGET_MODE targetMode; + DISPLAYCONFIG_SOURCE_MODE sourceMode; + DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo; + } DUMMYUNIONNAME; +} DISPLAYCONFIG_MODE_INFO; + +#endif \ No newline at end of file diff --git a/vdagent/D3Dkmt.h b/vdagent/D3Dkmt.h new file mode 100644 index 0000000..81530fb --- /dev/null +++ b/vdagent/D3Dkmt.h @@ -0,0 +1,134 @@ + +/* +Copyright (C) 2015 Red Hat, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +//File provides definitions and structures for the D3D KMT interface calls +//make by WDDM vd agent interface + +#pragma once +#include <winnt.h> +typedef UINT D3DKMT_HANDLE; +typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID; + +typedef struct _D3DKMT_OPENADAPTERFROMHDC { + HDC hDc; + D3DKMT_HANDLE hAdapter; + LUID AdapterLuid; + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId; +} D3DKMT_OPENADAPTERFROMHDC; + +typedef struct _D3DKMT_CLOSEADAPTER { + D3DKMT_HANDLE hAdapter; +} D3DKMT_CLOSEADAPTER; + +typedef enum _D3DKMT_ESCAPETYPE { + D3DKMT_ESCAPE_DRIVERPRIVATE = 0, + D3DKMT_ESCAPE_VIDMM = 1, + D3DKMT_ESCAPE_TDRDBGCTRL = 2, + D3DKMT_ESCAPE_VIDSCH = 3, + D3DKMT_ESCAPE_DEVICE = 4, + D3DKMT_ESCAPE_DMM = 5, + D3DKMT_ESCAPE_DEBUG_SNAPSHOT = 6, + D3DKMT_ESCAPE_SETDRIVERUPDATESTATUS = 7, + D3DKMT_ESCAPE_DRT_TEST = 8, +#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN8) + D3DKMT_ESCAPE_DIAGNOSTICS = 9, + D3DKMT_ESCAPE_OUTPUTDUPL_SNAPSHOT = 10, + D3DKMT_ESCAPE_OUTPUTDUPL_DIAGNOSTICS = 11, + D3DKMT_ESCAPE_BDD_PNP = 12, + D3DKMT_ESCAPE_BDD_FALLBACK = 13, + D3DKMT_ESCAPE_ACTIVATE_SPECIFIC_DIAG = 14, + D3DKMT_ESCAPE_MODES_PRUNED_OUT = 15, + D3DKMT_ESCAPE_WHQL_INFO = 16, + D3DKMT_ESCAPE_BRIGHTNESS = 17, + D3DKMT_ESCAPE_EDID_CACHE = 18, + D3DKMT_ESCAPE_GENERIC_ADAPTER_DIAG_INFO = 19, +#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM1_3) + D3DKMT_ESCAPE_MIRACAST_DISPLAY_REQUEST = 20, + D3DKMT_ESCAPE_HISTORY_BUFFER_STATUS = 21, + D3DKMT_ESCAPE_MIRACAST_ADAPTER_DIAG_INFO = 23, +#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_0) + D3DKMT_ESCAPE_FORCE_BDDFALLBACK_HEADLESS = 24, + D3DKMT_ESCAPE_REQUEST_MACHINE_CRASH = 25, +#endif +#endif + + D3DKMT_ESCAPE_WIN32K_START = 1024, + D3DKMT_ESCAPE_WIN32K_HIP_DEVICE_INFO = 1024, + D3DKMT_ESCAPE_WIN32K_QUERY_CD_ROTATION_BLOCK = 1025, +#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM1_3) + D3DKMT_ESCAPE_WIN32K_DPI_INFO = 1026, + D3DKMT_ESCAPE_WIN32K_PRESENTER_VIEW_INFO = 1027, + D3DKMT_ESCAPE_WIN32K_SYSTEM_DPI = 1028, +#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_0) + D3DKMT_ESCAPE_WIN32K_BDD_FALLBACK = 1029, + D3DKMT_ESCAPE_WIN32K_DDA_TEST_CTL = 1030, + D3DKMT_ESCAPE_WIN32K_USER_DETECTED_BLACK_SCREEN = 1031, +#endif // DXGKDDI_INTERFACE_VERSION_WDDM2_0 +#endif // DXGKDDI_INTERFACE_VERSION_WDDM1_3 +#endif // DXGKDDI_INTERFACE_VERSION_WIN8 +} D3DKMT_ESCAPETYPE; + + +typedef struct _D3DDDI_ESCAPEFLAGS { + union { + struct { + UINT HardwareAccess : 1; +#if ((DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM1_3) || \ + (D3D_UMD_INTERFACE_VERSION >= D3D_UMD_INTERFACE_VERSION_WDDM1_3)) + UINT DeviceStatusQuery : 1; + UINT ChangeFrameLatency : 1; + UINT Reserved : 29; +#else + UINT Reserved : 31; +#endif // WDDM1_3 + }; + UINT Value; + }; +} D3DDDI_ESCAPEFLAGS; + +typedef struct _D3DKMT_ESCAPE { + D3DKMT_HANDLE hAdapter; + D3DKMT_HANDLE hDevice; + D3DKMT_ESCAPETYPE Type; + D3DDDI_ESCAPEFLAGS Flags; + VOID* pPrivateDriverData; + UINT PrivateDriverDataSize; + D3DKMT_HANDLE hContext; +} D3DKMT_ESCAPE; + + +typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME { + PCWSTR pDeviceName; + D3DKMT_HANDLE hAdapter; + LUID AdapterLuid; +} D3DKMT_OPENADAPTERFROMDEVICENAME; + +typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID; + +typedef struct _D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME { + WCHAR DeviceName[32]; + D3DKMT_HANDLE hAdapter; + LUID AdapterLuid; + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId; +} D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME; + +typedef NTSTATUS(APIENTRY* PFND3DKMT_ESCAPE)(CONST D3DKMT_ESCAPE*); +typedef NTSTATUS(APIENTRY* PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*); +typedef NTSTATUS(APIENTRY* PFND3DKMT_OPENADAPTERFROMDEVICENAME)(D3DKMT_OPENADAPTERFROMDEVICENAME*); +typedef NTSTATUS(APIENTRY* PFND3DKMT_CLOSEADAPTER)(D3DKMT_CLOSEADAPTER*); +typedef NTSTATUS(APIENTRY* PFND3DKMT_OPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC*); \ No newline at end of file diff --git a/vdagent/desktop_layout.cpp b/vdagent/desktop_layout.cpp index a7666ca..7aff7e7 100644 --- a/vdagent/desktop_layout.cpp +++ b/vdagent/desktop_layout.cpp @@ -18,8 +18,8 @@ #include <spice/qxl_windows.h> #include <spice/qxl_dev.h> #include "desktop_layout.h" +#include "display_configuration.h" #include "vdlog.h" - #ifdef __MINGW32__ using std::min; using std::max; @@ -35,15 +35,19 @@ void DisplayMode::set_res(DWORD width, DWORD height, DWORD depth) DesktopLayout::DesktopLayout() : _total_width (0) , _total_height (0) - , _send_monitors_position(false) + , _display_config(NULL) { MUTEX_INIT(_mutex); + _display_config = DISPLAY_CONFIG::create_config(); get_displays(); } DesktopLayout::~DesktopLayout() { clean_displays(); + if (_display_config){ + delete _display_config; + } } void DesktopLayout::get_displays() @@ -59,6 +63,7 @@ void DesktopLayout::get_displays() unlock(); return; } + _display_config->update_config_path(); clean_displays(); ZeroMemory(&dev_info, sizeof(dev_info)); dev_info.cb = sizeof(dev_info); @@ -82,12 +87,13 @@ void DesktopLayout::get_displays() _displays[i] = NULL; } } - attached = !!(dev_info.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP); + attached = _display_config->is_attached(&dev_info); + EnumDisplaySettings(dev_info.DeviceName, ENUM_CURRENT_SETTINGS, &mode); _displays[display_id] = new DisplayMode(mode.dmPosition.x, mode.dmPosition.y, mode.dmPelsWidth, mode.dmPelsHeight, mode.dmBitsPerPel, attached); - update_monitor_config(dev_info.DeviceName, _displays[display_id]); + _display_config->update_monitor_config(dev_info.DeviceName, _displays[display_id], &mode); } normalize_displays_pos(); unlock(); @@ -121,6 +127,7 @@ void DesktopLayout::set_displays() unlock(); return; } + _display_config->update_config_path(); ZeroMemory(&dev_info, sizeof(dev_info)); dev_info.cb = sizeof(dev_info); ZeroMemory(&dev_mode, sizeof(dev_mode)); @@ -146,28 +153,32 @@ void DesktopLayout::set_displays() break; } DisplayMode * mode(_displays.at(display_id)); - if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode, normal_x, normal_y, true)) { + if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode)) { vd_printf("No suitable mode found for display %S", dev_info.DeviceName); break; } vd_printf("Set display mode %lux%lu", dev_mode.dmPelsWidth, dev_mode.dmPelsHeight); - LONG ret = ChangeDisplaySettingsEx(dev_info.DeviceName, &dev_mode, NULL, - CDS_UPDATEREGISTRY | CDS_NORESET, NULL); - if (ret == DISP_CHANGE_SUCCESSFUL) { + if(_display_config->update_dev_mode_position(dev_info.DeviceName, &dev_mode, + mode->_pos_x - normal_x, + mode->_pos_y - normal_y)) { dev_sets++; - update_monitor_config(dev_info.DeviceName, mode); + _display_config->update_monitor_config(dev_info.DeviceName, mode, &dev_mode); } if (!is_qxl) { display_id++; } } if (dev_sets) { - ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL); + _display_config->update_display_settings(); normalize_displays_pos(); } unlock(); } +void DesktopLayout::set_position_configurable(bool flag) { + _display_config->set_monitors_config(flag); +} + // Normalize all display positions to non-negative coordinates and update total width and height of // the virtual desktop. Caller is responsible to lock() & unlock(). void DesktopLayout::normalize_displays_pos() @@ -265,125 +276,30 @@ bool DesktopLayout::get_qxl_device_id(WCHAR* device_key, DWORD* device_id) return key_found; } -bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode* mode, - LONG normal_x, LONG normal_y, bool set_pos) +bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode* mode) { - DWORD closest_diff = -1; - DWORD best = -1; - QXLEscapeSetCustomDisplay custom; - HDC hdc = NULL; - LONG ret; - ZeroMemory(dev_mode, sizeof(DEVMODE)); dev_mode->dmSize = sizeof(DEVMODE); - if (!mode || !mode->_attached) { - //Detach monitor - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; + + //Update monitor state + MONITOR_STATE monitor_state = (!mode || !mode->_attached)? MONITOR_DETACHED : MONITOR_ATTACHED; + _display_config->set_monitor_state(dev_name, dev_mode, monitor_state); + if (monitor_state == MONITOR_DETACHED) { return true; } - hdc = CreateDC(dev_name, NULL, NULL, NULL); - if (!hdc) { - // for some reason, windows want those 3 flags to enable monitor - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; - dev_mode->dmPelsWidth = mode->_width; - dev_mode->dmPelsHeight = mode->_height; - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL, CDS_UPDATEREGISTRY, NULL); - if (ret == DISP_CHANGE_BADMODE) { - // custom resolution might not be set yet, use known resolution - // FIXME: this causes client temporary resize... a - // solution would involve passing custom resolution before - // driver initialization, perhaps through registry - dev_mode->dmPelsWidth = 640; - dev_mode->dmPelsHeight = 480; - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL, CDS_UPDATEREGISTRY, NULL); - } - - vd_printf("attach %ld", ret); - hdc = CreateDC(dev_name, NULL, NULL, NULL); - } - - if (!hdc) { - vd_printf("failed to create DC"); + // Update custom resolution + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; + dev_mode->dmPelsWidth = mode->_width; + dev_mode->dmPelsHeight = mode->_height; + dev_mode->dmBitsPerPel = mode->_depth; + if (!_display_config->custom_display_escape(dev_name, dev_mode)) return false; - } else { - // Update custom resolution - custom.xres = mode->_width; - custom.yres = mode->_height; - custom.bpp = mode->_depth; - - int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY, - sizeof(QXLEscapeSetCustomDisplay), (LPCSTR)&custom, 0, NULL); - if (err <= 0) { - vd_printf("can't set custom display, perhaps an old driver"); - } - DeleteDC(hdc); - } - - // force refresh mode table - DEVMODE tempDevMode; - ZeroMemory(&tempDevMode, sizeof (tempDevMode)); - tempDevMode.dmSize = sizeof(DEVMODE); - EnumDisplaySettings(dev_name, 0xffffff, &tempDevMode); - - //Find the closest size which will fit within the monitor - for (DWORD i = 0; EnumDisplaySettings(dev_name, i, dev_mode); i++) { - if (dev_mode->dmPelsWidth > mode->_width || - dev_mode->dmPelsHeight > mode->_height || - dev_mode->dmBitsPerPel != mode->_depth) { - continue; - } - DWORD wdiff = mode->_width - dev_mode->dmPelsWidth; - DWORD hdiff = mode->_height - dev_mode->dmPelsHeight; - DWORD diff = wdiff * wdiff + hdiff * hdiff; - if (diff < closest_diff) { - closest_diff = diff; - best = i; - } - } - if (best == (DWORD)-1 || !EnumDisplaySettings(dev_name, best, dev_mode)) { - return false; - } - dev_mode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - if (set_pos) { - //Convert the position so that the primary is always at (0,0) - dev_mode->dmPosition.x = mode->_pos_x - normal_x; - dev_mode->dmPosition.y = mode->_pos_y - normal_y; - dev_mode->dmFields |= DM_POSITION; - } // update current DisplayMode (so mouse scaling works properly) mode->_width = dev_mode->dmPelsWidth; mode->_height = dev_mode->dmPelsHeight; - return true; -} - -bool DesktopLayout::update_monitor_config(LPCTSTR dev_name, DisplayMode* mode) -{ - QXLHead monitor_config; - if (!mode || !mode->get_attached()) - return false; - - //Don't configure monitors unless the client supports it - if(!_send_monitors_position) return FALSE; - - HDC hdc = CreateDC(dev_name, NULL, NULL, NULL); - - memset(&monitor_config, 0, sizeof(monitor_config)); - monitor_config.x = mode->_pos_x; - monitor_config.y = mode->_pos_y; - monitor_config.width = mode->_width; - monitor_config.height = mode->_height; - - int err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG, - sizeof(QXLHead), (LPCSTR) &monitor_config, 0, NULL); - - if (err < 0){ - vd_printf("can't update monitor config, may have an older driver"); - } - - DeleteDC(hdc); - return (err >= 0); } + diff --git a/vdagent/desktop_layout.h b/vdagent/desktop_layout.h index ece3946..fd6af76 100644 --- a/vdagent/desktop_layout.h +++ b/vdagent/desktop_layout.h @@ -60,6 +60,7 @@ private: }; typedef std::vector<DisplayMode*> Displays; +class DisplayConfig; class DesktopLayout { public: @@ -73,23 +74,21 @@ public: size_t get_display_count() { return _displays.size();} DWORD get_total_width() { return _total_width;} DWORD get_total_height() { return _total_height;} - void set_position_configurable(bool flag) { _send_monitors_position = flag; } + void set_position_configurable(bool flag); private: void clean_displays(); void normalize_displays_pos(); DisplayMode * get_primary_display(); - bool update_monitor_config(LPCTSTR dev_name, DisplayMode* mode); + bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode* mode); static bool consistent_displays(); static bool is_attached(LPCTSTR dev_name); static bool get_qxl_device_id(WCHAR* device_key, DWORD* device_id); - static bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode* mode, - LONG normal_x, LONG normal_y, bool set_pos); private: mutex_t _mutex; Displays _displays; DWORD _total_width; DWORD _total_height; - bool _send_monitors_position; + DisplayConfig* _display_config; }; #endif diff --git a/vdagent/display_configuration.cpp b/vdagent/display_configuration.cpp new file mode 100644 index 0000000..19641e9 --- /dev/null +++ b/vdagent/display_configuration.cpp @@ -0,0 +1,889 @@ +/* +Copyright (C) 2015 Red Hat, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "display_configuration.h" +#include <winternl.h> +//#include <ntstatus.h> + +typedef struct QXL_MONITOR_ESCAPE { + QXL_MONITOR_ESCAPE(DEVMODE* dev_mode) + { + ZeroMemory(&_head, sizeof(_head)); + _head.x = dev_mode->dmPosition.x; + _head.y = dev_mode->dmPosition.y; + _head.width = dev_mode->dmPelsWidth; + _head.height = dev_mode->dmPelsHeight; + + } + QXLHead _head; +}QXL_MONITOR_ESCAPE; + +typedef struct QxlCustomEscapeObj : public QXLEscapeSetCustomDisplay { + QxlCustomEscapeObj(uint32_t bitsPerPel, uint32_t width, uint32_t height) + { + xres = width; + yres = height; + bpp = bitsPerPel; + } + QxlCustomEscapeObj() {}; +}QxlCustomEscapeObj; + +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) +typedef struct WDDM_CUSTOM_DISPLAY_ESCAPE { + WDDM_CUSTOM_DISPLAY_ESCAPE(DEVMODE* dev_mode) + { + _ioctl = QXL_ESCAPE_SET_CUSTOM_DISPLAY; + _custom.bpp = dev_mode->dmBitsPerPel; + _custom.xres = dev_mode->dmPelsWidth; + _custom.yres = dev_mode->dmPelsHeight; + } + int _ioctl; + QXLEscapeSetCustomDisplay _custom; +} WDDM_CUSTOM_DISPLAY_ESCAPE; +typedef struct WDDM_MONITOR_CONFIG_ESCAPE { + WDDM_MONITOR_CONFIG_ESCAPE(DisplayMode* mode) + { + _ioctl = QXL_ESCAPE_MONITOR_CONFIG; + _head.id = _head.surface_id = 0; + _head.x = mode->get_pos_x(); + _head.y = mode->get_pos_y(); + _head.width = mode->get_width(); + _head.height = mode->get_height(); + } + int _ioctl; + QXLHead _head; +} WDDM_MONITOR_CONFIG_ESCAPE; +#endif +DisplayConfig* DisplayConfig::create_config() +{ + DisplayConfig* new_interface; +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) + //Try to open a WDDM adapter. + new_interface = new WDDMInterface(); + if(new_interface->type() == WDDM) { + return new_interface; + } + //If that failed so clean up and assume we have an XPDM driver + delete new_interface; +#endif + + new_interface = new XPDMInterface(); + return new_interface; +} + +DisplayConfig::DisplayConfig() + : _driver_type(INVALID_DRIVER) + , _send_monitors_config(false) +{} + +bool XPDMInterface::is_attached(DISPLAY_DEVICE* dev_info) +{ + return !!(dev_info->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP); +} + +bool XPDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state) +{ + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; + if(state == MONITOR_ATTACHED) { + return true; + } + + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL, CDS_UPDATEREGISTRY, NULL); + return (status == DISP_CHANGE_SUCCESSFUL); +} + +LONG XPDMInterface::update_display_settings() +{ + return ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL); +} + +bool XPDMInterface::update_dev_mode_position(LPCTSTR device_name, + DEVMODE* dev_mode, LONG x, LONG y) +{ + //Convert the position so that the primary is always at (0,0) + dev_mode->dmPosition.x = x; + dev_mode->dmPosition.y = y; + dev_mode->dmFields |= DM_POSITION; + vd_printf("%s: setting %S at (%lu, %lu)", __FUNCTION__, device_name, dev_mode->dmPosition.x, + dev_mode->dmPosition.y); + + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL, + CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + return (status == DISP_CHANGE_SUCCESSFUL); +} + +bool XPDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode) +{ + LONG ret; + NTSTATUS Status (ERROR_SUCCESS); + HDC hdc = CreateDC(device_name, NULL, NULL, NULL); + + if (!hdc) { + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL, CDS_UPDATEREGISTRY, NULL); + if (ret == DISP_CHANGE_BADMODE) { + // custom resolution might not be set yet, use known resolution + // FIXME: this causes client temporary resize... a + // solution would involve passing custom resolution before + // driver initialization, perhaps through registry + dev_mode->dmPelsWidth = 640; + dev_mode->dmPelsHeight = 480; + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL, CDS_UPDATEREGISTRY, NULL); + } + + vd_printf("attach %ld", ret); + if (!(hdc = CreateDC(device_name, NULL, NULL, NULL))) { + vd_printf("%s: failed to create DC", __FUNCTION__); + return false; + } + } + + QxlCustomEscapeObj custom_escape(dev_mode->dmBitsPerPel, + dev_mode->dmPelsWidth, dev_mode->dmPelsHeight); + + int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY, + sizeof(QXLEscapeSetCustomDisplay), (LPCSTR) &custom_escape, 0, NULL); + if (err <= 0) { + vd_printf("%s: Can't set custom display, perhaps running with an older driver?", + __FUNCTION__); + } + + if(!find_best_mode(device_name, dev_mode)) { + Status = E_FAIL; + } + + DeleteDC(hdc); + return NT_SUCCESS(Status); +} + +bool XPDMInterface::update_monitor_config(LPCTSTR device_name, DisplayMode* mode, + DEVMODE* dev_mode) +{ + if(!mode || !mode->get_attached()) { + return false; + } + + QXL_MONITOR_ESCAPE monitor_config(dev_mode); + HDC hdc(CreateDC(device_name, NULL, NULL, NULL)); + int err(0); + + if (!hdc || !_send_monitors_config) { + return false; + } + + err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG, sizeof(QXLHead), + (LPCSTR) &monitor_config, 0, NULL); + if (err < 0) { + vd_printf("%s: %S can't update monitor config, may have old, old driver", + __FUNCTION__, device_name); + } + DeleteDC(hdc); + return (err >= 0); +} + +bool XPDMInterface::find_best_mode(LPCTSTR Device, DEVMODE* dev_mode) +{ + DWORD closest_diff = -1; + DWORD best = -1; + + // force refresh mode table + DEVMODE test_dev_mode; + ZeroMemory(&test_dev_mode, sizeof(test_dev_mode)); + test_dev_mode.dmSize = sizeof(DEVMODE); + EnumDisplaySettings(Device, 0xffffff, &test_dev_mode); + + //Find the closest size which will fit within the monitor + for(DWORD i = 0; EnumDisplaySettings(Device, i, &test_dev_mode); i++) { + if (dev_mode->dmPelsWidth > test_dev_mode.dmPelsWidth || + dev_mode->dmPelsHeight > test_dev_mode.dmPelsHeight || + dev_mode->dmBitsPerPel != test_dev_mode.dmBitsPerPel) { + continue; + } + DWORD wdiff = dev_mode->dmPelsWidth - test_dev_mode.dmPelsWidth; + DWORD hdiff = dev_mode->dmPelsHeight - test_dev_mode.dmPelsHeight; + DWORD diff = wdiff * wdiff + hdiff * hdiff; + if (diff < closest_diff) { + closest_diff = diff; + best = i; + } + } + vd_printf("%s: closest_diff at %lu best %lu", __FUNCTION__, closest_diff, best); + if (best == (DWORD) -1 || !EnumDisplaySettings(Device, best, dev_mode)) { + return false; + } + + //Change to the best fit + LONG status = ChangeDisplaySettingsEx(Device, dev_mode, NULL, + CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + return NT_SUCCESS(status); +} +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) +WDDMInterface::WDDMInterface() + : _pfnOpen_adapter_hdc(NULL) + , _pfnClose_adapter(NULL) + , _pfnEscape(NULL) + , _pfnOpen_adapter_device_name(NULL) + , _pfnOpen_adapter_gdi_name(NULL) +{ + _driver_type = INVALID_DRIVER; + + //Did the CCD load? + if(_ccd.error() == ERROR_NOT_SUPPORTED){ + return; + } + + //Can we find the D3D calls we need? + if (!init_d3d_api()) { + return; + } + + //Initialize CCD path stuff + if (!_ccd.query_display_config()){ + return;; + } + if(!_ccd.set_display_config()) { + return; + } + _driver_type = WDDM; +} + +WDDMInterface::~WDDMInterface() +{ + if (_driver_type != WDDM) { + vd_printf("%s called with invalid driver type of %d", __FUNCTION__, _driver_type); + return; + } +} + +bool WDDMInterface::is_attached(DISPLAY_DEVICE* dev_info) +{ + return _ccd.is_attached(dev_info->DeviceName); +} + +bool WDDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state) +{ + return _ccd.set_path_state(device_name, state); +} + +bool WDDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode) +{ + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name, false); + if (!mode) { + return false; + } + + //Don't bother if we are already set to the new resolution + if (mode->sourceMode.width == dev_mode->dmPelsWidth && + mode->sourceMode.height == dev_mode->dmPelsHeight) { + return true; + } + + vd_printf("%s: updating %S resolution\n", __FUNCTION__, device_name); + + WDDM_CUSTOM_DISPLAY_ESCAPE wddm_escape (dev_mode); + if(escape(device_name, &wddm_escape, sizeof(wddm_escape))) { + return _ccd.update_mode_size(device_name, dev_mode); + } + + vd_printf("%s: (%dx%d)", __FUNCTION__, mode->sourceMode.width, mode->sourceMode.height); + return false; +} + +bool WDDMInterface::update_monitor_config(LPCTSTR device_name, DisplayMode* display_mode, + DEVMODE* dev_mode) +{ + if(!display_mode || !display_mode->get_attached()) { + return false; + } + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name, false); + if (!mode || !_send_monitors_config) + return false; + + WDDM_MONITOR_CONFIG_ESCAPE wddm_escape(display_mode); + if(escape(device_name, &wddm_escape, sizeof(wddm_escape))) { + //Update the path position + return _ccd.update_mode_position(device_name, dev_mode); + } + + vd_printf("%s: %S failed", __FUNCTION__, device_name); + return false; + +} + +LONG WDDMInterface::update_display_settings() +{ + //If we removed the primary monitor since the last call, we need to + //reorder the other monitors, making the leftmost one the primary + _ccd.verify_primary_position(); + + if (!_ccd.set_display_config()) { + if(_ccd._error != ERROR_INVALID_PARAMETER) { + vd_printf("%s: set_display_config failed", __FUNCTION__); + } + else { + vd_printf("%s: Invalid parameter!", __FUNCTION__); + _ccd.debug_print_config("After error"); + } + } + return _ccd.error(); +} + +void WDDMInterface::update_config_path() +{ + _ccd.query_display_config(); +} + +bool WDDMInterface::update_dev_mode_position(LPCTSTR device_name, DEVMODE* dev_mode, + LONG x, LONG y) +{ + //Convert the position so that the primary is always at (0,0) + dev_mode->dmPosition.x = x; + dev_mode->dmPosition.y = y; + _ccd.update_mode_position(device_name, dev_mode); + return true; +} + +bool WDDMInterface::init_d3d_api() +{ + HMODULE hModule = LoadLibrary(L"gdi32.dll"); + + //Look for the gdi32 functions we need to perform driver escapes + if(!hModule) { + vd_printf("%s something wildly wrong as we can't open gdi32.dll", __FUNCTION__); + _driver_type = INVALID_DRIVER; + return false; + } + + do { + _pfnClose_adapter = (PFND3DKMT_CLOSEADAPTER) + GetProcAddress(hModule, "D3DKMTCloseAdapter"); + if (!_pfnClose_adapter) { + break; + } + + _pfnEscape = (PFND3DKMT_ESCAPE) GetProcAddress(hModule, "D3DKMTEscape"); + if (!_pfnEscape) { + break; + } + + _pfnOpen_adapter_hdc = (PFND3DKMT_OPENADAPTERFROMHDC) + GetProcAddress(hModule, "D3DKMTOpenAdapterFromHdc"); + if (!_pfnOpen_adapter_hdc) { + break; + } + + _pfnOpen_adapter_device_name = (PFND3DKMT_OPENADAPTERFROMDEVICENAME) + GetProcAddress(hModule, "D3DKMTOpenAdapterFromDeviceName"); + if (!_pfnOpen_adapter_device_name) { + break; + } + + _pfnOpen_adapter_gdi_name = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME) + GetProcAddress(hModule, "D3DKMTOpenAdapterFromGdiDisplayName"); + if (!_pfnOpen_adapter_gdi_name) { + break; + } + + } + while(0); + + FreeLibrary(hModule); + + //Did we get them ? + if (!_pfnClose_adapter || !_pfnOpen_adapter_hdc || !_pfnEscape) { + return false; + } + _driver_type = WDDM; + return true; +} + +D3DKMT_HANDLE WDDMInterface::adapter_handle(LPCTSTR device_name) +{ + D3DKMT_HANDLE hAdapter(0); + + //For some reason, unknown to me, this call will occasionally fail. + if ((hAdapter = handle_from_DC(device_name))) { + return hAdapter; + } + //So try other available methods. + if (_pfnOpen_adapter_device_name && (hAdapter = handle_from_device_name(device_name))) { + return hAdapter; + } + //One last chance to open this guy + if(_pfnOpen_adapter_gdi_name) { + hAdapter = handle_from_GDI_name(device_name); + } + + if(!hAdapter) { + vd_printf("%s: failed to open adapter %S", __FUNCTION__, device_name); + } + + return hAdapter; +} + +D3DKMT_HANDLE WDDMInterface::handle_from_DC(LPCTSTR adapter_name) +{ + NTSTATUS status; + D3DKMT_OPENADAPTERFROMHDC open_data; + HDC hDc(CreateDC(adapter_name, NULL, NULL, NULL)); + + if (!hDc) { + vd_printf("%s: %S CreateDC failed with %lu", __FUNCTION__, adapter_name, GetLastError()); + return 0; + } + + ZeroMemory(&open_data, sizeof(D3DKMT_OPENADAPTERFROMHDC)); + open_data.hDc = hDc; + + if (!NT_SUCCESS(status = _pfnOpen_adapter_hdc(&open_data))) { + vd_printf("%s: %S open adapter from hdc failed with %lu", __FUNCTION__, adapter_name, + status); + open_data.hAdapter = 0; + } + + DeleteDC(hDc); + return open_data.hAdapter; +} + +D3DKMT_HANDLE WDDMInterface::handle_from_device_name(LPCTSTR adapter_name) +{ + D3DKMT_OPENADAPTERFROMDEVICENAME display_name_data; + NTSTATUS status; + + ZeroMemory(&display_name_data, sizeof(display_name_data)); + display_name_data.pDeviceName = adapter_name; + + if (NT_SUCCESS(status = _pfnOpen_adapter_device_name(&display_name_data))) { + return display_name_data.hAdapter; + } + + vd_printf("%s %S failed with 0x%lx", __FUNCTION__, adapter_name, status); + return 0; +} + +D3DKMT_HANDLE WDDMInterface::handle_from_GDI_name(LPCTSTR adapter_name) +{ + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME gdi_display_name; + NTSTATUS status; + + ZeroMemory(&gdi_display_name, sizeof(gdi_display_name)); + memcpy((void *) gdi_display_name.DeviceName, adapter_name, sizeof(TCHAR)* CCHDEVICENAME); + + if (NT_SUCCESS(status = _pfnOpen_adapter_gdi_name(&gdi_display_name))) { + return gdi_display_name.hAdapter; + } + + vd_printf("%s: %S aurrrgghh nothing works..error is 0x%lx", __FUNCTION__, adapter_name, + status); + return 0; +} + +void WDDMInterface::close_adapter(D3DKMT_HANDLE handle) +{ + D3DKMT_CLOSEADAPTER closeData; + if (handle ){ + closeData.hAdapter = handle; + _pfnClose_adapter(&closeData); + } +} + +bool WDDMInterface::escape(LPCTSTR device_name, void* data, UINT size_data) +{ + D3DKMT_ESCAPE escapeData; + NTSTATUS status; + D3DKMT_HANDLE hAdapter(0); + + if (!(hAdapter = adapter_handle(device_name))) + return false; + + escapeData.hAdapter = hAdapter; + escapeData.hDevice = 0; + escapeData.hContext = 0; + escapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE; + escapeData.Flags.Value = 0; + escapeData.pPrivateDriverData = data; + escapeData.PrivateDriverDataSize = size_data; + + status = _pfnEscape(&escapeData); + + if (!NT_SUCCESS(status)) { + vd_printf("%s: this should never happen. Status is 0x%lx", __FUNCTION__, status); + _driver_type = INVALID_DRIVER; + } + + //Close the handle to this device + close_adapter(hAdapter); + return NT_SUCCESS(status); +} + +CCD::CCD() + :_NumPathElements(0) + ,_NumModeElements(0) + ,_pPathInfo(NULL) + ,_pModeInfo(NULL) + ,_pfnGetDeviceInfo(NULL) + ,_pfnGetDisplayConfigBufferSizes(NULL) + ,_pfnQueryDisplayConfig(NULL) + ,_pfnSetDisplayConfig(NULL) + ,_error(0) + ,_primary_detached(false) + ,_path_state(PATH_UPDATED) +{ + if(load_api()) { + get_config_buffers(); + } +} + +CCD::~CCD() +{ + free_config_buffers(); +} + +bool CCD::query_display_config() +{ + LONG query_error(ERROR_SUCCESS); + + //Until we get it or error != ERROR_INSUFFICIENT_BUFFER + do { + query_error = _pfnQueryDisplayConfig(QDC_ALL_PATHS, &_NumPathElements, _pPathInfo, + &_NumModeElements, _pModeInfo, NULL); + + // if ERROR_INSUFFICIENT_BUFFER need to retry QueryDisplayConfig + // to get a new set of config buffers + //(see https://msdn.microsoft.com/en-us/library/windows/hardware/ff569215(v=vs.85).aspx ) + if (query_error) { + if (query_error == ERROR_INSUFFICIENT_BUFFER) { + free_config_buffers(); + if (!get_config_buffers()) + return false; + } + else { + _error = query_error; + vd_printf("%s failed QueryDisplayConfig with 0x%lx", __FUNCTION__, _error); + return false; + } + } + } while(query_error); + _path_state = PATH_CURRENT; + return true; +} + +DISPLAYCONFIG_MODE_INFO* CCD::get_active_mode(LPCTSTR device_name, bool return_on_error) +{ + DISPLAYCONFIG_PATH_INFO* active_path; + + active_path = get_device_path(device_name, true); + + if (!active_path ) { + vd_printf("%s:%S failed", __FUNCTION__, device_name); + return NULL; + } + return &_pModeInfo[active_path->sourceInfo.modeInfoIdx]; +} + +bool CCD::set_display_config() { + + debug_print_config("Before SetDisplayConfig"); + + if (_path_state == PATH_CURRENT) { + vd_printf("%s: path states says nothing changed", __FUNCTION__); + return true; + } + + if(!(_error = _pfnSetDisplayConfig(_NumPathElements, _pPathInfo, + _NumModeElements, _pModeInfo, + SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_FORCE_MODE_ENUMERATION))) + { + return true; + } + + vd_printf("%s failed SetDisplayConfig with 0x%lx", __FUNCTION__, _error); + debug_print_config("After failed SetDisplayConfig"); + return false; +} + +DISPLAYCONFIG_PATH_INFO* CCD::get_device_path(LPCTSTR device_name, bool bActive) +{ + //Search for device's active path + for(UINT32 i = 0; i < _NumPathElements; i++) { + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i]; + + //if bActive, return only paths that are currently active + if(bActive && !is_active_path(path_info)) + continue; + if (!is_device_path(device_name, path_info)) + continue; + return path_info; + } + _error = ERROR_GEN_FAILURE; + return NULL; +} + +void CCD::debug_print_config(const char* prefix) +{ + TCHAR dev_name[CCHDEVICENAME]; + for (UINT32 i = 0; i < _NumPathElements; i++) { + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i]; + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE)) + continue; + get_device_name_config(path_info, dev_name); + + if (path_info->sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID) { + vd_printf("%s: %S [%s] This path is active but has invalid mode set.", __FUNCTION__, + dev_name, prefix); + continue; + } + DISPLAYCONFIG_MODE_INFO* mode = &_pModeInfo[path_info->sourceInfo.modeInfoIdx]; + vd_printf("%s: %S [%s] (%u,%u) (%ux%u).", __FUNCTION__, dev_name, prefix, + mode->sourceMode.position.x, mode->sourceMode.position.y, + mode->sourceMode.width, mode->sourceMode.height); + } +} + +bool CCD::load_api() +{ + HMODULE hModule = LoadLibrary(L"user32.dll"); + if(!hModule) { + return false; + } + + bool bFound_all(false); + do { + if(!(_pfnGetDeviceInfo = (PDISPLAYCONFIG_GETDEVICEINFO) + GetProcAddress(hModule, "DisplayConfigGetDeviceInfo"))) { + break; + } + + if(!(_pfnGetDisplayConfigBufferSizes = (PGETDISPLAYCONFIG_BUFFERSIZES) + GetProcAddress(hModule, "GetDisplayConfigBufferSizes"))) { + break; + } + + if(!(_pfnQueryDisplayConfig = (PQUERYDISPLAYCONFIG) + GetProcAddress(hModule, "QueryDisplayConfig"))) { + break; + } + + if(!(_pfnSetDisplayConfig = (PSETDISPLAYCONFIG) + GetProcAddress(hModule, "SetDisplayConfig"))) { + break; + } + bFound_all = true; + } + while(0); + + FreeLibrary(hModule); + return bFound_all; +} + +bool CCD::get_config_buffers() +{ + //Get Config Buffer Sizes + free_config_buffers(); + _error = _pfnGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &_NumPathElements, + &_NumModeElements); + if (_error) { + vd_printf("%s: GetDisplayConfigBufferSizes failed with 0x%lx", __FUNCTION__, _error); + return false; + } + + //Allocate arrays + _pPathInfo = ((DISPLAYCONFIG_PATH_INFO*) malloc(sizeof(DISPLAYCONFIG_PATH_INFO) * _NumPathElements)); + _pModeInfo = ((DISPLAYCONFIG_MODE_INFO*) malloc(sizeof(DISPLAYCONFIG_MODE_INFO) * _NumModeElements)); + + if (!_pPathInfo || !_pModeInfo) { + vd_printf("%s OOM ", __FUNCTION__); + return false; + } + + ///clear the above arrays + ZeroMemory(_pPathInfo, sizeof(DISPLAYCONFIG_PATH_INFO) * _NumPathElements); + ZeroMemory(_pModeInfo, sizeof(DISPLAYCONFIG_MODE_INFO) * _NumModeElements); + return true; +} + +void CCD::free_config_buffers() +{ + if (_pModeInfo) { + free(_pModeInfo); + _pModeInfo = NULL; + } + if (_pPathInfo) { + free(_pPathInfo); + _pPathInfo = NULL; + } + _NumModeElements = _NumPathElements = 0; +} + +bool CCD::get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR dev_name) +{ + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name; + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME); + source_name.header.adapterId = path->sourceInfo.adapterId; + source_name.header.id = path->sourceInfo.id; + + _error = _pfnGetDeviceInfo(&source_name.header); + if (_error) { + vd_printf("%s DisplayConfigGetDeviceInfo failed with %lu", __FUNCTION__, _error); + return false; + } + memcpy((void *)dev_name, source_name.viewGdiDeviceName, CCHDEVICENAME* sizeof(TCHAR)); + return true; +} + +bool CCD::is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO* path) +{ + //Does this path belong to device_name? + TCHAR dev_name[CCHDEVICENAME]; + if (!get_device_name_config(path, dev_name)) { + return false; + } + if (_tcscmp(dev_name, device_name)) { + return false; + } + return true; +} + +// If we have detached the primary monitor, then we need to reset the positions of the remaining +// monitors to insure that at least one is positioned at (0,0) +bool CCD::verify_primary_position() +{ + LONG leftmost_x(0); + if(!_primary_detached) { + return true; + } + _primary_detached = false; + + for (UINT32 i = 0; i < _NumPathElements; i++) { + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i]; + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE)) + continue; + + DISPLAYCONFIG_MODE_INFO* mode = &_pModeInfo[path_info->sourceInfo.modeInfoIdx]; + if (leftmost_x > mode->sourceMode.position.x) { + leftmost_x = mode->sourceMode.position.x; + } + } + + if (leftmost_x == 0) { + return false; + } + + for (UINT32 i = 0; i < _NumPathElements; i++) { + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i]; + if ((!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE))) + continue; + DISPLAYCONFIG_MODE_INFO* mode = &_pModeInfo[path_info->sourceInfo.modeInfoIdx]; + vd_printf("%s: setting mode x to %lu", __FUNCTION__, mode->sourceMode.position.x); + mode->sourceMode.position.x -= leftmost_x; + } + _path_state = PATH_UPDATED; + return true; +} + +bool CCD::update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode) +{ + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false); + if (!mode) + return false; + + mode->sourceMode.position.x = dev_mode->dmPosition.x; + mode->sourceMode.position.y = dev_mode->dmPosition.y; + vd_printf("%s: %S updated path mode to (%lu, %lu) - (%u x%u)", __FUNCTION__, + device_name, + mode->sourceMode.position.x, mode->sourceMode.position.y, + mode->sourceMode.width, mode->sourceMode.height); + _path_state = PATH_UPDATED; + return true; + +} + +bool CCD::update_mode_size(LPCTSTR device_name, DEVMODE* dev_mode) +{ + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false); + if (!mode) { + return false; + } + + mode->sourceMode.width = dev_mode->dmPelsWidth; + mode->sourceMode.height = dev_mode->dmPelsHeight; + vd_printf("%s: %S updated path mode to (%lu, %lu - (%u x %u)", __FUNCTION__, + device_name, + mode->sourceMode.position.x, mode->sourceMode.position.y, + mode->sourceMode.width, mode->sourceMode.height); + _path_state = PATH_UPDATED; + return true; +} + +void CCD::update_detached_primary_state(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO * path_info) +{ + DISPLAYCONFIG_MODE_INFO* mode(get_active_mode(device_name, false)); + + //will need to reset monitor positions if primary detached + path_info->flags = path_info->flags & ~DISPLAYCONFIG_PATH_ACTIVE; + if (!mode|| mode->sourceMode.position.x != 0 || mode->sourceMode.position.y != 0) { + return ; + } + _primary_detached = true; +} + +bool CCD::set_path_state(LPCTSTR device_name, MONITOR_STATE new_state) +{ + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false)); + MONITOR_STATE current_path_state(MONITOR_DETACHED); + + if(path && (path->flags & DISPLAYCONFIG_PATH_ACTIVE)) { + current_path_state = MONITOR_ATTACHED; + } + + //If state didn't change, nothing to do + if(current_path_state == new_state ) { + return true; + } + + if(!path) { + return false; + } + + _path_state = PATH_UPDATED; + if (new_state == MONITOR_DETACHED) { + update_detached_primary_state(device_name, path); + } + else { + path->flags = path->flags | DISPLAYCONFIG_PATH_ACTIVE; + } + return true; +} + +bool CCD::is_attached(LPCTSTR device_name) +{ + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false)); + if(!path) { + return false; + } + return (path->flags & DISPLAYCONFIG_PATH_ACTIVE); +} + +bool CCD::is_active_path(DISPLAYCONFIG_PATH_INFO * path) +{ + if(!path || !(path->flags & DISPLAYCONFIG_PATH_ACTIVE) || + (path->sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)) { + return false; + } + return true; +} +#endif \ No newline at end of file diff --git a/vdagent/display_configuration.h b/vdagent/display_configuration.h new file mode 100644 index 0000000..eeba1c2 --- /dev/null +++ b/vdagent/display_configuration.h @@ -0,0 +1,192 @@ +/* +Copyright (C) 2015 Red Hat, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once +#include <sdkddkver.h> +#include <windows.h> +#include <d3dtypes.h> +#include "vdlog.h" + +#ifdef __MINGW32__ +#include "d3dkmt.h" +#include "CCD.h" +#endif + +//Check for a reasonable SDK +#if (_WIN32_WINNT < _WIN32_WINNT_WINXP) +#error required Windows WDK not found +#endif + +//Windows 10 build only +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) +#include <d3dumddi.h> +#include <km/D3dkmthk.h> +#endif + +#include <spice/qxl_windows.h> +#include <spice/qxl_dev.h> +#include "desktop_layout.h" +#include "vdlog.h" + +typedef enum { + XPDM, + WDDM, + INVALID_DRIVER, +}DRIVER_TYPE; + +typedef enum { + MONITOR_DETACHED, + MONITOR_ATTACHED, +}MONITOR_STATE; + +typedef enum { + PATH_UPDATED, + PATH_CURRENT, +}PATH_STATE; + +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) +//Makes calls into the CCD API for getting/setting display settings on WDDM drivers +//Use is exclusive to wddm display config class + +typedef LONG(APIENTRY* PDISPLAYCONFIG_GETDEVICEINFO)(DISPLAYCONFIG_DEVICE_INFO_HEADER*); +typedef LONG(APIENTRY* PGETDISPLAYCONFIG_BUFFERSIZES)(UINT32, UINT32*, UINT32*); +typedef LONG(APIENTRY* PQUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, + DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*); +typedef LONG(APIENTRY* PSETDISPLAYCONFIG)(UINT32, DISPLAYCONFIG_PATH_INFO*, UINT32, + DISPLAYCONFIG_MODE_INFO*, UINT32); + +class CCD { +protected: + CCD(); + ~CCD(); + + bool query_display_config(); + bool set_display_config(); + bool update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode); + bool update_mode_size(LPCTSTR DeviceNmae, DEVMODE* dev_mode); + void update_detached_primary_state(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO * path_info); + bool set_path_state(LPCTSTR device_name, MONITOR_STATE state); + bool is_attached(LPCTSTR device_name); + bool is_active_path(DISPLAYCONFIG_PATH_INFO * path); + LONG error() { return _error; } + +private: + bool load_api(); + bool get_config_buffers(); + void free_config_buffers(); + bool verify_primary_position(); + bool is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO* path); + DISPLAYCONFIG_MODE_INFO* get_active_mode(LPCTSTR device_name, bool return_on_error); + DISPLAYCONFIG_PATH_INFO* get_device_path(LPCTSTR device_name, bool bActive); + bool get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR dev_name); + void debug_print_config(const char* prefix = NULL); + +private: + //CCD API stuff + UINT32 _NumPathElements; + UINT32 _NumModeElements; + DISPLAYCONFIG_PATH_INFO* _pPathInfo; + DISPLAYCONFIG_MODE_INFO* _pModeInfo; + + //CCD API function pointers + PDISPLAYCONFIG_GETDEVICEINFO _pfnGetDeviceInfo; + PGETDISPLAYCONFIG_BUFFERSIZES _pfnGetDisplayConfigBufferSizes; + PQUERYDISPLAYCONFIG _pfnQueryDisplayConfig; + PSETDISPLAYCONFIG _pfnSetDisplayConfig; + + LONG _error; + bool _primary_detached; + PATH_STATE _path_state; + friend class WDDMInterface; +}; +#endif + +class DisplayMode; + +//Class provides interface to get/set display configurations +class DisplayConfig { +public: + static DisplayConfig* create_config(); + DisplayConfig();; + virtual ~DisplayConfig() {}; + + virtual bool is_attached(DISPLAY_DEVICE* dev_info) = 0; + virtual bool custom_display_escape(LPCTSTR device, DEVMODE* mode) = 0; + virtual bool update_monitor_config(LPCTSTR device, DisplayMode* mode, DEVMODE* dev_mode) = 0; + virtual bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state) = 0; + virtual LONG update_display_settings() = 0; + virtual bool update_dev_mode_position(LPCTSTR dev_name, DEVMODE* dev_mode, LONG x, LONG y) = 0; + DRIVER_TYPE type() { return _driver_type; }; + void set_monitors_config(bool flag) { _send_monitors_config = flag; } + virtual void update_config_path() {}; + +protected: + DRIVER_TYPE _driver_type; + bool _send_monitors_config; +}; + +//DisplayConfig implementation for guest with XPDM graphics drivers +class XPDMInterface : public DisplayConfig { +public: + XPDMInterface() :DisplayConfig() { _driver_type = XPDM; }; + ~XPDMInterface() {} + bool is_attached(DISPLAY_DEVICE* dev_info);; + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode); + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode, DEVMODE* dev_mode); + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state); + LONG update_display_settings(); + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode, LONG x, LONG y); + +private: + bool find_best_mode(LPCTSTR Device, DEVMODE* dev_mode); +}; +#if (_WIN32_WINNT == _WIN32_WINNT_WIN10) +//DisplayConfig implementation for guest with WDDM graphics drivers +class WDDMInterface : public DisplayConfig { +public: + WDDMInterface(); + ~WDDMInterface(); + bool is_attached(DISPLAY_DEVICE* dev_info); + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state); + LONG update_display_settings(); + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode); + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode, DEVMODE* dev_mode); + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode, LONG x, LONG y); + void update_config_path(); + +private: + bool init_d3d_api(); + D3DKMT_HANDLE adapter_handle(LPCTSTR device_name); + D3DKMT_HANDLE handle_from_DC(LPCTSTR adapter_name); + D3DKMT_HANDLE handle_from_device_name(LPCTSTR adapter_name); + D3DKMT_HANDLE handle_from_GDI_name(LPCTSTR adapter_name); + + void close_adapter(D3DKMT_HANDLE handle); + bool escape(LPCTSTR device_name, void* data, UINT sizeData); + +private: + //GDI Function pointers + PFND3DKMT_OPENADAPTERFROMHDC _pfnOpen_adapter_hdc; + PFND3DKMT_CLOSEADAPTER _pfnClose_adapter; + PFND3DKMT_ESCAPE _pfnEscape; + PFND3DKMT_OPENADAPTERFROMDEVICENAME _pfnOpen_adapter_device_name; + PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME _pfnOpen_adapter_gdi_name; + + //object handles the CCD API + CCD _ccd; +}; +#endif +typedef class DisplayConfig DISPLAY_CONFIG; diff --git a/vdagent/vdagent.vcxproj b/vdagent/vdagent.vcxproj new file mode 100644 index 0000000..4f6f54a --- /dev/null +++ b/vdagent/vdagent.vcxproj @@ -0,0 +1,380 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win10 Debug|Win32"> + <Configuration>Win10 Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win10 Debug|x64"> + <Configuration>Win10 Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win10 Release|Win32"> + <Configuration>Win10 Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win10 Release|x64"> + <Configuration>Win10 Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{CAD5A7E6-E9F5-4071-AFDA-25F76FDA5442}</ProjectGuid> + <RootNamespace>redagent</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win10 Release|Win32'"> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win10 Release|x64'"> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Win10 Release|x64'"> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Win10 Release|Win32'"> + <Import Project="..\Spice.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|Win32'"> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(Configuration)\</IntDir> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Release|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_DEBUG_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_DEBUG_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;$(WindowsSdkDir)\Include\$(TargetPlatformVersion);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=_WIN32_WINNT_WIN10;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_DEBUG_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_DEBUG_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_DEBUG_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_DEBUG_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;$(WindowsSdkDir)\Include\$(TargetPlatformVersion);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_DEBUG_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_DEBUG_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_LIBS_DIR);$(SPICE_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=_WIN32_WINNT_WIN10;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;$(WindowsSdkDir)\Include\$(TargetPlatformVersion);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win10 Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=_WIN32_WINNT_WIN10;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);$(SPICE_LIBS)\include\CxImage;$(WindowsSdkDir)\Include\$(TargetPlatformVersion);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Link> + <AdditionalDependencies>Version.lib;$(SPICE_LIB_LIST);wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SPICE_LIBS_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\common\vdcommon.cpp" /> + <ClCompile Include="..\common\vdlog.cpp" /> + <ClCompile Include="as_user.cpp" /> + <ClCompile Include="desktop_layout.cpp" /> + <ClCompile Include="display_configuration.cpp" /> + <ClCompile Include="display_setting.cpp" /> + <ClCompile Include="file_xfer.cpp" /> + <ClCompile Include="vdagent.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\common\vdcommon.h" /> + <ClInclude Include="..\common\vdlog.h" /> + <ClInclude Include="as_user.h" /> + <ClInclude Include="CCD.h" /> + <ClInclude Include="desktop_layout.h" /> + <ClInclude Include="display_configuration.h" /> + <ClInclude Include="display_setting.h" /> + <ClInclude Include="driver_interface.h" /> + <ClInclude Include="file_xfer.h" /> + <ClInclude Include="resource.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="vdagent.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/vdservice/vdservice.vcxproj b/vdservice/vdservice.vcxproj new file mode 100644 index 0000000..7ea66ea --- /dev/null +++ b/vdservice/vdservice.vcxproj @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}</ProjectGuid> + <RootNamespace>redservice</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\Spice.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(Configuration)\</IntDir> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>WtsApi32.lib;Userenv.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>WtsApi32.lib;Userenv.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX64</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>WtsApi32.lib;Userenv.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <AdditionalIncludeDirectories>..\common;$(SPICE_PROTOCOL_DIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader /> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>WtsApi32.lib;Userenv.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention /> + <TargetMachine>MachineX64</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\common\vdcommon.h" /> + <ClInclude Include="..\common\vdlog.h" /> + <ClInclude Include="resource.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="vdservice.rc" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\common\vdcommon.cpp" /> + <ClCompile Include="..\common\vdlog.cpp" /> + <ClCompile Include="vdservice.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file -- 1.8.3.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel