// Copyright (c) Microsoft Corporation // 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; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using ManagedCommon; using PowerDisplay.Common.Interfaces; using PowerDisplay.Common.Models; using WmiLight; using Monitor = PowerDisplay.Common.Models.Monitor; namespace PowerDisplay.Common.Drivers.WMI { /// /// WMI monitor controller for controlling internal laptop displays. /// Rewritten to use WmiLight library for Native AOT compatibility. /// public partial class WmiController : IMonitorController, IDisposable { private const string WmiNamespace = @"root\WMI"; private const string BrightnessQueryClass = "WmiMonitorBrightness"; private const string BrightnessMethodClass = "WmiMonitorBrightnessMethods"; private const string MonitorIdClass = "WmiMonitorID"; // Common WMI error codes for classification private const int WbemENotFound = unchecked((int)0x80041002); private const int WbemEAccessDenied = unchecked((int)0x80041003); private const int WbemEProviderFailure = unchecked((int)0x80041004); private const int WbemEInvalidQuery = unchecked((int)0x80041017); private const int WmiFeatureNotSupported = 0x1068; private bool _disposed; /// /// Classifies WMI exceptions into user-friendly error messages. /// private static MonitorOperationResult ClassifyWmiError(WmiException ex, string operation) { var hresult = ex.HResult; return hresult switch { WbemENotFound => MonitorOperationResult.Failure($"WMI class not found during {operation}. This feature may not be supported on your system.", hresult), WbemEAccessDenied => MonitorOperationResult.Failure($"Access denied during {operation}. Administrator privileges may be required.", hresult), WbemEProviderFailure => MonitorOperationResult.Failure($"WMI provider failure during {operation}. The display driver may not support this feature.", hresult), WbemEInvalidQuery => MonitorOperationResult.Failure($"Invalid WMI query during {operation}. This is likely a bug.", hresult), WmiFeatureNotSupported => MonitorOperationResult.Failure($"WMI brightness control not supported on this system during {operation}.", hresult), _ => MonitorOperationResult.Failure($"WMI error during {operation}: {ex.Message}", hresult), }; } /// /// Determines if the WMI error is expected for systems without WMI brightness support. /// private static bool IsExpectedUnsupportedError(WmiException ex) { return ex.HResult == WmiFeatureNotSupported || ex.HResult == WbemENotFound; } /// /// Escape special characters in WMI query strings. /// WMI requires backslashes and single quotes to be escaped in WHERE clauses. /// See: https://learn.microsoft.com/en-us/windows/win32/wmisdk/wql-sql-for-wmi /// /// The string value to escape. /// The escaped string safe for use in WMI queries. private static string EscapeWmiString(string value) { if (string.IsNullOrEmpty(value)) { return value; } // WMI requires backslashes and single quotes to be escaped in WHERE clauses // Backslash must be escaped first to avoid double-escaping the quote's backslash return value.Replace("\\", "\\\\").Replace("'", "\\'"); } /// /// Extract hardware ID from WMI InstanceName. /// InstanceName format: "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0" /// Returns the second segment (e.g., "BOE0900") which is the manufacturer+product code. /// /// The WMI InstanceName. /// The hardware ID extracted from the InstanceName, or empty string if extraction fails. private static string ExtractHardwareIdFromInstanceName(string instanceName) { if (string.IsNullOrEmpty(instanceName)) { return string.Empty; } // Split by backslash: ["DISPLAY", "BOE0900", "4&10fd3ab1&0&UID265988_0"] var parts = instanceName.Split('\\'); if (parts.Length >= 2 && !string.IsNullOrEmpty(parts[1])) { // Return the second part (e.g., "BOE0900") return parts[1]; } 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)"; /// /// Check if the specified monitor can be controlled. /// Verifies the specific monitor exists in WMI by filtering on InstanceName. /// public async Task CanControlMonitorAsync(Monitor monitor, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(monitor); if (monitor.CommunicationMethod != "WMI") { return false; } // If no InstanceName, we can't verify the specific monitor if (string.IsNullOrEmpty(monitor.InstanceName)) { return false; } return await Task.Run( () => { try { using var connection = new WmiConnection(WmiNamespace); // Filter by InstanceName to verify this specific monitor exists var escapedInstanceName = EscapeWmiString(monitor.InstanceName); var query = $"SELECT InstanceName FROM {BrightnessQueryClass} WHERE InstanceName = '{escapedInstanceName}'"; var results = connection.CreateQuery(query).ToList(); return results.Count > 0; } catch (Exception ex) { Logger.LogWarning($"WMI CanControlMonitor check failed for '{monitor.InstanceName}': {ex.Message}"); return false; } }, cancellationToken); } /// /// Get monitor brightness /// public async Task GetBrightnessAsync(Monitor monitor, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(monitor); return await Task.Run( () => { try { using var connection = new WmiConnection(WmiNamespace); // Filter by InstanceName to target the specific monitor var escapedInstanceName = EscapeWmiString(monitor.InstanceName); var query = $"SELECT CurrentBrightness FROM {BrightnessQueryClass} WHERE InstanceName = '{escapedInstanceName}'"; var results = connection.CreateQuery(query); foreach (var obj in results) { var currentBrightness = obj.GetPropertyValue("CurrentBrightness"); return new BrightnessInfo(currentBrightness, 0, 100); } // No match found - monitor may have been disconnected Logger.LogDebug($"WMI GetBrightness: No monitor found with InstanceName '{monitor.InstanceName}'"); } catch (WmiException ex) { Logger.LogWarning($"WMI GetBrightness failed: {ex.Message} (HResult: 0x{ex.HResult:X})"); } catch (Exception ex) { Logger.LogWarning($"WMI GetBrightness failed: {ex.Message}"); } return BrightnessInfo.Invalid; }, cancellationToken); } /// /// Set monitor brightness /// public async Task SetBrightnessAsync(Monitor monitor, int brightness, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(monitor); // Validate brightness range brightness = Math.Clamp(brightness, 0, 100); return await Task.Run( () => { try { using var connection = new WmiConnection(WmiNamespace); // Filter by InstanceName to target the specific monitor var escapedInstanceName = EscapeWmiString(monitor.InstanceName); var query = $"SELECT * FROM {BrightnessMethodClass} WHERE InstanceName = '{escapedInstanceName}'"; var results = connection.CreateQuery(query); foreach (var obj in results) { // Call WmiSetBrightness method // Parameters: Timeout (uint32), Brightness (uint8) // Note: WmiLight requires string values for method parameters using (WmiMethod method = obj.GetMethod("WmiSetBrightness")) using (WmiMethodParameters inParams = method.CreateInParameters()) { inParams.SetPropertyValue("Timeout", "0"); inParams.SetPropertyValue("Brightness", brightness.ToString(CultureInfo.InvariantCulture)); uint result = obj.ExecuteMethod( method, inParams, out WmiMethodParameters outParams); // Check return value (0 indicates success) if (result == 0) { return MonitorOperationResult.Success(); } else { return MonitorOperationResult.Failure($"WMI method returned error code: {result}", (int)result); } } } // No match found - monitor may have been disconnected Logger.LogWarning($"WMI SetBrightness: No monitor found with InstanceName '{monitor.InstanceName}'"); return MonitorOperationResult.Failure($"No WMI brightness method found for monitor '{monitor.InstanceName}'"); } catch (UnauthorizedAccessException) { return MonitorOperationResult.Failure("Access denied. Administrator privileges may be required.", 5); } catch (WmiException ex) { return ClassifyWmiError(ex, "SetBrightness"); } catch (Exception ex) { return MonitorOperationResult.Failure($"Unexpected error during SetBrightness: {ex.Message}"); } }, cancellationToken); } /// /// Discover supported monitors /// public async Task> DiscoverMonitorsAsync(CancellationToken cancellationToken = default) { return await Task.Run( () => { var monitors = new List(); try { using var connection = new WmiConnection(WmiNamespace); // First check if WMI brightness support is available var brightnessQuery = $"SELECT * FROM {BrightnessQueryClass}"; var brightnessResults = connection.CreateQuery(brightnessQuery).ToList(); if (brightnessResults.Count == 0) { return monitors; } // Get monitor information var idQuery = $"SELECT * FROM {MonitorIdClass}"; var idResults = connection.CreateQuery(idQuery).ToList(); var monitorInfos = new Dictionary(); foreach (var obj in idResults) { try { var instanceName = obj.GetPropertyValue("InstanceName") ?? string.Empty; var userFriendlyName = GetUserFriendlyName(obj) ?? "Internal Display"; if (!string.IsNullOrEmpty(instanceName)) { monitorInfos[instanceName] = (userFriendlyName, instanceName); } } catch (Exception ex) { // Skip problematic entries Logger.LogDebug($"Failed to parse WMI monitor info: {ex.Message}"); } } // 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) { try { var instanceName = obj.GetPropertyValue("InstanceName") ?? string.Empty; var currentBrightness = obj.GetPropertyValue("CurrentBrightness"); var name = "Internal Display"; if (monitorInfos.TryGetValue(instanceName, out var info)) { name = info.Name; } // Extract EdidId from InstanceName // e.g., "DISPLAY\BOE0900\4&10fd3ab1&0&UID265988_0" -> "BOE0900" var edidId = ExtractHardwareIdFromInstanceName(instanceName); // Get MonitorNumber from QueryDisplayConfig by matching EdidId // This matches Windows Display Settings "Identify" feature int monitorNumber = GetMonitorNumberFromDisplayInfo(edidId, monitorDisplayInfos); // Generate unique monitor Id: "WMI_{EdidId}_{MonitorNumber}" string monitorId = !string.IsNullOrEmpty(edidId) ? $"WMI_{edidId}_{monitorNumber}" : $"WMI_Unknown_{monitorNumber}"; var monitor = new Monitor { Id = monitorId, Name = name, CurrentBrightness = currentBrightness, MinBrightness = 0, MaxBrightness = 100, IsAvailable = true, InstanceName = instanceName, Capabilities = MonitorCapabilities.Brightness | MonitorCapabilities.Wmi, ConnectionType = "Internal", CommunicationMethod = "WMI", Manufacturer = edidId.Length >= 3 ? edidId.Substring(0, 3) : "Internal", SupportsColorTemperature = false, MonitorNumber = monitorNumber, }; monitors.Add(monitor); } catch (Exception ex) { // Skip problematic monitors Logger.LogWarning($"Failed to create monitor from WMI data: {ex.Message}"); } } } catch (WmiException ex) { // Return empty list instead of throwing exception Logger.LogError($"WMI DiscoverMonitors failed: {ex.Message} (HResult: 0x{ex.HResult:X})"); } catch (Exception ex) { Logger.LogError($"WMI DiscoverMonitors failed: {ex.Message}"); } return monitors; }, cancellationToken); } /// /// Get user-friendly name from WMI object. /// WmiMonitorID returns UserFriendlyName as a fixed-size uint16 array buffer, /// with UserFriendlyNameLength indicating the actual character count. /// private static string? GetUserFriendlyName(WmiObject monitorObject) { try { var userFriendlyName = monitorObject.GetPropertyValue("UserFriendlyName"); var nameLength = monitorObject.GetPropertyValue("UserFriendlyNameLength"); if (userFriendlyName != null && nameLength > 0 && nameLength <= userFriendlyName.Length) { // Use UserFriendlyNameLength to extract only valid characters var chars = userFriendlyName .Take(nameLength) .Select(c => (char)c) .ToArray(); if (chars.Length > 0) { return new string(chars).Trim(); } } } catch (Exception ex) { Logger.LogDebug($"Failed to parse UserFriendlyName: {ex.Message}"); } return null; } /// /// Check WMI service availability /// public static bool IsWmiAvailable() { try { using var connection = new WmiConnection(WmiNamespace); var query = $"SELECT * FROM {BrightnessQueryClass}"; var results = connection.CreateQuery(query).ToList(); return results.Count > 0; } catch (WmiException ex) when (IsExpectedUnsupportedError(ex)) { // Expected on systems without WMI brightness support (desktops, some laptops) Logger.LogInfo("WMI brightness control not supported on this system (expected for desktops)"); return false; } catch (WmiException ex) { // Unexpected WMI error - log with details for debugging Logger.LogWarning($"WMI availability check failed: {ex.Message} (HResult: 0x{ex.HResult:X})"); return false; } catch (Exception ex) { // Unexpected non-WMI error Logger.LogDebug($"WMI availability check failed: {ex.Message}"); return false; } } // Extended features not supported by WMI public Task SetContrastAsync(Monitor monitor, int contrast, CancellationToken cancellationToken = default) { return Task.FromResult(MonitorOperationResult.Failure("Contrast control not supported via WMI")); } public Task SetVolumeAsync(Monitor monitor, int volume, CancellationToken cancellationToken = default) { return Task.FromResult(MonitorOperationResult.Failure("Volume control not supported via WMI")); } public Task GetColorTemperatureAsync(Monitor monitor, CancellationToken cancellationToken = default) { return Task.FromResult(BrightnessInfo.Invalid); } public Task SetColorTemperatureAsync(Monitor monitor, int colorTemperature, CancellationToken cancellationToken = default) { return Task.FromResult(MonitorOperationResult.Failure("Color temperature control not supported via WMI")); } public Task GetInputSourceAsync(Monitor monitor, CancellationToken cancellationToken = default) { // Input source switching not supported for internal displays return Task.FromResult(BrightnessInfo.Invalid); } public Task SetInputSourceAsync(Monitor monitor, int inputSource, CancellationToken cancellationToken = default) { // Input source switching not supported for internal displays return Task.FromResult(MonitorOperationResult.Failure("Input source switching not supported via WMI")); } public Task GetCapabilitiesStringAsync(Monitor monitor, CancellationToken cancellationToken = default) { return Task.FromResult(string.Empty); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed && disposing) { // WmiLight objects are automatically cleaned up, no specific cleanup needed here _disposed = true; } } } }