Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 57 additions & 79 deletions TimVer/Helpers/VideoHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,85 +7,60 @@ namespace TimVer.Helpers;
/// </summary>
internal static class VideoHelpers
{
#region Get list of video controllers
#region Get all video controllers with full info
/// <summary>
/// Gets the DeviceID for each video controller.
/// Gets all video controllers with their complete information.
/// </summary>
/// <returns>A List of controller DeviceID's</returns>
internal static List<string?> GetGPUList()
/// <returns>A list of dictionaries containing video controller information</returns>
internal static List<Dictionary<string, string>> GetAllVideoControllers()
{
const string scope = @"\\.\root\CIMV2";
const string dialect = "WQL";
const string query = "SELECT DeviceID From Win32_VideoController";

try
{
List<string?> devices = [];
using CimSession cimSession = CimSession.Create(null);
devices.AddRange(cimSession.QueryInstances(scope, dialect, query)
.Select(drive => drive.CimInstanceProperties["DeviceID"]?.Value!.ToString()));
return devices;
}
catch (Exception ex)
{
_log.Error(ex, "Win32_VideoController call failed.");
return [];
}
}
#endregion Get list of video controllers

#region Get WMI info for video controller(s)
/// <summary>
/// Get CIM value from Win32_VideoController
/// </summary>
/// <param name="controller">DeviceID of the controller</param>
/// <returns>Video controller information as a Dictionary</returns>
public static Dictionary<string, string> GetVideoInfo(string controller)
{
const string scope = @"\\.\root\CIMV2";
const string dialect = "WQL";
string query = "SELECT DeviceID, Name, Description, CurrentHorizontalResolution, CurrentVerticalResolution, " +
"CurrentRefreshRate, CurrentBitsPerPixel, VideoProcessor, " +
"AdapterRam, CurrentNumberOfColors " +
$"From Win32_VideoController Where DeviceID = '{controller}'";
const string query = "SELECT DeviceID, Name, Description, CurrentHorizontalResolution, CurrentVerticalResolution, " +
"CurrentRefreshRate, CurrentBitsPerPixel, VideoProcessor, " +
"AdapterRam, CurrentNumberOfColors " +
"FROM Win32_VideoController";
try
{
List<Dictionary<string, string>> controllers = [];
using CimSession cimSession = CimSession.Create(null);
IEnumerable<CimInstance> instance = cimSession.QueryInstances(scope, dialect, query);
Stopwatch sw = Stopwatch.StartNew();
Dictionary<string, string> info = instance
.Select(gpu => new Dictionary<string, string>

var instances = cimSession.QueryInstances(scope, dialect, query);

int displayCount = GetDisplayCount();

foreach (var gpu in instances)
{
Dictionary<string, string> controllerInfo = new()
{
[GetStringResource("GraphicsInfo_GraphicsAdapter")] = CimStringProperty(gpu, "Name"),
[GetStringResource("GraphicsInfo_AdapterType")] = CimStringProperty(gpu, "VideoProcessor"),
[GetStringResource("GraphicsInfo_Description")] = CimStringProperty(gpu, "Description"),
[GetStringResource("GraphicsInfo_DeviceID")] = CimStringProperty(gpu, "DeviceID"),
[GetStringResource("GraphicsInfo_CurrentResolution")] = FormatResolution(gpu),
[GetStringResource("GraphicsInfo_CurrentRefreshRate")] = FormatCurrentRefresh(gpu),
//[GetStringResource("GraphicsInfo_AdapterRAM")] = FormatAdapterRamInfo(gpu),
[GetStringResource("GraphicsInfo_AdapterRAM")] = FormatAdapterRamInfo(gpu),
[GetStringResource("GraphicsInfo_BitsPerPixel")] = CimStringProperty(gpu, "CurrentBitsPerPixel"),
[GetStringResource("GraphicsInfo_NumberOfColors")] = FormatColorsInfo(gpu),
[GetStringResource("GraphicsInfo_NumberOfDisplays")] = GetDisplayCount()
.ToString(CultureInfo.InvariantCulture),
})
.FirstOrDefault()!;
[GetStringResource("GraphicsInfo_NumberOfDisplays")] = displayCount.ToString(CultureInfo.InvariantCulture),
};
controllers.Add(controllerInfo);
_log.Debug($"Found video controller: {controllerInfo[GetStringResource("GraphicsInfo_GraphicsAdapter")]} (Device ID is " +
$"{controllerInfo[GetStringResource("GraphicsInfo_DeviceID")]})");
}

sw.Stop();
_log.Debug($"Getting video controller info took {sw.Elapsed.TotalMilliseconds:N2} ms");
return info ?? new Dictionary<string, string>
{
[GetStringResource("MsgText_NotAvailable")] = string.Empty
};
_log.Debug($"Getting all video controller info took {sw.Elapsed.TotalMilliseconds:N2} ms. Found {controllers.Count} controller(s)");
return controllers;
}
catch (Exception ex)
{
_log.Error(ex, "Win32_VideoController call failed.");
return new Dictionary<string, string>
{
[GetStringResource("MsgText_NotAvailable")] = string.Empty
};
_log.Error(ex, $"Win32_VideoController call failed. {ex.Message} - {ex.InnerException}");
return [];
}
}
#endregion Get WMI info for video controller(s)
#endregion Get all video controllers with full info

#region Get WMI information formatted as string
/// <summary>
Expand All @@ -99,7 +74,12 @@ private static string CimStringProperty(CimInstance instance, string name)
if (instance.CimInstanceProperties[name] == null)
{
_log.Debug($"Value for {name} was null");
return "Not Available";
return GetStringResource("MsgText_NotAvailable");
}
if (instance.CimInstanceProperties[name].Value == null)
{
_log.Debug($"Value for {name} was null");
return GetStringResource("MsgText_NotAvailable");
}
return instance.CimInstanceProperties[name].Value.ToString()!;
}
Expand All @@ -113,8 +93,13 @@ private static string CimStringProperty(CimInstance instance, string name)
/// <returns>A formatted string.</returns>
private static string FormatCurrentRefresh(CimInstance instance)
{
string? rate = instance.CimInstanceProperties["CurrentRefreshRate"].Value.ToString();
return $"{rate} Hz";
var rateValue = instance.CimInstanceProperties["CurrentRefreshRate"]?.Value;
if (rateValue == null)
{
_log.Debug("CurrentRefreshRate was null");
return GetStringResource("MsgText_NotAvailable");
}
return $"{rateValue} Hz";
}
#endregion Get current refresh rate

Expand All @@ -126,9 +111,15 @@ private static string FormatCurrentRefresh(CimInstance instance)
/// <returns>A formatted string.</returns>
private static string FormatResolution(CimInstance instance)
{
string? horz = instance.CimInstanceProperties["CurrentHorizontalResolution"].Value.ToString();
string? vert = instance.CimInstanceProperties["CurrentVerticalResolution"].Value.ToString();
return $"{horz} x {vert}";
object? horzValue = instance.CimInstanceProperties["CurrentHorizontalResolution"]?.Value;
object? vertValue = instance.CimInstanceProperties["CurrentVerticalResolution"]?.Value;

if (horzValue == null || vertValue == null)
{
_log.Debug("Resolution properties were null");
return GetStringResource("MsgText_NotAvailable");
}
return $"{horzValue} x {vertValue}";
}
#endregion Get current resolution

Expand All @@ -139,14 +130,14 @@ private static string FormatResolution(CimInstance instance)
/// <param name="instance">The CimInstance</param>
/// <returns>A formatted string.</returns>
#pragma warning disable RCS1213 // Remove unused member declaration
// Leaving this method in place for now as I may add it back in the future. It is currently commented out in the GetVideoInfo method.
// Leaving this method in place for now as I may add it back in the future. It is currently commented out in the GetAllVideoControllers method.
private static string FormatAdapterRamInfo(CimInstance instance)
#pragma warning restore RCS1213 // Remove unused member declaration
{
Comment on lines 132 to 136
if (instance.CimInstanceProperties["AdapterRam"] == null)
{
_log.Debug("Value for AdapterRam was null");
return "Not Available";
return GetStringResource("MsgText_NotAvailable");
}
double ram = Convert.ToDouble(instance.CimInstanceProperties["AdapterRam"].Value, CultureInfo.InvariantCulture);
if (ram >= Math.Pow(1024, 3))
Expand Down Expand Up @@ -188,7 +179,7 @@ private static int GetDisplayCount()
/// Gets to number of colors.
/// </summary>
/// <param name="instance">The CimInstance</param>
/// <returns>A formatted string.</returns>
/// <returns>A string formatted for the current culture.</returns>
private static string FormatColorsInfo(CimInstance instance)
{
if (instance.CimInstanceProperties["CurrentNumberOfColors"] == null)
Expand All @@ -197,21 +188,8 @@ private static string FormatColorsInfo(CimInstance instance)
return GetStringResource("MsgText_NotAvailable");
}
Comment on lines 185 to 189

ulong colors = Convert.ToUInt64(instance.CimInstanceProperties["CurrentNumberOfColors"].Value, CultureInfo.InvariantCulture);
if (colors >= (ulong)Math.Pow(1024, 2))
{
colors /= (ulong)Math.Pow(1024, 3);
return string.Format(CultureInfo.CurrentCulture, $"{colors:N2} {GetStringResource("MsgText_Million")}");
}
else if (colors >= (ulong)Math.Pow(1024, 1))
{
colors /= (ulong)Math.Pow(1024, 2);
return string.Format(CultureInfo.CurrentCulture, $"{colors:N2} {GetStringResource("MsgText_Thousand")}");
}
else
{
return string.Format(CultureInfo.CurrentCulture, $"{colors:N0}");
}
ulong colors = Convert.ToUInt64(instance.CimInstanceProperties["CurrentNumberOfColors"].Value, CultureInfo.CurrentCulture);
return $"{colors:N0}";
}
#endregion Total Colors
}
5 changes: 5 additions & 0 deletions TimVer/Languages/Strings.en-US.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
<sys:String x:Key="GraphicsInfo_SelectAdapter">Select Adapter</sys:String>
<sys:String x:Key="GraphicsInfo_SelectAdapterToolTipLine1">If there is more than one video adapter installed</sys:String>
<sys:String x:Key="GraphicsInfo_SelectAdapterToolTipLine2">use the drop-down to select the adapter to display.</sys:String>
<sys:String x:Key="GraphicsInfo_Unknown">Unknown</sys:String>
<!-- Hardware Information Page -->
<sys:String x:Key="HardwareInfo_BIOS">BIOS</sys:String>
<sys:String x:Key="HardwareInfo_BiosManufacturer">BIOS Manufacturer</sys:String>
Expand Down Expand Up @@ -534,4 +535,8 @@
<!-- A | SettingsItem_DarkModeTheme -->
<!-- A | MsgText_UefiUnknown -->
<!-- End of changes on 2026/07/15 @ 23:30 UTC-->

<!-- Begin changes on 2026/07/24 @ 17:00 UTC-->
<!-- A | GraphicsInfo_Unknown -->
<!-- End of changes on 2026/07/24 @ 17:00 UTC-->
</ResourceDictionary>
4 changes: 2 additions & 2 deletions TimVer/TimVer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
<!-- Set version and prerelease string (if needed) -->
<PropertyGroup>
<VersionValidate>true</VersionValidate>
<Version>0.14.0</Version>
<VersionPrerelease></VersionPrerelease>
<Version>0.14.1</Version>
<VersionPrerelease>Beta</VersionPrerelease>
</PropertyGroup>

<!-- Analyzers -->
Expand Down
15 changes: 10 additions & 5 deletions TimVer/ViewModels/VideoViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal sealed partial class VideoViewModel : ObservableObject
#region Constructor
public VideoViewModel()
{
if (VideoInfoCollection == null)
if (AllControllers == null || AllControllers.Count == 0)
{
LoadData();
}
Expand All @@ -17,8 +17,10 @@ public VideoViewModel()
#region Load data for video properties
private static void LoadData()
{
ControllerList = VideoHelpers.GetGPUList()!;
VideoInfoCollection = VideoHelpers.GetVideoInfo(ControllerList[0]);
AllControllers = VideoHelpers.GetAllVideoControllers();
ControllerList = [.. AllControllers.Select(c =>
c.GetValueOrDefault( GetStringResource("GraphicsInfo_GraphicsAdapter"), GetStringResource("GraphicsInfo_Unknown")))];
VideoInfoCollection = AllControllers.FirstOrDefault();
}
Comment on lines +20 to 24
#endregion Load data for video properties

Expand All @@ -30,15 +32,18 @@ private static void LoadData()
[RelayCommand]
private static void SelectVideoController(SelectionChangedEventArgs e)
{
if (e.Source is ComboBox box)
if (e.Source is ComboBox box && AllControllers?.Count > 0
&& box.SelectedIndex >= 0 && box.SelectedIndex < AllControllers.Count)
{
VideoInfoCollection = VideoHelpers.GetVideoInfo(ControllerList![box.SelectedIndex]);
VideoInfoCollection = AllControllers[box.SelectedIndex];
VideoPage.Instance!.VideoGrid.ItemsSource = VideoInfoCollection;
}
}
#endregion Relay command

#region Collections
private static List<Dictionary<string, string>>? AllControllers { get; set; }

public static List<string>? ControllerList { get; private set; }

public static Dictionary<string, string>? VideoInfoCollection { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions TimVer/Views/VideoPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
</ComboBox>
<StackPanel Grid.Column="2"
Orientation="Horizontal">
<TextBlock Margin="0,2" VerticalAlignment="Center"
<TextBlock Margin="10,2" VerticalAlignment="Center"
Text="{DynamicResource GraphicsInfo_SelectAdapter}" />
<TextBlock Margin="7,3" VerticalAlignment="Center"
<TextBlock Margin="0,2" VerticalAlignment="Center"
ToolTipService.InitialShowDelay="300"
ToolTipService.Placement="Top">
<materialDesign:PackIcon Width="18" Height="18"
Expand Down