diff --git a/src/modules/powerdisplay/PowerDisplay.Lib.UnitTests/MonitorMatchingHelperTests.cs b/src/modules/powerdisplay/PowerDisplay.Lib.UnitTests/MonitorMatchingHelperTests.cs
index 8542dbe85d..ec2b6f6615 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib.UnitTests/MonitorMatchingHelperTests.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib.UnitTests/MonitorMatchingHelperTests.cs
@@ -2,282 +2,18 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using PowerDisplay.Common.Drivers.DDC;
using PowerDisplay.Common.Utils;
namespace PowerDisplay.UnitTests;
///
/// Unit tests for MonitorMatchingHelper class.
-/// Tests parsing logic for monitor numbers and device matching.
+/// Tests monitor key generation and matching logic.
///
[TestClass]
public class MonitorMatchingHelperTests
{
- [TestMethod]
- [DataRow(@"\\.\DISPLAY1", 1)]
- [DataRow(@"\\.\DISPLAY2", 2)]
- [DataRow(@"\\.\DISPLAY10", 10)]
- [DataRow(@"\\.\DISPLAY99", 99)]
- public void ParseDisplayNumber_ValidAdapterName_ReturnsCorrectNumber(string adapterName, int expected)
- {
- // Act
- var result = MonitorMatchingHelper.ParseDisplayNumber(adapterName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow("DISPLAY1", 1)]
- [DataRow("DISPLAY2", 2)]
- [DataRow("display3", 3)]
- [DataRow("Display10", 10)]
- public void ParseDisplayNumber_WithoutPrefix_ReturnsCorrectNumber(string adapterName, int expected)
- {
- // Act
- var result = MonitorMatchingHelper.ParseDisplayNumber(adapterName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow(null, 0)]
- [DataRow("", 0)]
- [DataRow(" ", 0)]
- public void ParseDisplayNumber_NullOrEmpty_ReturnsZero(string? adapterName, int expected)
- {
- // Act
- var result = MonitorMatchingHelper.ParseDisplayNumber(adapterName!);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow("MONITOR1", 0)]
- [DataRow("SCREEN1", 0)]
- [DataRow("InvalidName", 0)]
- [DataRow(@"\\.\MONITOR1", 0)]
- public void ParseDisplayNumber_NoDisplayKeyword_ReturnsZero(string adapterName, int expected)
- {
- // Act
- var result = MonitorMatchingHelper.ParseDisplayNumber(adapterName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow(@"\\.\DISPLAY", 0)]
- [DataRow("DISPLAY", 0)]
- [DataRow("DISPLAYabc", 0)]
- public void ParseDisplayNumber_NoNumberAfterDisplay_ReturnsZero(string adapterName, int expected)
- {
- // Act
- var result = MonitorMatchingHelper.ParseDisplayNumber(adapterName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\LGD05E5\4&abcdef12&0&UID12345_0", "4&abcdef12&0&UID12345")]
- [DataRow(@"DISPLAY\HPN360C\5&2c03a83e&0&UID262_1", "5&2c03a83e&0&UID262")]
- [DataRow(@"DISPLAY\DELL\4&other&0&UID999_12", "4&other&0&UID999")]
- [DataRow(@"DISPLAY\TEST\path_99", "path")]
- public void ExtractDeviceInstancePath_ValidInstanceNameWithSuffix_ReturnsPathWithoutSuffix(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\TEST\devicepath", "devicepath")]
- [DataRow(@"DISPLAY\TEST\path_abc", "path_abc")] // Non-digit suffix should not be removed
- [DataRow(@"DISPLAY\TEST\path_", "path_")] // Empty suffix should not be removed
- [DataRow(@"DISPLAY\TEST\path_0x1", "path_0x1")] // Mixed suffix should not be removed
- public void ExtractDeviceInstancePath_ValidInstanceNameWithoutSuffix_ReturnsPath(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- [TestMethod]
- [DataRow(null)]
- [DataRow("")]
- public void ExtractDeviceInstancePath_NullOrEmpty_ReturnsNull(string? instanceName)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName!);
-
- // Assert
- Assert.IsNull(result);
- }
-
- [TestMethod]
- [DataRow("NoBackslashInName")]
- [DataRow("SingleSegment")]
- public void ExtractDeviceInstancePath_NoBackslash_ReturnsNull(string instanceName)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.IsNull(result);
- }
-
- [TestMethod]
- [DataRow(@"DISPLAY\BOE0900\")]
- public void ExtractDeviceInstancePath_TrailingBackslash_ReturnsNull(string instanceName)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.IsNull(result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_MatchingDevice_ReturnsMonitorNumber()
- {
- // Arrange
- var instanceName = @"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY2",
- DeviceKey = @"\\?\DISPLAY#DELL#4&other&0&UID999#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(1, result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_SecondDevice_ReturnsCorrectNumber()
- {
- // Arrange
- var instanceName = @"DISPLAY\DELL\4&other&0&UID999_0";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY2",
- DeviceKey = @"\\?\DISPLAY#DELL#4&other&0&UID999#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(2, result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_NoMatchingDevice_ReturnsZero()
- {
- // Arrange
- var instanceName = @"DISPLAY\UNKNOWN\nonexistent_0";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(0, result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_EmptyDeviceList_ReturnsZero()
- {
- // Arrange
- var instanceName = @"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0";
- var displayDevices = new List();
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(0, result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_InvalidInstanceName_ReturnsZero()
- {
- // Arrange
- var instanceName = "InvalidInstanceName";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(0, result);
- }
-
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_CaseInsensitiveMatch_ReturnsMonitorNumber()
- {
- // Arrange
- var instanceName = @"DISPLAY\boe0900\4&10FD3AB1&0&uid265988_0";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(1, result);
- }
-
[TestMethod]
public void GetMonitorKey_WithHardwareId_ReturnsHardwareId()
{
@@ -347,183 +83,4 @@ public class MonitorMatchingHelperTests
// Assert
Assert.AreEqual(internalName, result);
}
-
- ///
- /// Tests that WMI instance index suffixes (_0, _1, _2, etc.) are correctly removed.
- /// WMI appends "_N" where N is the instance index to device instance paths.
- /// See: https://learn.microsoft.com/en-us/windows/win32/wmicoreprov/wmimonitorid
- ///
- [TestMethod]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_1", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_2", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_9", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_10", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_99", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_100", "4&10fd3ab1&0&UID265988")]
- [DataRow(@"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_999", "4&10fd3ab1&0&UID265988")]
- public void ExtractDeviceInstancePath_WmiInstanceIndexSuffix_RemovesSuffix(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- ///
- /// Tests real-world WMI InstanceName formats from various monitor manufacturers.
- /// These formats are documented at: https://learn.microsoft.com/en-us/windows/win32/wmicoreprov/wmimonitorid
- ///
- [TestMethod]
- [DataRow(@"DISPLAY\HPN360C\5&2c03a83e&0&UID262_0", "5&2c03a83e&0&UID262")] // HP monitor
- [DataRow(@"DISPLAY\HWP2868\5&3eb7fbc&0&UID16777472_0", "5&3eb7fbc&0&UID16777472")] // HP monitor
- [DataRow(@"DISPLAY\ENC2530\4&307c4481&0&UID224795_0", "4&307c4481&0&UID224795")] // EIZO monitor
- [DataRow(@"DISPLAY\DEL0000\0&00000000&0&UID0000_0", "0&00000000&0&UID0000")] // Dell monitor
- [DataRow(@"DISPLAY\SAM0382\4&38b6bd55&0&UID198147_0", "4&38b6bd55&0&UID198147")] // Samsung monitor
- [DataRow(@"DISPLAY\GSM5C6D\5&1234abcd&0&UID999_0", "5&1234abcd&0&UID999")] // LG monitor
- [DataRow(@"DISPLAY\ACI27F6\4&deadbeef&0&UID12345_0", "4&deadbeef&0&UID12345")] // ASUS monitor
- public void ExtractDeviceInstancePath_RealWorldFormats_ExtractsCorrectly(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- ///
- /// Tests that non-numeric suffixes are preserved (not removed).
- /// Only pure numeric suffixes after underscore should be removed.
- ///
- [TestMethod]
- [DataRow(@"DISPLAY\TEST\path_abc", "path_abc")]
- [DataRow(@"DISPLAY\TEST\path_0a", "path_0a")]
- [DataRow(@"DISPLAY\TEST\path_a0", "path_a0")]
- [DataRow(@"DISPLAY\TEST\path_0x1", "path_0x1")]
- [DataRow(@"DISPLAY\TEST\path_1x", "path_1x")]
- [DataRow(@"DISPLAY\TEST\path_", "path_")]
- [DataRow(@"DISPLAY\TEST\path_ ", "path_ ")]
- public void ExtractDeviceInstancePath_NonNumericSuffix_PreservesSuffix(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- ///
- /// Tests paths with multiple underscores - only the last numeric suffix should be removed.
- ///
- [TestMethod]
- [DataRow(@"DISPLAY\TEST\a_b_0", "a_b")]
- [DataRow(@"DISPLAY\TEST\a_b_c_1", "a_b_c")]
- [DataRow(@"DISPLAY\TEST\path_with_underscores_99", "path_with_underscores")]
- [DataRow(@"DISPLAY\TEST\UID_265988_0", "UID_265988")]
- public void ExtractDeviceInstancePath_MultipleUnderscores_RemovesOnlyLastNumericSuffix(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- ///
- /// Tests edge cases where underscore is at the beginning.
- ///
- [TestMethod]
- [DataRow(@"DISPLAY\TEST\_0", "_0")] // Underscore at position 0, should not be removed
- [DataRow(@"DISPLAY\TEST\_123", "_123")] // Underscore at position 0, should not be removed
- public void ExtractDeviceInstancePath_UnderscoreAtStart_PreservesPath(string instanceName, string expected)
- {
- // Act
- var result = MonitorMatchingHelper.ExtractDeviceInstancePath(instanceName);
-
- // Assert
- Assert.AreEqual(expected, result);
- }
-
- ///
- /// Tests that GetMonitorNumberFromWmiInstanceName works correctly with non-zero WMI instance indices.
- /// This verifies the fix for handling _1, _2, etc. suffixes instead of just _0.
- ///
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_WithInstanceIndex1_ReturnsMonitorNumber()
- {
- // Arrange - Using _1 suffix instead of _0
- var instanceName = @"DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_1";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID265988#{some-guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(1, result);
- }
-
- ///
- /// Tests matching with multi-digit WMI instance index.
- ///
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_WithInstanceIndex12_ReturnsMonitorNumber()
- {
- // Arrange - Using _12 suffix
- var instanceName = @"DISPLAY\DELL\4&abcdef&0&UID999_12";
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY3",
- DeviceKey = @"\\?\DISPLAY#DELL#4&abcdef&0&UID999#{guid}",
- },
- };
-
- // Act
- var result = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
-
- // Assert
- Assert.AreEqual(3, result);
- }
-
- ///
- /// Tests that multiple monitors with different WMI instance indices match correctly.
- /// Simulates a scenario with duplicate monitor models where WMI assigns different indices.
- ///
- [TestMethod]
- public void GetMonitorNumberFromWmiInstanceName_MultipleMonitorsSameModel_MatchesCorrectly()
- {
- // Arrange - Two monitors of same model but different UIDs
- var displayDevices = new List
- {
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY1",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID100#{guid}",
- },
- new DisplayDeviceInfo
- {
- AdapterName = @"\\.\DISPLAY2",
- DeviceKey = @"\\?\DISPLAY#BOE0900#4&10fd3ab1&0&UID200#{guid}",
- },
- };
-
- // Act & Assert - First monitor with _0 suffix
- var result1 = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(
- @"DISPLAY\BOE0900\4&10fd3ab1&0&UID100_0", displayDevices);
- Assert.AreEqual(1, result1);
-
- // Act & Assert - Second monitor with _0 suffix (different UID)
- var result2 = MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(
- @"DISPLAY\BOE0900\4&10fd3ab1&0&UID200_0", displayDevices);
- Assert.AreEqual(2, result2);
- }
}
diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/DdcCiNative.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/DdcCiNative.cs
index f78ad02216..ec5df906ff 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/DdcCiNative.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/DdcCiNative.cs
@@ -482,6 +482,7 @@ namespace PowerDisplay.Common.Drivers.DDC
}
// Get information for each path
+ // The path index corresponds to Windows Display Settings "Identify" number
for (int i = 0; i < pathCount; i++)
{
var path = paths[i];
@@ -497,7 +498,10 @@ namespace PowerDisplay.Common.Drivers.DDC
HardwareId = hardwareId ?? string.Empty,
AdapterId = path.TargetInfo.AdapterId,
TargetId = path.TargetInfo.Id,
+ MonitorNumber = i + 1, // 1-based, matches Windows Display Settings
};
+
+ Logger.LogDebug($"QueryDisplayConfig path[{i}]: HardwareId={hardwareId}, FriendlyName={friendlyName}, MonitorNumber={i + 1}");
}
}
}
@@ -610,5 +614,12 @@ namespace PowerDisplay.Common.Drivers.DDC
public LUID AdapterId { get; set; }
public uint TargetId { get; set; }
+
+ ///
+ /// Gets or sets the monitor number based on QueryDisplayConfig path index.
+ /// This matches the number shown in Windows Display Settings "Identify" feature.
+ /// 1-based index (paths[0] = 1, paths[1] = 2, etc.)
+ ///
+ public int MonitorNumber { get; set; }
}
}
diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/MonitorDiscoveryHelper.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/MonitorDiscoveryHelper.cs
index 3ae5fea609..e961980884 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/MonitorDiscoveryHelper.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/DDC/MonitorDiscoveryHelper.cs
@@ -220,7 +220,7 @@ namespace PowerDisplay.Common.Drivers.DDC
CommunicationMethod = "DDC/CI",
Manufacturer = ExtractManufacturer(name),
CapabilitiesStatus = "unknown",
- MonitorNumber = MonitorMatchingHelper.ParseDisplayNumber(adapterName),
+ MonitorNumber = GetMonitorNumber(matchedInfo),
Orientation = GetMonitorOrientation(adapterName),
};
@@ -307,6 +307,21 @@ namespace PowerDisplay.Common.Drivers.DDC
return firstWord.Length > 2 ? firstWord : "Unknown";
}
+ ///
+ /// Get monitor number from MonitorDisplayInfo (QueryDisplayConfig path index).
+ /// This matches the number shown in Windows Display Settings "Identify" feature.
+ ///
+ private int GetMonitorNumber(MonitorDisplayInfo? matchedInfo)
+ {
+ if (matchedInfo.HasValue && matchedInfo.Value.MonitorNumber > 0)
+ {
+ return matchedInfo.Value.MonitorNumber;
+ }
+
+ // No match found - return 0 (will not display number suffix)
+ return 0;
+ }
+
///
/// Get monitor orientation using EnumDisplaySettings
///
diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/WMI/WmiController.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/WMI/WmiController.cs
index 0cc82975b9..d616eb2312 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/WMI/WmiController.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Drivers/WMI/WmiController.cs
@@ -106,6 +106,34 @@ namespace PowerDisplay.Common.Drivers.WMI
return string.Empty;
}
+ ///
+ /// Get monitor number from MonitorDisplayInfo dictionary by matching HardwareId.
+ /// Uses QueryDisplayConfig path index which matches Windows Display Settings "Identify" feature.
+ ///
+ /// The hardware ID to match (e.g., "LEN4038", "BOE0900").
+ /// Dictionary of monitor display info from QueryDisplayConfig.
+ /// Monitor number (1-based) or 0 if not found.
+ private static int GetMonitorNumberFromDisplayInfo(string hardwareId, Dictionary monitorDisplayInfos)
+ {
+ if (string.IsNullOrEmpty(hardwareId) || monitorDisplayInfos == null || monitorDisplayInfos.Count == 0)
+ {
+ return 0;
+ }
+
+ foreach (var kvp in monitorDisplayInfos)
+ {
+ if (!string.IsNullOrEmpty(kvp.Value.HardwareId) &&
+ kvp.Value.HardwareId.Equals(hardwareId, StringComparison.OrdinalIgnoreCase))
+ {
+ Logger.LogDebug($"WMI: Matched HardwareId '{hardwareId}' to MonitorNumber {kvp.Value.MonitorNumber}");
+ return kvp.Value.MonitorNumber;
+ }
+ }
+
+ Logger.LogWarning($"WMI: Could not find MonitorNumber for HardwareId '{hardwareId}'");
+ return 0;
+ }
+
public string Name => "WMI Monitor Controller (WmiLight)";
///
@@ -309,8 +337,8 @@ namespace PowerDisplay.Common.Drivers.WMI
}
}
- // Pre-fetch display devices once to avoid repeated Win32 API calls in the loop
- var displayDevices = Drivers.DDC.DdcCiNative.GetAllDisplayDevices();
+ // Get MonitorDisplayInfo from QueryDisplayConfig - this provides the correct monitor numbers
+ var monitorDisplayInfos = Drivers.DDC.DdcCiNative.GetAllMonitorDisplayInfo();
// Create monitor objects for each supported brightness instance
foreach (var obj in brightnessResults)
@@ -330,6 +358,10 @@ namespace PowerDisplay.Common.Drivers.WMI
// e.g., "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0" -> "BOE0900"
var hardwareId = ExtractHardwareIdFromInstanceName(instanceName);
+ // Get MonitorNumber from QueryDisplayConfig by matching HardwareId
+ // This matches Windows Display Settings "Identify" feature
+ int monitorNumber = GetMonitorNumberFromDisplayInfo(hardwareId, monitorDisplayInfos);
+
var monitor = new Monitor
{
Id = $"WMI_{instanceName}",
@@ -345,7 +377,7 @@ namespace PowerDisplay.Common.Drivers.WMI
CommunicationMethod = "WMI",
Manufacturer = hardwareId.Length >= 3 ? hardwareId.Substring(0, 3) : "Internal",
SupportsColorTemperature = false,
- MonitorNumber = Utils.MonitorMatchingHelper.GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices),
+ MonitorNumber = monitorNumber,
};
monitors.Add(monitor);
diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Utils/MonitorMatchingHelper.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Utils/MonitorMatchingHelper.cs
index 9c63172fe8..2f99030002 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Utils/MonitorMatchingHelper.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Utils/MonitorMatchingHelper.cs
@@ -3,10 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
-using System.Linq;
-using ManagedCommon;
-using PowerDisplay.Common.Drivers.DDC;
using PowerDisplay.Common.Interfaces;
namespace PowerDisplay.Common.Utils
@@ -17,152 +13,6 @@ namespace PowerDisplay.Common.Utils
///
public static class MonitorMatchingHelper
{
- ///
- /// Get monitor number from WMI InstanceName by matching with EnumDisplayDevices.
- /// Returns 0 if matching fails.
- ///
- /// WMI InstanceName (e.g., "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0")
- /// Monitor number (1, 2, 3...) or 0 if not found
- public static int GetMonitorNumberFromWmiInstanceName(string instanceName)
- {
- // Fetch display devices and delegate to the overload
- var displayDevices = DdcCiNative.GetAllDisplayDevices();
- return GetMonitorNumberFromWmiInstanceName(instanceName, displayDevices);
- }
-
- ///
- /// Get monitor number from WMI InstanceName using pre-fetched display devices.
- /// Use this overload in loops to avoid repeated Win32 API calls.
- /// Returns 0 if matching fails.
- ///
- /// WMI InstanceName (e.g., "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0")
- /// Pre-fetched list of display devices from DdcCiNative.GetAllDisplayDevices()
- /// Monitor number (1, 2, 3...) or 0 if not found
- public static int GetMonitorNumberFromWmiInstanceName(string instanceName, IReadOnlyList displayDevices)
- {
- try
- {
- // Extract the device instance path for matching
- string? devicePath = ExtractDeviceInstancePath(instanceName);
- if (string.IsNullOrEmpty(devicePath))
- {
- Logger.LogWarning($"GetMonitorNumberFromWmiInstanceName: Failed to extract device path from '{instanceName}'");
- return 0;
- }
-
- if (displayDevices.Count == 0)
- {
- Logger.LogWarning("GetMonitorNumberFromWmiInstanceName: No display devices found from EnumDisplayDevices");
- return 0;
- }
-
- // Log all available devices for debugging
- Logger.LogDebug($"GetMonitorNumberFromWmiInstanceName: Searching for devicePath='{devicePath}' in {displayDevices.Count} devices");
- foreach (var d in displayDevices)
- {
- Logger.LogDebug($" - Adapter: {d.AdapterName}, DeviceKey: {d.DeviceKey}");
- }
-
- // Find matching device by checking if DeviceKey contains our device path
- foreach (var device in displayDevices)
- {
- if (!string.IsNullOrEmpty(device.DeviceKey) &&
- device.DeviceKey.Contains(devicePath, StringComparison.OrdinalIgnoreCase))
- {
- // Found match! Parse monitor number from AdapterName (e.g., "\\.\DISPLAY1" -> 1)
- int monitorNumber = ParseDisplayNumber(device.AdapterName);
- Logger.LogDebug($"GetMonitorNumberFromWmiInstanceName: Matched '{instanceName}' to DISPLAY{monitorNumber}");
- return monitorNumber;
- }
- }
-
- // No match found
- Logger.LogWarning($"GetMonitorNumberFromWmiInstanceName: No matching display device found for path '{devicePath}'");
- }
- catch (Exception ex)
- {
- Logger.LogError($"GetMonitorNumberFromWmiInstanceName: Exception while parsing '{instanceName}': {ex.Message}");
- }
-
- return 0;
- }
-
- ///
- /// Extract the device instance path from WMI InstanceName for matching.
- /// WMI InstanceName format: "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0"
- /// Returns: "4&10fd3ab1&0&UID265988" (the unique device path portion)
- ///
- /// WMI InstanceName
- /// Device instance path for matching, or null if extraction fails
- public static string? ExtractDeviceInstancePath(string instanceName)
- {
- if (string.IsNullOrEmpty(instanceName))
- {
- Logger.LogDebug("ExtractDeviceInstancePath: instanceName is null or empty");
- return null;
- }
-
- // Find the last backslash to get the instance path portion
- // e.g., "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0" -> "4&10fd3ab1&0&UID265988_0"
- int lastBackslash = instanceName.LastIndexOf('\\');
- if (lastBackslash < 0 || lastBackslash >= instanceName.Length - 1)
- {
- Logger.LogWarning($"ExtractDeviceInstancePath: Invalid format, no valid backslash found in '{instanceName}'");
- return null;
- }
-
- string instancePath = instanceName.Substring(lastBackslash + 1);
-
- // Remove trailing WMI instance index suffix (e.g., _0, _1, _12)
- // WMI appends "_N" where N is the instance index to device instance paths
- // See: https://learn.microsoft.com/en-us/windows/win32/wmicoreprov/wmimonitorid
- int lastUnderscore = instancePath.LastIndexOf('_');
- if (lastUnderscore > 0)
- {
- string suffix = instancePath[(lastUnderscore + 1)..];
- if (suffix.Length > 0 && suffix.All(char.IsDigit))
- {
- instancePath = instancePath[..lastUnderscore];
- }
- }
-
- if (string.IsNullOrEmpty(instancePath))
- {
- Logger.LogWarning($"ExtractDeviceInstancePath: Extracted path is empty from '{instanceName}'");
- return null;
- }
-
- return instancePath;
- }
-
- ///
- /// Parse display number from adapter name (e.g., "\\.\DISPLAY1" -> 1)
- ///
- /// Adapter name from EnumDisplayDevices
- /// Display number or 0 if parsing fails
- public static int ParseDisplayNumber(string adapterName)
- {
- if (string.IsNullOrEmpty(adapterName))
- {
- return 0;
- }
-
- // Find "DISPLAY" and extract the number after it
- int index = adapterName.IndexOf("DISPLAY", StringComparison.OrdinalIgnoreCase);
- if (index >= 0)
- {
- string numberPart = adapterName.Substring(index + 7);
- string numberStr = new string(numberPart.TakeWhile(char.IsDigit).ToArray());
-
- if (int.TryParse(numberStr, out int number))
- {
- return number;
- }
- }
-
- return 0;
- }
-
///
/// Generate a unique key for monitor matching based on hardware ID and internal name.
/// Uses HardwareId if available; otherwise falls back to Id (InternalName) or Name.