I want to change which monitor is the main one using Windows API functions in my C# program. When I run my code, the screen flickers for a moment but the primary display doesn’t actually change. I think there might be something wrong with how I’m calling the API functions.
public const int DISPLAY_ORIENT = 0x00000001;
public const int PAPER_FORMAT = 0x00000002;
public const int PAPER_HEIGHT = 0x00000004;
public const int PAPER_WIDTH = 0x00000008;
public const int DISPLAY_SCALE = 0x00000010;
public const int SCREEN_POSITION = 0x00000020;
public const int SCREEN_WIDTH = 0x00080000;
public const int SCREEN_HEIGHT = 0x00100000;
public const int REFRESH_RATE = 0x00400000;
public const int BITS_PER_PIXEL = 0x00040000;
public const int CURRENT_SETTINGS = -1;
public const int UPDATE_REGISTRY = 0x01;
public const int TEST_MODE = 0x02;
public const int MAKE_PRIMARY = 0x00000010;
public const long CHANGE_OK = 0;
public const long CHANGE_RESTART_NEEDED = 1;
public const long CHANGE_ERROR = -1;
public const long BAD_MODE = -2;
public const long NOT_UPDATED = -3;
public static void MakePrimaryDisplay(Screen targetScreen)
{
DISPLAY_DEVICE device = new DISPLAY_DEVICE();
DEVMODE mode = new DEVMODE();
device.cb = Marshal.SizeOf(device);
uint displayIndex = 1;
WinAPI.EnumDisplayDevices(null, displayIndex, ref device, 0);
WinAPI.EnumDisplaySettings(device.DeviceName, 0, ref mode);
mode.dmPelsWidth = 1920;
mode.dmPelsHeight = 1080;
mode.dmPositionX = targetScreen.Bounds.Left;
mode.dmFields = SCREEN_POSITION | SCREEN_WIDTH | SCREEN_HEIGHT;
WinAPI.ChangeDisplaySettingsEx(device.DeviceName, ref mode, IntPtr.Zero, MAKE_PRIMARY, IntPtr.Zero);
}
I’m calling it like this:
MakePrimaryDisplay(Screen.AllScreens[0])
What could be going wrong here?
The flickering indicates that your API calls are functioning, but there’s a logical issue. You’re setting displayIndex = 1 while calling MakePrimaryDisplay(Screen.AllScreens[0]), which targets the first screen but modifies a different display. In addition, using EnumDisplaySettings with index 0 instead of CURRENT_SETTINGS can result in outdated display information. I encountered a similar problem when creating a multi-monitor application. To resolve this, consider obtaining the device name from your target screen or iterating through all devices to align with your target screen’s bounds. Changing the primary display often requires applying settings to all displays in the correct sequence, not solely the one you intend to change.
you’re not settin the position right to make it primary. the main display needs dmPositionX and dmPositionY both at 0,0. don’t forget to update your other monitors’ positions or they’ll overlap. set mode.dmPositionX = 0; mode.dmPositionY = 0; and use UPDATE_REGISTRY | MAKE_PRIMARY flags together.
Your problem lies in hardcoding displayIndex = 1 regardless of the screen you want to target. I faced a similar challenge; it’s crucial to iterate through all displays to retrieve the actual device name for your chosen screen. The flickering indicates that while the API call is being executed, you’re affecting the wrong display device. Utilize Screen.DeviceName to obtain the correct device name rather than relying on indices. Additionally, ensure to combine the UPDATE_REGISTRY and MAKE_PRIMARY flags in your call to ChangeDisplaySettingsEx. If you skip the registry update, your changes won’t persist. Simply using position coordinates isn’t sufficient for determining which monitor to set as primary; access the correct device name mapping as well.
This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.