{"id":108033,"date":"2023-04-10T07:00:00","date_gmt":"2023-04-10T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108033"},"modified":"2023-04-10T07:47:35","modified_gmt":"2023-04-10T14:47:35","slug":"20230410-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230410-00\/?p=108033","title":{"rendered":"Why is there a large gap between some of the Windows system metrics indices?"},"content":{"rendered":"<p>The <code>Get\u00adSystem\u00adMetrics<\/code> function lets you query a grab bag of system metrics, primarily related to user interface matters. You pass in the magic number representing a metric, and the function returns the value of that metric.<\/p>\n<p>Historically, the magic numbers for these metrics were small integers, starting with <code>SM_CXSCREEN<\/code> at zero, and continuing sequentially.<\/p>\n<p>And then Windows 2000 introduced <code>SM_<wbr \/>REMOTE\u00adSESSION<\/code> with the value way out at <code>0x1000<\/code>. Why such a large value?<\/p>\n<p>That particular gap was an artifact of the internal organization of the Windows team. The Remote Session metric is not really a user interface metric, even though the <code>Get\u00adSystem\u00adMetrics<\/code> function is in the user interface library. The Terminal Services folks kind of jammed that one into the <code>Get\u00adSystem\u00adMetrics<\/code> function, but since they knew they were treading on another team&#8217;s turf, they put their index way out in a different part of the index space so they wouldn&#8217;t mess up the user interface team&#8217;s system of having all the metrics just be indices into an internal array of <code>int<\/code> values.<\/p>\n<pre>int GetSystemMetrics(int index)\r\n{\r\n    <span style=\"color: #08f;\">if (index == SM_REMOTESESSION) {\r\n        return AskTerminalServicesIfSessionIsRemote();\r\n    }<\/span>\r\n\r\n    \/* rest of code unchanged *\/\r\n    if (index &gt;= 0 &amp;&amp; index &lt; SM_CMETRICS) {\r\n        return metricsTable[index];\r\n    }\r\n\r\n    SetLastError(ERROR_INVALID_PARAMETER);\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Next up is Windows XP, which introduced <code>SM_<wbr \/>SHUTTING\u00adDOWN<\/code> with the value way out at <code>0x2000<\/code>. The user interface team decided that they would keep the low-index metrics for true metrics (things that represent the size or number of other things), and any new metrics that are really just Boolean values disguised as metrics should be placed in the range starting at <code>0x2000<\/code>.<\/p>\n<p>That&#8217;s why you have new metrics like <code>SM_<wbr \/>SHUTTING\u00adDOWN<\/code> and <code>SM_<wbr \/>CARET\u00adBLINKING\u00adENABLED<\/code> out in the <code>0x2000<\/code> region.<\/p>\n<p>This change roughly parallels the change in the assignment of <code>System\u00adParameters\u00adInfo<\/code> parameter indices: Historically, system parameter indices were also small integers, but at some point the user interface team decided to organize them a bit, and put all the Boolean-valued parameters in the <code>0x1000<\/code> range, and all of the integer-valued parameters go in the <code>0x2000<\/code> range. This simplified parameter validation since all of the integer or Boolean parameters can be validated in common code.<\/p>\n<p>For system metrics, however, this doesn&#8217;t really provide that much of a simplification. You could still have put the values in the array of integers. There&#8217;s no validation necessary beyond the index itself, unlike <code>System\u00adParameters\u00adInfo<\/code> which had to validate pointers and structure sizes.<\/p>\n<p>I mean, sure, you saved a tiny bit of memory by packing a bunch of Boolean metrics into a bitmask, but that&#8217;s a meager savings of just a few dozen bytes at most. The code necessary to manage the bitmask is probably already bigger than the data savings.<\/p>\n<p>Well, what&#8217;s done is done. And that&#8217;s why there are gaps in the system metrics index values.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An artifact of the internal implementation.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-108033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>An artifact of the internal implementation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108033"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}