All posts tagged window resources

I think the title says it pretty well: we want the DatePicker control to not be stupid and allow tabbing to the calendar button so we can meet mouse-less compliance standards.

Q: Why didn’t Microsoft do this to begin with?
A: *shrugs* But, we’re going to fix it.

The code:


using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

/// <summary>
/// Extended DatePicker.
/// </summary>
public class ExtendedDatePicker : DatePicker
{
    #region Members

    private bool _tabInvoked;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="ExtendedDatePicker"/> class.
    /// </summary>
    public ExtendedDatePicker()
    {
        _tabInvoked = false;
        this.PreviewKeyDown += DatePickerPreviewKeyDown;
        this.CalendarClosed += DatePickerCalendarClosed;

        // Allow to be a tab target
        IsTabStop = true;
    }

    #endregion

    #region Events

    /// <summary>
    /// Dates the picker preview key down.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="KeyEventArgs"/> instance containing the event data.
    /// </param>
    private void DatePickerPreviewKeyDown(object sender, KeyEventArgs e)
    {
        var datePicker = sender as DatePicker;
        if (datePicker == null || e.Key != Key.Tab) return;

        // Mark that "tab" was pressed
        _tabInvoked = true;

        // Reverse drop down opened state
        datePicker.IsDropDownOpen = !datePicker.IsDropDownOpen;
    }

    /// <summary>
    /// Dates the picker calendar closed.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.
    /// </param>
    private void DatePickerCalendarClosed(object sender, RoutedEventArgs e)
    {
        if (!_tabInvoked) return;

        // Reset marker
        _tabInvoked = false;

        // Go to next control in sequence
        var element = Keyboard.FocusedElement as UIElement;
        if (element == null) return;
        element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }

    #endregion
}

Here is what it does in a nutshell:

  • Makes this control a tab stop (it’s not by default)
  • Binds to the PreviewKeyDown event, which catches when Tab is pressed. It then sets a marker, telling the control that the calendar was opened via keyboard and sets IsDropDownOpen to true.
  • Binds to the CalendarClosed event, which (if Tab was invoked) resets the marker and sets the focus to the next control in the view.

It’s not overly complicated, but it solves an annoyance.

Until next time…

This is a bit dated, but the question is about how you get (near) accurate processor information in Windows 2003 with WMI and no external executables.

I wrote this a long time ago for VBS and translated it into C# for my upcoming application: Astronomy. I added some snazzy XAML in there to pimp it out a bit. There is a lot of code here, but that is because a lot needs to be done to format the data into something we want to see.

The desired result:

So, let’s see all that code:

The XAML:


<Window x:Class="GetProcessCountLegacy.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="525">

    <Window.Resources>

        <!-- Text Styles -->
        <Style x:Key="ListHeader" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="Bold" />
        </Style>
        <Style x:Key="ListLabel" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="Normal" />
        </Style>
        <Style x:Key="ListValue" TargetType="{x:Type TextBlock}">
            <Setter Property="FontWeight" Value="DemiBold" />
        </Style>

        <!-- Border -->
        <Style x:Key="BorderStyle" TargetType="Border">
            <Setter Property="BorderBrush" Value="#999" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="CornerRadius" Value="6" />
            <Setter Property="Padding" Value="16,14,16,16" />
            <Setter Property="Margin" Value="12,6,12,6" />
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0.5, 0" EndPoint="0.5, 1" Opacity="1.0">
                        <GradientStop Color="#FFFFFF" Offset="0" />
                        <GradientStop Color="#FFFFFF" Offset="0.5" />
                        <GradientStop Color="#EDEDED" Offset="1" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <!-- Processor Information -->
        <Border Style="{StaticResource BorderStyle}">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="28"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                    <RowDefinition Height="22"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="600"/>
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
                                       VerticalAlignment="Top"
                                       Text="Processor Information"
                                       Style="{StaticResource ListHeader}" />

                <TextBlock Grid.Row="1" Grid.Column="0"
                                       Text="Description:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="1" Grid.Column="1"
                                       x:Name="txtDescription"
                                       Style="{StaticResource ListValue}" />

                <TextBlock Grid.Row="2" Grid.Column="0"
                                       Text="Core Speed:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="2" Grid.Column="1"
                                       x:Name="txtSpeed"
                                       Style="{StaticResource ListValue}" />

                <TextBlock Grid.Row="3" Grid.Column="0"
                                       Text="Count:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="3" Grid.Column="1"
                                       x:Name="txtCount"
                                       Style="{StaticResource ListValue}" />

                <TextBlock Grid.Row="4" Grid.Column="0"
                                       Text="Width:"
                                       Style="{StaticResource ListLabel}" />
                <TextBlock Grid.Row="4" Grid.Column="1"
                                       x:Name="txtWidth"
                                       Style="{StaticResource ListValue}" />
            </Grid>
        </Border>
    </Grid>
</Window>

C#

[Main Code]


    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Contructors

        /// <summary>
        /// Main constructor.
        /// </summary>
        public MainWindow()
        {
            // Initialize UI
            InitializeComponent();

            // Get processor information
            GetProcessorInformation();
        }

        #endregion

        /// <summary>
        /// Retrieve the processor information and add to UI.
        /// </summary>
        private void GetProcessorInformation()
        {
            // Build an options object for the remote connection
            var options = new ConnectionOptions
                {
                    Impersonation = ImpersonationLevel.Impersonate,
                    EnablePrivileges = true
                };

            // Make a connection to a remote computer.
            var ms = new ManagementScope(@"" + "." + @"rootcimv2", options);

            // Query
            string query = "SELECT Manufacturer, MaxClockSpeed, AddressWidth, Name, " +
                           "SocketDesignation, ProcessorID, UniqueID FROM Win32_Processor";

            // Searcher
            var searcher =
                new ManagementObjectSearcher(ms, new WqlObjectQuery(query));

            // Get legacy info
            var processor = GetProcessorInfoLegacy(searcher);

            // Processor information
            // Description
            txtDescription.Text = RemoveExcessSpaces(processor.Name);
            if (String.IsNullOrEmpty(txtDescription.Text))
            {
                txtDescription.Text = "{Unknown}";
            }

            // Speed
            txtSpeed.Text = GetProcessorSpeed(processor.Speed);
            if (String.IsNullOrEmpty(txtSpeed.Text))
            {
                txtSpeed.Text = "{Unknown}";
            }

            // Count
            txtCount.Text = GetProcessorCount(5.2, processor);
            if (String.IsNullOrEmpty(txtCount.Text))
            {
                txtCount.Text = "{Unknown}";
            }

            // Width
            txtWidth.Text = "x86-" + processor.Architecture;
            if (String.IsNullOrEmpty(txtWidth.Text))
            {
                txtWidth.Text = "{Unknown}";
            }
        }

        /// <summary>
        /// Gets processor information for Windows version 5.x.
        /// </summary>
        /// <param name="searcher"></param>
        /// <returns></returns>
        private static ProcessorInfo GetProcessorInfoLegacy(
            ManagementObjectSearcher searcher)
        {
            // Processor object
            var processor = new ProcessorInfo();

            // Descriptors
            var socket = new List<string>();
            var procId = new List<string>();
            var uniqueId = new List<string>();

            // Get data
            ManagementObjectCollection colItems = searcher.Get();

            try
            {
                // Evaluate data
                foreach (ManagementBaseObject objItem in colItems)
                {
                    // Manufacturer
                    if (objItem["Manufacturer"] != null)
                    {
                        processor.Manufacturer = objItem["Manufacturer"].ToString();
                    }

                    // Speed
                    if (objItem["MaxClockSpeed"] != null)
                    {
                        processor.Speed = Convert.ToInt32(objItem["MaxClockSpeed"]);
                    }

                    // Architecture
                    if (objItem["AddressWidth"] != null)
                    {
                        processor.Architecture = objItem["AddressWidth"].ToString();
                    }

                    // Socket Designation
                    if (objItem["SocketDesignation"] != null)
                    {
                        processor.SocketDesignation =
                            objItem["SocketDesignation"].ToString();
                        socket.Add(processor.SocketDesignation);
                    }

                    // Name
                    if (objItem["Name"] != null)
                    {
                        processor.Name = objItem["Name"].ToString();
                    }

                    // ProcessorID
                    if (objItem["ProcessorID"] != null)
                    {
                        processor.ProcessorID = objItem["ProcessorID"].ToString();
                        procId.Add(processor.ProcessorID);
                    }
                    else
                    {
                        procId.Add("");
                    }

                    // UniqueID
                    if (objItem["UniqueID"] != null)
                    {
                        processor.UniqueID = objItem["UniqueID"].ToString();
                        uniqueId.Add(processor.UniqueID);
                    }
                    else
                    {
                        uniqueId.Add("");
                    }
                }

                // Logical count
                int totalProcCount = colItems.Count;
                processor.LogicalProcessors = totalProcCount;

                // Cores
                GetLegacyCoreCount(socket, procId, uniqueId, ref processor);

                // Get #of possible sockets
                if ((processor.Cores > 0) && (processor.LogicalProcessors > 0))
                {
                    int result = (processor.LogicalProcessors / processor.Cores);
                    processor.Count = result;
                }
            }
            catch
            {
            }
            finally
            {
                colItems.Dispose();
            }

            // return
            return processor;
        }

        /// <summary>
        /// Gets the number of processor cores for Windows version 5.x.
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="procId"></param>
        /// <param name="uniqueId"></param>
        /// <param name="processor"></param>
        private static void GetLegacyCoreCount(List<string> socket, List<string> procId,
                                               List<string> uniqueId, ref ProcessorInfo processor)
        {
            int totalProcessors = 0;

            // Processor marker

            // Check Socket Designation
            for (int i = 0; i < socket.Count; i++)
            {
                // Start with the assumption this is unique.
                bool isUnique = true;

                // Check for Redundancies
                for (int j = i + 1; j < socket.Count; j++)
                {
                    if (socket[i] == socket[j])
                    {
                        isUnique = false;
                        break;
                    }
                }

                // If Redundant Unique ID's Exist
                for (int j = i + 1; j < socket.Count; j++)
                {
                    if ((uniqueId[i] != "") && (uniqueId[j] != "") &&
                        (uniqueId[i] != uniqueId[j]))
                    {
                        isUnique = true;
                        break;
                    }
                }

                // Check for NULL ProcessorID
                if (procId[i].Trim() == "0000000000000000")
                {
                    isUnique = false;
                }

                // Calculate Total
                if (isUnique)
                {
                    totalProcessors++;
                }
            }

            // Get Cores
            int result = (processor.LogicalProcessors / totalProcessors);
            processor.Cores = result;
        }

        /// <summary>
        /// Retrieves the Processor speed in human-readable format.
        /// </summary>
        /// <param name="speed"></param>
        /// <returns></returns>
        public static string GetProcessorSpeed(int speed)
        {
            string result = string.Empty;

            if (speed.ToString().Length >= 4)
            {
                double dSpeed = Convert.ToDouble(speed) / 1000;
                result = dSpeed.ToString("0.00") + " GHz";
            }
            else
            {
                result = speed.ToString() + " MHz";
            }

            // Return
            return result;
        }

        /// <summary>
        /// Returns the processor count in a human-readable format.
        /// </summary>
        /// <param name="oSver"></param>
        /// <param name="proc"></param>
        /// <returns></returns>
        public static string GetProcessorCount(double oSver, ProcessorInfo proc)
        {
            string result = "";

            int physical = proc.Count;
            int cores = proc.Cores;

            // Manufacturer
            string hyper = "HyperThreading";
            if (proc.Manufacturer.ToLower().IndexOf("intel") == -1)
            {
                hyper = "HyperTransport";
            }

            // Processor count
            string physDesc = physical.ToString() + " processor(s)";

            // Cores
            string coreDesc = string.Empty;

            // Current
            if (oSver >= 6)
            {
                coreDesc = cores.ToString() + " core(s)";
                if (proc.IsHyperThreaded)
                {
                    coreDesc += " w/ HyperThreading";
                }
            }

                // Legacy
            else
            {
                coreDesc = cores.ToString() + " core(s)";

                if ((cores / physical) == 2)
                {
                    // Intel
                    if (proc.Manufacturer.ToLower().IndexOf("intel") != -1)
                    {
                        coreDesc += " (or " + physical + " core(s) w/ " + hyper + ")";
                    }
                }
            }

            result = physDesc + " (" + coreDesc + ")";

            // Return
            return result;
        }

        /// <summary>
        /// Removes extra spaces between words.
        /// </summary>
        /// <param name="procDesc"></param>
        /// <returns></returns>
        public static string RemoveExcessSpaces(string procDesc)
        {
            string result = "";

            // Evaluate
            string[] desc = procDesc.Split((char)32);

            // Name
            for (int i = 0; i < desc.Length; i++)
            {
                if (desc[i].Trim() != "")
                {
                    result += desc[i] + " ";
                }
            }

            // Return
            return result;
        }
    }

[ProcessorInfo class]


    /// <summary>
    /// Information relevant to the physical processors.
    /// </summary>
    public class ProcessorInfo
    {
        #region Properties

        /// <summary>
        /// Win32_Processor: AddressWidth: On a 32-bit operating system, the value is 32
        /// and on a 64-bit operating system it is 64.
        /// </summary>
        public string Architecture { get; set; }

        /// <summary>
        /// Win32_Processor: NumberOfCores: Number of cores for the current instance of
        /// the processor.
        /// </summary>
        public int Cores { get; set; }

        /// <summary>
        /// Total processor count.
        /// </summary>
        public int Count { get; set; }

        /// <summary>
        /// Determines whether processors support Hyper-Threading or Hyper-Transport.
        /// </summary>
        public bool IsHyperThreaded { get; set; }

        /// <summary>
        /// Win32_Processor: NumberOfLogicalProcessors: Number of logical processors for
        /// the current instance of the processor.
        /// </summary>
        public int LogicalProcessors { get; set; }

        /// <summary>
        /// Win32_Processor: Manufacturer: Name of the processor manufacturer.
        /// </summary>
        public string Manufacturer { get; set; }

        /// <summary>
        /// Win32_Processor: Name: Label by which the object is known.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Win32_Processor: ProcessorID: Processor information that describes the
        /// processor features.
        /// </summary>
        public string ProcessorID { get; set; }

        /// <summary>
        /// Win32_Processor: SocketDesignation: Type of chip socket used on the circuit.
        /// </summary>
        public string SocketDesignation { get; set; }

        /// <summary>
        /// Win32_Processor: MaxClockSpeed: Detected processor speed.
        /// </summary>
        public int Speed { get; set; }

        /// <summary>
        /// Win32_Processor: UniqueID: Globally unique identifier for the processor.
        /// </summary>
        public string UniqueID { get; set; }

        #endregion

        #region Constructors

        public ProcessorInfo()
        {
            Architecture = "x86";
        }

        #endregion
    }