Windows 11 Enterprise 24H2 using WinApi set primary screen failed

Anonymous
2024-11-19T05:47:57+00:00

I am using Windows 11 Enterprise 24H2. running the following script to switch the primary display. The following script works fine in windwos11 23H2, but I found that in 24H2, the script can set the first screen as the primary display if the second screen is the primary display, and the script cannot set the second screen as the primary display if the first screen is the primary display.

Function Set-ScreenResolution { $pinvokeCode = @"using System;using System.Runtime.InteropServices;using System.Collections.Generic;using System.Linq;public class Screen{public WinApi.DEVMODE DeviceMode { get; set; }public WinApi.DISPLAY_DEVICE ScreenDevice { get; set; }public string DeviceName { get; set; }public bool IsPrimary { get; set; }public int ScreenWidth { get; set; }public int ScreenHeight { get; set; }public int XPosition { get; set; }public int YPosition { get; set; }}

public class ScreenHelper{public static List<Screen> GetAllScreen(){List<WinApi.DISPLAY_DEVICE> devices = new List<WinApi.DISPLAY_DEVICE>();List<Screen> screens = new List<Screen>();bool error = false;//Here I am listing all DisplayDevices (Monitors)for (int devId = 0; !error; devId++){try{WinApi.DISPLAY_DEVICE device = new WinApi.DISPLAY_DEVICE();device.cb = Marshal.SizeOf(typeof(WinApi.DISPLAY_DEVICE));error = !WinApi.User_32.EnumDisplayDevices(null, devId, ref device, 0);if ((device.StateFlags & WinApi.DisplayDeviceStateFlags.AttachedToDesktop) == WinApi.DisplayDeviceStateFlags.AttachedToDesktop){devices.Add(device);}}catch (Exception){error = true;}}

devices.ForEach(d => {WinApi.DEVMODE ndm = NewDevMode();WinApi.User_32.EnumDisplaySettings(d.DeviceName, (int)WinApi.DEVMODE_SETTINGS.ENUM_REGISTRY_SETTINGS, ref ndm);screens.Add(new Screen() {DeviceMode = ndm,ScreenDevice = d,DeviceName = d.DeviceName,IsPrimary = ((d.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) == WinApi.DisplayDeviceStateFlags.PrimaryDevice),ScreenWidth = (int)ndm.dmPelsWidth,ScreenHeight = (int)ndm.dmPelsHeight,XPosition = (int)ndm.dmPosition.x,YPosition = (int)ndm.dmPosition.y}); });

            return screens; }

public static void SetPrimaryScreen(string deviceName){List<Screen> screenList = GetAllScreen(); Screen primaryScreen = GetPrimaryScreen(screenList); Screen newPrimaryScreen = GetScreen(deviceName);

SwitchPrimaryScreen(newPrimaryScreen, primaryScreen);}

public static Screen GetPrimaryScreen(List<Screen> devices){foreach (Screen d in devices){if ((d.ScreenDevice.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) == WinApi.DisplayDeviceStateFlags.PrimaryDevice){return d;}}return null;}

public static List<Screen> GetUnPrimaryScreen(List<Screen> devices){ List<Screen> dList = new List<Screen>();

            foreach (Screen d in devices) {if ((d.ScreenDevice.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) != WinApi.DisplayDeviceStateFlags.PrimaryDevice){dList.Add(d);} }

            return dList; }

public static Screen GetScreen(string deviceName){List<Screen> screenList = GetAllScreen();return screenList.Where(p => p.ScreenDevice.DeviceName == deviceName).FirstOrDefault();}

public static void SwitchPrimaryScreen(Screen newPrimary, Screen oldPrimary){MoveOldPrimary(newPrimary, oldPrimary);MoveNewPrimary(newPrimary, oldPrimary);CommitChange(newPrimary, oldPrimary);}

private static void MoveOldPrimary(Screen newPrimary, Screen oldPrimary){WinApi.DEVMODE ndm3 = NewDevMode();ndm3.dmFields = WinApi.DEVMODE_Flags.DM_POSITION;ndm3.dmPosition.x = (int)newPrimary.DeviceMode.dmPelsWidth;ndm3.dmPosition.y = 0; WinApi.User_32.ChangeDisplaySettingsEx(oldPrimary.ScreenDevice.DeviceName, ref ndm3, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY | (int)WinApi.DeviceFlags.CDS_NORESET, IntPtr.Zero);

        }

        private static void MoveNewPrimary(Screen newPrimary, Screen oldPrimary) {WinApi.DEVMODE ndm4 = NewDevMode();ndm4.dmFields = WinApi.DEVMODE_Flags.DM_POSITION;ndm4.dmPosition.x = 0;ndm4.dmPosition.y = 0;WinApi.User_32.ChangeDisplaySettingsEx(newPrimary.ScreenDevice.DeviceName, ref ndm4, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_SET_PRIMARY | (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY | (int)WinApi.DeviceFlags.CDS_NORESET, IntPtr.Zero); }

        private static void CommitChange(Screen newPrimary, Screen oldPrimary) {WinApi.User_32.ChangeDisplaySettingsEx(null, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero); }

        private static WinApi.DEVMODE NewDevMode() {WinApi.DEVMODE dm = new WinApi.DEVMODE();dm.dmDeviceName = new String(new char[31]);dm.dmFormName = new String(new char[31]);dm.dmSize = (ushort)Marshal.SizeOf(dm);return dm;} }

   public class WinApi {public const Int32 CCHDEVICENAME = 32;public const Int32 CCHFORMNAME = 32;

public enum DEVMODE_SETTINGS{ENUM_CURRENT_SETTINGS = (-1),ENUM_REGISTRY_SETTINGS = (-2)}[Flags()]public enum DisplayDeviceStateFlags : int{/// <summary>The device is part of the desktop.</summary>AttachedToDesktop = 0x1,MultiDriver = 0x2,/// <summary>The device is part of the desktop.</summary>PrimaryDevice = 0x4,/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>MirroringDriver = 0x8,/// <summary>The device is VGA compatible.</summary>VGACompatible = 0x10,/// <summary>The device is removable; it cannot be the primary display.</summary>Removable = 0x20,/// <summary>The device has more display modes than its output devices support.</summary>ModesPruned = 0x8000000,Remote = 0x4000000,Disconnect = 0x2000000 }

        public enum Display_Device_Stateflags {DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x1,DISPLAY_DEVICE_MIRRORING_DRIVER = 0x8,DISPLAY_DEVICE_MODESPRUNED = 0x8000000,DISPLAY_DEVICE_MULTI_DRIVER = 0x2,DISPLAY_DEVICE_PRIMARY_DEVICE = 0x4,DISPLAY_DEVICE_VGA_COMPATIBLE = 0x10}

public enum DeviceFlags{CDS_FULLSCREEN = 0x4,CDS_GLOBAL = 0x8,CDS_NORESET = 0x10000000,CDS_RESET = 0x40000000,CDS_SET_PRIMARY = 0x10,CDS_TEST = 0x2,CDS_UPDATEREGISTRY = 0x1,CDS_VIDEOPARAMETERS = 0x20,}

public enum DEVMODE_Flags{DM_BITSPERPEL = 0x40000,DM_DISPLAYFLAGS = 0x200000,DM_DISPLAYFREQUENCY = 0x400000,DM_PELSHEIGHT = 0x100000,DM_PELSWIDTH = 0x80000,DM_POSITION = 0x20}

public enum DisplaySetting_Results{DISP_CHANGE_BADFLAGS = -4,DISP_CHANGE_BADMODE = -2,DISP_CHANGE_BADPARAM = -5,DISP_CHANGE_FAILED = -1,DISP_CHANGE_NOTUPDATED = -3,DISP_CHANGE_RESTART = 1,DISP_CHANGE_SUCCESSFUL = 0}

[StructLayout(LayoutKind.Sequential)]public struct POINTL{[MarshalAs(UnmanagedType.I4)]public int x;[MarshalAs(UnmanagedType.I4)]public int y;}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]public struct DEVMODE{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string dmDeviceName;

[MarshalAs(UnmanagedType.U2)]public UInt16 dmSpecVersion;

[MarshalAs(UnmanagedType.U2)]public UInt16 dmDriverVersion;

[MarshalAs(UnmanagedType.U2)]public UInt16 dmSize;

[MarshalAs(UnmanagedType.U2)]public UInt16 dmDriverExtra;

[MarshalAs(UnmanagedType.U4)]public DEVMODE_Flags dmFields;

public POINTL dmPosition;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmDisplayOrientation;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmDisplayFixedOutput;

[MarshalAs(UnmanagedType.I2)]public Int16 dmColor;

[MarshalAs(UnmanagedType.I2)]public Int16 dmDuplex;

[MarshalAs(UnmanagedType.I2)]public Int16 dmYResolution;

[MarshalAs(UnmanagedType.I2)]public Int16 dmTTOption;

[MarshalAs(UnmanagedType.I2)]public Int16 dmCollate;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string dmFormName;

[MarshalAs(UnmanagedType.U2)]public UInt16 dmLogPixels;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmBitsPerPel;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmPelsWidth;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmPelsHeight;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmDisplayFlags;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmDisplayFrequency;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmICMMethod;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmICMIntent;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmMediaType;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmDitherType;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmReserved1;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmReserved2;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmPanningWidth;

[MarshalAs(UnmanagedType.U4)]public UInt32 dmPanningHeight;}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]public struct DISPLAY_DEVICE{[MarshalAs(UnmanagedType.U4)]public int cb;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string DeviceName;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]public string DeviceString;[MarshalAs(UnmanagedType.U4)]public DisplayDeviceStateFlags StateFlags;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]public string DeviceID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]public string DeviceKey; }

        public class User_32 {[DllImport("user32.dll")]public static extern int ChangeDisplaySettings(ref DEVMODE devMode, int flags);

[DllImport("user32.dll")]public static extern int ChangeDisplaySettingsEx(string lpszDeviceName, [In] ref DEVMODE lpDevMode, IntPtr hwnd, int dwFlags, IntPtr lParam);

[DllImport("user32.dll")]public static extern int ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, int dwFlags, IntPtr lParam);

[DllImport("user32.dll")]public static extern bool EnumDisplayDevices(string lpDevice, int iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);

[DllImport("user32.dll")]public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode); }

    }

public class DisplaySwapper {public static void SwapPrimarySecondary() {List<Screen> UnPrimaryScreen = ScreenHelper.GetUnPrimaryScreen(ScreenHelper.GetAllScreen());if (UnPrimaryScreen.Count == 0){Console.WriteLine("Only one screen, no swapping.");return;}ScreenHelper.SetPrimaryScreen(UnPrimaryScreen[0].DeviceName);}}"@

Add-Type -TypeDefinition $pinvokeCode -Language CSharp

Call the function to swap displaysSet-ScreenResolution

***moved from Windows / Windows 11 / Display and graphics***

Windows Windows Client for IT Pros Devices and deployment Set up upgrades and drivers

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question. To protect privacy, user profiles for migrated questions are anonymized.

0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Anonymous
    2024-11-20T08:24:03+00:00

    Hello Monjelle,

    thank you for posting on the Microsoft Community Forums.

    Based on the description, I understand that your issue is related to development.

    Since there are no engineers dedicated to development in this forum. In order to be able to deal with your questions quickly and efficiently, I recommend that you repost your questions in the Developer Community, where there will be a dedicated engineer to provide you with a professional and effective response.

    Here is a link to the Developer Community: Developer Community.

    Have a nice day.

    Best regards,

    Lei

    0 comments No comments