/// <summary>
        /// Remaps an array of DisplayConfigModeInfo entries' adapter IDs from a previous session to
        /// the current Windows session's adapter IDs for a given display adapter.
        /// </summary>
        /// <param name="displayPreset">The Display preset containing old adapter ID information to remap</param>
        /// <param name="modeInfoArray">The array of mode info entries to modify with new adapter IDs.</param>
        /// <returns></returns>
        public bool RemapDisplayConfigModeInfoAdapterIds(DisplayPreset displayPreset, ref CCD.DisplayConfigModeInfo[] modeInfoArray)
        {
            bool allAdapterIdsRemappable = true;

            Dictionary <CCD.LUID, string> displayPresetAdapterIdToAdapterNameMap = new Dictionary <CCD.LUID, string>();

            foreach (CCD.DisplayConfigAdapterName adapterName in displayPreset.AdapterNames)
            {
                displayPresetAdapterIdToAdapterNameMap.Add(adapterName.header.adapterId, adapterName.adapterDevicePath);
            }

            for (int i = 0; i < modeInfoArray.Length; i++)
            {
                CCD.LUID currentAdapterId;

                if (GetCurrentAdapterIdForDevice(displayPresetAdapterIdToAdapterNameMap[modeInfoArray[i].adapterId], out currentAdapterId))
                {
                    modeInfoArray[i].adapterId = currentAdapterId;
                }
                else
                {
                    allAdapterIdsRemappable = false;
                    break;
                }
            }

            return(allAdapterIdsRemappable);
        }
示例#2
0
        /// <summary>
        /// Applies the supplied display preset to the system and dynamically switches to it. Returns the
        /// display configuration in use before the new preset is applied as a DisplayPreset. This allows
        /// consumers to switch back to that last configuration if needed. Throws exception if failed to
        /// capture current configuration, or if failed to apply supplied preset configuration.
        /// </summary>
        /// <param name="displayPreset">The display configuration to switch to.</param>
        /// <returns>The display configuration in use before the supplied preset is applied. The name of
        /// the preset will be a GUID.</returns>
        static public DisplayPreset ReturnLastConfigAndApplyPreset(DisplayPreset displayPreset)
        {
            Guid guid = Guid.NewGuid();

            DisplayPreset currentConfig = RecordCurrentConfiguration(guid.ToString());

            ApplyPreset(displayPreset);

            return(currentConfig);
        }
示例#3
0
        /// <summary>
        /// Retrieves the DisplayPreset with a specific name.
        /// </summary>
        /// <param name="name">Name of the preset.</param>
        /// <returns>The DisplayPreset with the supplied name, null otherwise.</returns>
        public DisplayPreset GetPreset(string name)
        {
            DisplayPreset requestedPreset = null;

            if (mDisplayPresetDictionary.TryGetValue(name, out requestedPreset))
            {
                return(requestedPreset);
            }
            else
            {
                return(null);
            }
        }
示例#4
0
        /// <summary>
        /// Adds a new DisplayPreset to the collection of display configuration presets.
        /// </summary>
        /// <param name="preset">The new DisplayPreset to add.</param>
        /// <returns>True if the DisplayPreset.Name is unique in the collection of presets. False otherwise.</returns>
        public bool TryAddDisplayPreset(DisplayPreset preset)
        {
            if (!mDisplayPresetDictionary.ContainsKey(preset.Name))
            {
                mDisplayPresetDictionary.Add(preset.Name, preset);
                DisplayPresetCollectionChanged?.Invoke(DisplayPresetCollectionChangeType.PresetAdded, preset.Name);

                return(true);
            }
            else
            {
                return(false);
            }
        }
示例#5
0
        /// <summary>
        /// Applies the supplied display preset to the system, and dynamically changes it.
        /// Throws if the settings failed to be applied.
        /// </summary>
        /// <param name="displayPreset">The display preset to apply.</param>
        static public void ApplyPreset(DisplayPreset displayPreset)
        {
            AdapterIdMapper.DisplayPresetAdapterIdValidation validationResult =
                AdapterIdMapper.GetAdapterIdMapper().ValidateDisplayPresetAdapterIds(displayPreset);

            // Copy to working arrays so that if we need to remap we don't affect the original
            // display preset data.
            CCD.DisplayConfigPathInfo[] pathInfoArrayToApply = new CCD.DisplayConfigPathInfo[displayPreset.PathInfoArray.Length];
            displayPreset.PathInfoArray.CopyTo(pathInfoArrayToApply, 0);

            CCD.DisplayConfigModeInfo[] modeInfoArrayToApply = new CCD.DisplayConfigModeInfo[displayPreset.ModeInfoArray.Length];
            displayPreset.ModeInfoArray.CopyTo(modeInfoArrayToApply, 0);

            if (validationResult == AdapterIdMapper.DisplayPresetAdapterIdValidation.NeedAdapterIdRemap)
            {
                // TODO: The remap methods return a boolean, though it sorta doesn't matter for us since
                // we've already done validation. It's the right design that those methods return a
                // boolean, so maybe we should put an assert here?
                AdapterIdMapper.GetAdapterIdMapper().RemapDisplayConfigPathInfoAdapterIds(displayPreset, ref pathInfoArrayToApply);
                AdapterIdMapper.GetAdapterIdMapper().RemapDisplayConfigModeInfoAdapterIds(displayPreset, ref modeInfoArrayToApply);
            }
            else if (validationResult == AdapterIdMapper.DisplayPresetAdapterIdValidation.MissingAdapter)
            {
                // TODO: Have better interface for handling this case, cuz it's a real case where someone
                // upgrades a video card for example.
                throw new Exception("Missing adapter! Can't apply preset.");
            }
            else if (validationResult == AdapterIdMapper.DisplayPresetAdapterIdValidation.DisplayPresetMissingAdapterInformation)
            {
                // TODO: Handle this better, basically case where schema change
                throw new Exception("Display Preset is missing adapter name information.");
            }

            // Third validation result case is that all the adapter IDs are still valid and map correctly, so no action required.

            Win32Utilities.ThrowIfResultCodeNotSuccess(
                CCD.SetDisplayConfig(
                    (uint)pathInfoArrayToApply.Length,
                    pathInfoArrayToApply,
                    (uint)modeInfoArrayToApply.Length,
                    modeInfoArrayToApply,
                    CCD.SdcFlags.Apply | CCD.SdcFlags.UseSuppliedDisplayConfig | CCD.SdcFlags.AllowChanges | CCD.SdcFlags.SaveToDatabase));
        }
        /// <summary>
        /// Checks the adapter IDs in use by a DisplayPreset and validates whether those IDs need to be
        /// remapped to new values before being applied, and whether all the display adapters the preset
        /// uses are still installed and available on the system.
        /// </summary>
        /// <param name="displayPreset">The preset to validate.</param>
        /// <returns>A DisplayPresetAdapterIdValidation value indicating the validation result.</returns>
        public DisplayPresetAdapterIdValidation ValidateDisplayPresetAdapterIds(DisplayPreset displayPreset)
        {
            bool allAdapterNamesAccountedFor = true;
            bool allAdapterIdsValid          = true;

            if (displayPreset.AdapterNames != null)
            {
                foreach (CCD.DisplayConfigAdapterName adapterName in displayPreset.AdapterNames)
                {
                    if (!mCurrentRuntimeDeviceAdapterNamesToAdapterIds.ContainsKey(adapterName.adapterDevicePath))
                    {
                        allAdapterNamesAccountedFor = false;
                        break;
                    }

                    if (!mCurrentRuntimeDeviceAdapterNamesToAdapterIds[adapterName.adapterDevicePath].Equals(adapterName.header.adapterId))
                    {
                        allAdapterIdsValid = false;
                    }
                }
            }

            if (displayPreset.AdapterNames == null)
            {
                return(DisplayPresetAdapterIdValidation.DisplayPresetMissingAdapterInformation);
            }
            else if (!allAdapterNamesAccountedFor)
            {
                return(DisplayPresetAdapterIdValidation.MissingAdapter);
            }
            else if (!allAdapterIdsValid)
            {
                return(DisplayPresetAdapterIdValidation.NeedAdapterIdRemap);
            }
            else
            {
                return(DisplayPresetAdapterIdValidation.AllValid);
            }
        }
示例#7
0
        /// <summary>
        /// Records the current display configuration as a display preset.
        /// </summary>
        /// <param name="presetName">Name of the preset to create</param>
        /// <returns>A DisplayPreset with the current configuration and supplied name.
        ///             Throws exception if failed to get display configuration paths and modes.</returns>
        static public DisplayPreset RecordCurrentConfiguration(string presetName)
        {
            DisplayPreset displayPreset = null;

            const CCD.QueryDisplayFlags OnlyActivePathsFlag = CCD.QueryDisplayFlags.OnlyActivePaths;

            int numPathArrayElements;
            int numModeInfoArrayElements;

            // Get the buffer sizes needed to hold the active paths and the source/target mode table.
            Win32Utilities.ThrowIfResultCodeNotSuccess(
                CCD.GetDisplayConfigBufferSizes(
                    OnlyActivePathsFlag,
                    out numPathArrayElements,
                    out numModeInfoArrayElements));

            CCD.DisplayConfigPathInfo[] pathInfoArray = new CCD.DisplayConfigPathInfo[numPathArrayElements];
            CCD.DisplayConfigModeInfo[] modeInfoArray = new CCD.DisplayConfigModeInfo[numModeInfoArrayElements];

            // Get the active paths and their associated source/target modes.
            Win32Utilities.ThrowIfResultCodeNotSuccess(
                CCD.QueryDisplayConfig(
                    OnlyActivePathsFlag,
                    ref numPathArrayElements,
                    pathInfoArray,
                    ref numModeInfoArrayElements,
                    modeInfoArray,
                    IntPtr.Zero));

            displayPreset = new DisplayPreset(presetName);

            displayPreset.PathInfoArray = pathInfoArray;
            displayPreset.ModeInfoArray = modeInfoArray;

            // Save the Target Device Name structs to log the monitor output devices. This isn't
            // actually used for anything but makes the XML output more readable.
            CCD.DisplayConfigTargetDeviceName[] targetDeviceNameArray = new CCD.DisplayConfigTargetDeviceName[pathInfoArray.Length];

            for (int i = 0; i < pathInfoArray.Length; i++)
            {
                targetDeviceNameArray[i] = GetTargetDeviceName(pathInfoArray[i].targetInfo.adapterId, pathInfoArray[i].targetInfo.id);
            }

            displayPreset.TargetDeviceNames = targetDeviceNameArray;

            // Save the Adapter Name structs. The adapter ID values may change on reboot, as they
            // appear to simply be a logical, run-time value rather than a persistent identifier.
            // So we save the Adapter Name structs to log a device name that the adapter ID maps to.
            // We can use this to update the adapter IDs we save in our presets such that the presets
            // will still be usable after a reboot. Otherwise, when the machine is rebooted and the
            // user tries to apply a saved preset, the API call will fail because the adapter ID has
            // changed.
            Dictionary <CCD.LUID, CCD.DisplayConfigAdapterName> adapterIdToAdapterName = new Dictionary <CCD.LUID, CCD.DisplayConfigAdapterName>();

            // Find all the unique adapter IDs used in the active paths and capture the display adapter
            // device names that those IDs map to.
            foreach (CCD.DisplayConfigPathInfo pathInfo in pathInfoArray)
            {
                if (!adapterIdToAdapterName.ContainsKey(pathInfo.sourceInfo.adapterId))
                {
                    CCD.DisplayConfigAdapterName adapterName = new CCD.DisplayConfigAdapterName();
                    adapterName.header.adapterId = pathInfo.sourceInfo.adapterId;
                    adapterName.header.size      = (uint)System.Runtime.InteropServices.Marshal.SizeOf(adapterName);
                    adapterName.header.type      = CCD.DisplayConfigDeviceInfoType.GetAdapterName;

                    Win32Utilities.ThrowIfResultCodeNotSuccess(CCD.DisplayConfigGetDeviceInfo(ref adapterName));

                    adapterIdToAdapterName.Add(adapterName.header.adapterId, adapterName);
                }
            }

            displayPreset.AdapterNames = adapterIdToAdapterName.Values.ToArray();

            return(displayPreset);
        }