@@ -12,6 +12,9 @@ internal sealed class WindowsPlatform : IPlatformServices
1212{
1313 public IReadOnlyList < MonitorInfo > GetMonitors ( )
1414 {
15+ // First, build a map of device name to device interface ID using EnumDisplayDevices
16+ var deviceIdMap = BuildDeviceIdMap ( ) ;
17+
1518 var monitors = new List < MonitorInfo > ( ) ;
1619 int index = 0 ;
1720
@@ -29,11 +32,15 @@ public IReadOnlyList<MonitorInfo> GetMonitors()
2932 info = Marshal . PtrToStructure < User32 . MONITORINFOEX > ( infoPtr ) ;
3033 var deviceName = info . GetDeviceName ( ) ;
3134
35+ // Get the full device interface ID for OBS monitor capture
36+ deviceIdMap . TryGetValue ( deviceName , out var deviceId ) ;
37+
3238 monitors . Add ( new MonitorInfo
3339 {
3440 Index = index ++ ,
3541 Handle = hMonitor ,
3642 DeviceName = deviceName ,
43+ DeviceId = deviceId ?? deviceName , // Fall back to device name if not found
3744 Name = deviceName ,
3845 X = info . rcMonitor . Left ,
3946 Y = info . rcMonitor . Top ,
@@ -56,6 +63,67 @@ public IReadOnlyList<MonitorInfo> GetMonitors()
5663 return monitors ;
5764 }
5865
66+ /// <summary>
67+ /// Builds a map of device names (e.g., \\.\DISPLAY1) to device interface IDs
68+ /// using EnumDisplayDevices with EDD_GET_DEVICE_INTERFACE_NAME flag.
69+ /// </summary>
70+ private static Dictionary < string , string > BuildDeviceIdMap ( )
71+ {
72+ var map = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
73+
74+ uint deviceIndex = 0 ;
75+ int displayDeviceSize = Marshal . SizeOf < User32 . DISPLAY_DEVICE > ( ) ;
76+ nint displayDevicePtr = Marshal . AllocHGlobal ( displayDeviceSize ) ;
77+
78+ try
79+ {
80+ while ( true )
81+ {
82+ // Initialize DISPLAY_DEVICE structure
83+ var displayDevice = new User32 . DISPLAY_DEVICE { cb = displayDeviceSize } ;
84+ Marshal . StructureToPtr ( displayDevice , displayDevicePtr , false ) ;
85+
86+ // Get display adapter info
87+ if ( User32 . EnumDisplayDevices ( 0 , deviceIndex , displayDevicePtr , 0 ) == 0 )
88+ break ;
89+
90+ displayDevice = Marshal . PtrToStructure < User32 . DISPLAY_DEVICE > ( displayDevicePtr ) ;
91+ var adapterName = displayDevice . DeviceName ; // e.g., \\.\DISPLAY1
92+
93+ // Now get the monitor attached to this adapter with the device interface name flag
94+ var monitorDevice = new User32 . DISPLAY_DEVICE { cb = displayDeviceSize } ;
95+ Marshal . StructureToPtr ( monitorDevice , displayDevicePtr , false ) ;
96+
97+ nint adapterNamePtr = Marshal . StringToHGlobalAnsi ( adapterName ) ;
98+ try
99+ {
100+ if ( User32 . EnumDisplayDevices ( adapterNamePtr , 0 , displayDevicePtr , User32 . EDD_GET_DEVICE_INTERFACE_NAME ) != 0 )
101+ {
102+ monitorDevice = Marshal . PtrToStructure < User32 . DISPLAY_DEVICE > ( displayDevicePtr ) ;
103+ var deviceId = monitorDevice . DeviceID ; // Full device interface ID
104+
105+ if ( ! string . IsNullOrEmpty ( deviceId ) )
106+ {
107+ map [ adapterName ] = deviceId ;
108+ }
109+ }
110+ }
111+ finally
112+ {
113+ Marshal . FreeHGlobal ( adapterNamePtr ) ;
114+ }
115+
116+ deviceIndex ++ ;
117+ }
118+ }
119+ finally
120+ {
121+ Marshal . FreeHGlobal ( displayDevicePtr ) ;
122+ }
123+
124+ return map ;
125+ }
126+
59127 public MonitorInfo ? GetPrimaryMonitor ( )
60128 {
61129 return GetMonitors ( ) . FirstOrDefault ( m => m . IsPrimary ) ;
0 commit comments