Connecting an External Monitor to a Laptop and Making it the Primary Display in Windows Programmatically
In today's world, where dual-monitor setups have become increasingly popular, it is essential to know how to connect and configure an external monitor to a laptop. This article will guide you through the process of making an external monitor the primary display in Windows programmatically. We will cover key concepts, provide detailed explanations, and include code blocks to help you achieve this.
Connecting the External Monitor
First, you need to connect the external monitor to your laptop. This can be done using an HDMI, DisplayPort, or VGA cable, depending on the available ports on both devices. Once connected, Windows should automatically detect the monitor and display the "Second screen" notification.
Choosing "Extend displays" and Setting the External Monitor as the Main Display
To set the external monitor as the primary display, follow these steps:
- Right-click on the desktop and select "Display settings"
- Under the "Select and rearrange displays" section, identify the monitor you want to set as the primary display
- Click on the monitor and check the "Make this my main display" checkbox
- Click "Apply" to save the changes
Making the External Monitor the Primary Display Programmatically
To make the external monitor the primary display programmatically, you can use the following code snippet in C#:
using System;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
SetPrimaryMonitor(1);
}
[DllImport("user32.dll")]
static extern int SetDisplayConfig(uint numPathArrayElements, IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, uint flags);
static void SetPrimaryMonitor(int monitorIndex)
{
const uint SET_DISPLAY_CONFIG_PATH_AND_MODE_INVALID = 0;
const uint SDC_TOPOLOGY_INTERNAL = 0;
const uint SDC_TOPOLOGY_CLONE = 1;
const uint SDC_TOPOLOGY_EXTEND = 2;
const uint SDC_CHANGE_FORCE_LAYERED = 0x20000000;
int errorCode = SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SDC_TOPOLOGY_EXTEND | SDC_CHANGE_FORCE_LAYERED);
if (errorCode != 0)
{
Console.WriteLine("Error setting display configuration: {0}", errorCode);
return;
}
// Get the current display configuration
uint numPathArrayElements;
uint numModeArrayElements;
errorCode = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, out numPathArrayElements, out numModeArrayElements);
if (errorCode != 0)
{
Console.WriteLine("Error getting display configuration buffer sizes: {0}", errorCode);
return;
}
IntPtr pathArray = Marshal.AllocHGlobal((int)(numPathArrayElements * Marshal.SizeOf(typeof(DISPLAYCONFIG_PATH_INFO))));
IntPtr modeArray = Marshal.AllocHGlobal((int)(numModeArrayElements * Marshal.SizeOf(typeof(DISPLAYCONFIG_MODE_INFO))));
errorCode = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, out numPathArrayElements, pathArray, out numModeArrayElements, modeArray, IntPtr.Zero);
if (errorCode != 0)
{
Console.WriteLine("Error querying display configuration: {0}", errorCode);
return;
}
// Set the desired monitor as the primary display
DISPLAYCONFIG_PATH_INFO[] pathInfoArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
Marshal.PtrToStructure(pathArray, pathInfoArray);
DISPLAYCONFIG_PATH_INFO pathInfo = pathInfoArray[monitorIndex];
pathInfo.targetInfo.id = pathInfo.sourceInfo.id;
pathInfo.targetInfo.flags = DISPLAYCONFIG\_TARGET\_FLAGS.DISPLAYCONFIG\_TARGET\_FORCE\_VCP\_TO\_DMT;
Marshal.StructureToPtr(pathInfo, pathArray, false);
errorCode = SetDisplayConfig(numPathArrayElements, pathArray, numModeArrayElements, modeArray, 0);
if (errorCode != 0)
{
Console.WriteLine("Error setting display configuration: {0}", errorCode);
}
Marshal.FreeHGlobal(pathArray);
Marshal.FreeHGlobal(modeArray);
}
[StructLayout(LayoutKind.Sequential)]
struct DISPLAYCONFIG\_PATH\_INFO
{
public DISPLAYCONFIG\_PATH\_SOURCE\_INFO source;
public DISPLAYCONFIG\_PATH\_TARGET\_INFO target;
public DISPLAYCONFIG\_PATH\_FLAGS flags;
public uint monitorDevice;
}
[StructLayout(LayoutKind.Sequential)]
struct DISPLAYCONFIG\_PATH\_SOURCE\_INFO
{
public IntPtr adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG\_ROTATION rotation;
public DISPLAYCONFIG\_SCALING scaling;
public DISPLAYCONFIG\_REFRESH\_RATE refreshRate;
public DISPLAYCONFIG\_PRIMARY\_DEVICE primaryDevice;
}
[StructLayout(LayoutKind.Sequential)]
struct DISPLAYCONFIG\_PATH\_TARGET\_INFO
{
public IntPtr adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG\_ROTATION rotation;
public DISPLAYCONFIG\_SCALING scaling;
public DISPLAYCONFIG\_REFRESH\_RATE refreshRate;
public DISPLAYCONFIG\_PRIMARY\_DEVICE primaryDevice;
}
[Flags]
enum DISPLAYCONFIG\_PATH\_FLAGS
{
DISPLAYCONFIG\_PATH\_FLAG\_NONE = 0,
DISPLAYCONFIG\_PATH\_FLAG\_ATTACHED\_TO\_DESKTOP = 1,
DISPLAYCONFIG\_PATH\_FLAG\_ACTIVE = 2,
DISPLAYCONFIG\_PATH\_FLAG\_FAILOVER = 4,
DISPLAYCONFIG\_PATH\_FLAG\_PATH\_IS\_EXTERNAL = 8,
DISPLAYCONFIG\_PATH\_FLAG\_PRIMARY\_DEVICE = 16,
DISPLAYCONFIG\_PATH\_FLAG\_UNIQUE\_ID = 32,
DISPLAYCONFIG\_PATH\_FLAG\_VALID\_PATH\_SOURCE\_FLAG = 128,
DISPLAYCONFIG\_PATH\_FLAG\_VALID\_PATH\_TARGET\_FLAG = 256,
DISPLAYCONFIG\_PATH\_FLAG\_VALID\_PATH\_INFO\_FLAG = 512,
DISPLAYCONFIG\_PATH\_FLAG\_VALID\_MODE\_INFO\_FLAG = 1024,
DISPLAYCONFIG\_PATH\_FLAG\_VALIDATED = 2048,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_ICD\_SDR = 4096,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_ICD\_HDR = 8192,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_GPU\_SDR = 16384,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_GPU\_HDR = 32768,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_DYNAMIC\_RANGE\_SDR = 65536,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_DYNAMIC\_RANGE\_HDR = 131072,
DISPLAYCONFIG\_PATH\_FLAG\_FORCE\_VCP\_TO\_DMT = 262144
}
[Flags]
enum DISPLAYCONFIG\_TARGET\_FLAGS
{
DISPLAYCONFIG\_TARGET\_FLAG\_NONE = 0,
DISPLAYCONFIG\_TARGET\_FLAG\_FORCE\_VCP\_TO\_DMT = 1,
DISPLAYCONFIG\_TARGET\_FLAG\_FORCE\_DMT\_TO\_VCP = 2,
DISPLAYCONFIG\_TARGET\_FLAG\_FORCE\_DMT\_TO\_DMT = 3,
DISPLAYCONFIG\_TARGET\_FLAG\_FORCE\_VCP\_TO\_VCP = 4
}
const uint QDC\_ONLY\_ACTIVE\_PATHS = 1;
[DllImport("user32.dll")]
static extern int GetDisplayConfigBufferSizes(uint flags, out uint numPathArrayElements, out uint numModeArrayElements);
[DllImport("user32.dll")]
static extern int QueryDisplayConfig(uint flags, out uint numPathArrayElements, IntPtr pathArray, out uint numModeArrayElements, IntPtr modeArray, IntPtr currentModeInfo);
}
In this article, we have discussed how to connect an external monitor to a laptop, choose "Extend displays," and set the external monitor as the primary display. We have also provided a C# code snippet that demonstrates how to make the external monitor the primary display programmatically. This information should help you configure your dual-monitor setup according to your preferences.
References
- Microsoft Docs: SetDisplayConfig function
- Microsoft Docs: QueryDisplayConfig function
- Microsoft Docs: DISPLAYCONFIG\_PATH\_INFO structure
- Microsoft Docs: DISPLAYCONFIG\_PATH\_SOURCE\_INFO structure
- Microsoft Docs: DISPLAYCONFIG\_PATH\_TARGET\_INFO structure