/// <summary> /// Validates an array of paths before applying /// </summary> /// <param name="pathInfos">The array of paths</param> /// <param name="allowChanges">true to allow changes and reordering of the provided paths, otherwise false</param> /// <returns>true if the provided paths are valid, otherwise false</returns> public static bool ValidatePathInfos(IEnumerable <PathInfo> pathInfos, bool allowChanges = true) { DisplayConfigModeInfo[] displayConfigModeInfos; var displayConfigPathInfos = GetDisplayConfigPathInfos(pathInfos, out displayConfigModeInfos); if (displayConfigPathInfos.Length <= 0) { return(false); } var flags = displayConfigModeInfos.Length == 0 ? SetDisplayConfigFlags.TopologySupplied : SetDisplayConfigFlags.UseSuppliedDisplayConfig; if (allowChanges) { flags |= displayConfigModeInfos.Length == 0 ? SetDisplayConfigFlags.AllowPathOrderChanges : SetDisplayConfigFlags.AllowChanges; } return (DisplayConfigApi.SetDisplayConfig( (uint)displayConfigPathInfos.Length, displayConfigPathInfos, (uint)displayConfigModeInfos.Length, displayConfigModeInfos.Length > 0 ? displayConfigModeInfos : null, SetDisplayConfigFlags.Validate | flags) == Win32Status.Success); }
/// <summary> /// Validates a topology before applying /// </summary> /// <param name="topology">The topology identification</param> /// <returns>true if topology is applicable, otherwise false</returns> /// <exception cref="ArgumentOutOfRangeException"></exception> public static bool ValidateTopology(DisplayConfigTopologyId topology) { if (topology == DisplayConfigTopologyId.None) { throw new ArgumentOutOfRangeException(nameof(topology), "Topology should not be empty."); } var flags = (SetDisplayConfigFlags)topology; return(DisplayConfigApi.SetDisplayConfig(0, null, 0, null, SetDisplayConfigFlags.Validate | flags) == Win32Status.Success); }
/// <summary> /// Applies an array of paths /// </summary> /// <param name="pathInfos">The array of paths</param> /// <param name="allowChanges">true to allow changes and reordering of the provided paths, otherwise false</param> /// <param name="saveToDatabase">true to save the paths to the persistence database if call succeed, otherwise false</param> /// <param name="forceModeEnumeration">true to force driver mode enumeration before applying the paths</param> /// <exception cref="PathChangeException">Error in changing paths</exception> public static void ApplyPathInfos(IEnumerable <PathInfo> pathInfos, bool allowChanges = true, bool saveToDatabase = false, bool forceModeEnumeration = false) { var pathInfosArray = pathInfos.ToArray(); if (!ValidatePathInfos(pathInfosArray, allowChanges)) { throw new PathChangeException("Invalid paths information."); } DisplayConfigModeInfo[] displayConfigModeInfos; var displayConfigPathInfos = GetDisplayConfigPathInfos(pathInfosArray, out displayConfigModeInfos); if (displayConfigPathInfos.Length <= 0) { return; } var flags = displayConfigModeInfos.Length == 0 ? SetDisplayConfigFlags.TopologySupplied : SetDisplayConfigFlags.UseSuppliedDisplayConfig; if (allowChanges) { flags |= displayConfigModeInfos.Length == 0 ? SetDisplayConfigFlags.AllowPathOrderChanges : SetDisplayConfigFlags.AllowChanges; } else if (displayConfigModeInfos.Length > 0) { flags |= SetDisplayConfigFlags.NoOptimization; } if (saveToDatabase && (displayConfigModeInfos.Length > 0)) { flags |= SetDisplayConfigFlags.SaveToDatabase; } if (forceModeEnumeration && (displayConfigModeInfos.Length > 0)) { flags |= SetDisplayConfigFlags.ForceModeEnumeration; } var result = DisplayConfigApi.SetDisplayConfig( (uint)displayConfigPathInfos.Length, displayConfigPathInfos, (uint)displayConfigModeInfos.Length, displayConfigModeInfos.Length > 0 ? displayConfigModeInfos : null, SetDisplayConfigFlags.Apply | flags); if (result != Win32Status.Success) { throw new PathChangeException("An error occurred while applying the paths information.", new Win32Exception((int)result)); } }
/// <summary> /// Applies a saved topology /// </summary> /// <param name="topology">The topology identification to apply</param> /// <param name="allowPersistence">true to allows persistence of the changes, otherwise false</param> /// <exception cref="PathChangeException">Error in changing paths</exception> public static void ApplyTopology(DisplayConfigTopologyId topology, bool allowPersistence = false) { if (!ValidateTopology(topology)) { throw new PathChangeException("Invalid topology request."); } var flags = (SetDisplayConfigFlags)topology; if (allowPersistence) { flags |= SetDisplayConfigFlags.PathPersistIfRequired; } var result = DisplayConfigApi.SetDisplayConfig(0, null, 0, null, SetDisplayConfigFlags.Apply | flags); if (result != Win32Status.Success) { throw new PathChangeException("An error occurred while applying the requested topology.", new Win32Exception((int)result)); } }
private static PathInfo[] GetPathInfos(QueryDeviceConfigFlags flags, out DisplayConfigTopologyId topologyId) { DisplayConfigPathInfo[] displayPaths; DisplayConfigModeInfo[] displayModes; uint pathCount; while (true) { uint modeCount; var error = DisplayConfigApi.GetDisplayConfigBufferSizes(flags, out pathCount, out modeCount); if (error != Win32Status.Success) { throw new Win32Exception((int)error); } displayPaths = new DisplayConfigPathInfo[pathCount]; displayModes = new DisplayConfigModeInfo[modeCount]; if (flags == QueryDeviceConfigFlags.DatabaseCurrent) { error = DisplayConfigApi.QueryDisplayConfig(flags, ref pathCount, displayPaths, ref modeCount, displayModes, out topologyId); } else { topologyId = DisplayConfigTopologyId.None; error = DisplayConfigApi.QueryDisplayConfig(flags, ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero); } if (error == Win32Status.Success) { break; } if (error != Win32Status.ErrorInsufficientBuffer) { throw new Win32Exception((int)error); } } var pathInfos = new Dictionary <uint, Tuple <DisplayConfigPathSourceInfo, DisplayConfigSourceMode?, List < Tuple <DisplayConfigPathInfoFlags, DisplayConfigPathTargetInfo, DisplayConfigTargetMode?, DisplayConfigDesktopImageInfo?> > > > (); var sourceId = uint.MaxValue; for (var i = 0u; i < pathCount; i++) { var displayPath = displayPaths[i]; DisplayConfigSourceMode?sourceMode = null; var key = sourceId; var isVirtualSupported = displayPath.Flags.HasFlag(DisplayConfigPathInfoFlags.SupportVirtualMode); if (isVirtualSupported && (displayPath.SourceInfo.SourceModeInfoIndex != DisplayConfigSourceMode.InvalidSourceModeIndex) && (displayModes[displayPath.SourceInfo.SourceModeInfoIndex].InfoType == DisplayConfigModeInfoType.Source)) { sourceMode = displayModes[displayPath.SourceInfo.SourceModeInfoIndex].SourceMode; key = displayPath.SourceInfo.SourceModeInfoIndex; } else if (!isVirtualSupported && (displayPath.SourceInfo.ModeInfoIndex != DisplayConfigModeInfo.InvalidModeIndex) && (displayModes[displayPath.SourceInfo.ModeInfoIndex].InfoType == DisplayConfigModeInfoType.Source)) { sourceMode = displayModes[displayPath.SourceInfo.ModeInfoIndex].SourceMode; key = displayPath.SourceInfo.ModeInfoIndex; } else { sourceId--; } if (!pathInfos.ContainsKey(key)) { pathInfos.Add(key, new Tuple <DisplayConfigPathSourceInfo, DisplayConfigSourceMode?, List < Tuple <DisplayConfigPathInfoFlags, DisplayConfigPathTargetInfo, DisplayConfigTargetMode?, DisplayConfigDesktopImageInfo?> > >( displayPath.SourceInfo, sourceMode, new List < Tuple <DisplayConfigPathInfoFlags, DisplayConfigPathTargetInfo, DisplayConfigTargetMode?, DisplayConfigDesktopImageInfo?> > ())); } DisplayConfigTargetMode?targetMode = null; if (isVirtualSupported && (displayPath.TargetInfo.TargetModeInfoIndex != DisplayConfigTargetMode.InvalidTargetModeIndex) && (displayModes[displayPath.TargetInfo.TargetModeInfoIndex].InfoType == DisplayConfigModeInfoType.Target)) { targetMode = displayModes[displayPath.TargetInfo.TargetModeInfoIndex].TargetMode; } else if (!isVirtualSupported && (displayPath.TargetInfo.ModeInfoIndex != DisplayConfigModeInfo.InvalidModeIndex) && (displayModes[displayPath.TargetInfo.ModeInfoIndex].InfoType == DisplayConfigModeInfoType.Target)) { targetMode = displayModes[displayPath.TargetInfo.ModeInfoIndex].TargetMode; } DisplayConfigDesktopImageInfo?desktopImageMode = null; if (isVirtualSupported && (displayPath.TargetInfo.DesktopModeInfoIndex != DisplayConfigDesktopImageInfo.InvalidDesktopImageModeIndex) && (displayModes[displayPath.TargetInfo.DesktopModeInfoIndex].InfoType == DisplayConfigModeInfoType.DesktopImage)) { desktopImageMode = displayModes[displayPath.TargetInfo.DesktopModeInfoIndex].DesktopImageInfo; } pathInfos[key].Item3.Add( new Tuple <DisplayConfigPathInfoFlags, DisplayConfigPathTargetInfo, DisplayConfigTargetMode?, DisplayConfigDesktopImageInfo?>( displayPath.Flags, displayPath.TargetInfo, targetMode, desktopImageMode)); } return (pathInfos.Select(pair => new PathInfo(pair.Value.Item1, pair.Value.Item2, pair.Value.Item3)).ToArray()); }