{"id":107623,"date":"2022-12-29T07:00:00","date_gmt":"2022-12-29T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107623"},"modified":"2022-12-15T16:17:18","modified_gmt":"2022-12-16T00:17:18","slug":"20221229-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221229-00\/?p=107623","title":{"rendered":"How can I detect programmatically whether Windows is an N or KN version?"},"content":{"rendered":"<p>A customer was dealing with a problem that occurred only when running on an N or KN version of Windows. These versions of Windows are special versions that omit the multimedia features.\u00b9 Microsoft is legally required to offer these versions of Windows in certain jurisdictions, although in practice, the number of people who buy them is vanishingly small. (It sometimes feels like the sole reason those customers exist is to file bugs that reproduce only on N and KN versions.)<\/p>\n<p>The customer wanted to know how to detect that the user is running an N or KN version of Windows, so they could disable the features of the product that depend upon multimedia support.<\/p>\n<p>The answer is that you don&#8217;t check whether you are on an N or KN version of Windows. Rather, you check whether multimedia support is present.<\/p>\n<p>Because the user, after buying an N or KN version of Windows (perhaps inadvertently), can later <a href=\"https:\/\/support.microsoft.com\/en-us\/topic\/media-feature-pack-list-for-windows-n-editions-c1c6fffa-d052-8338-7a79-a4bb980a700a\"> download and install the Media Feature Pack<\/a> and restore multimedia support. In that case, they expect your program to enable its multimedia features.<\/p>\n<p>So really, what you want to do is detect whether multimedia support is present. One way to do that is to see if you can call the <code>MFStartup<\/code> function, and whether it succeeds. If not, then Media Foundation is not available, and multimedia features are not available.<\/p>\n<p>This particular customer had a Web-based app, in which case they can use <code>HTMLMediaElement.<wbr \/>canPlayType<\/code> to detect whether the system can play their media, and skip the video if so.<\/p>\n<p><b>Bonus chatter<\/b>: The bug was that if you asked to see the training video, the video didn&#8217;t play (expected), but the app also hung (not expected). The reason is that the app tried to play the video roughly like this:<\/p>\n<pre>var video = document.queryselector(\"#training-video\");\r\nvideo.src = \"\/videos\/training.mp4\";\r\nvideo.addEventListener(\"error\", onVideoFinished);\r\nvideo.addEventListener(\"ended\", onVideoFinished);\r\n<\/pre>\n<p>If multimedia support is not present, the <code>error<\/code> event is raised immediate upon setting the <code>src<\/code> property. But the code hasn&#8217;t registered a handler for that event, so the <code>error<\/code> event is raised, but nobody is there to handle it. The app later adds a handler, but it&#8217;s too late. That&#8217;s why the app appeared to hang.<\/p>\n<p>To deal with errors that occur immediately, the app should register the event handlers <i>before<\/i> setting the source.<\/p>\n<p>(Note that <code>canPlayType<\/code> is still useful, even after they fix this race condition. That lets them detect that the system cannot play the training video at all, and they can remove the &#8220;Play training video&#8221; option from their interface, or replace it with an explanation of why the training video is not available.)<\/p>\n<p>\u00b9 The KN version also omits Windows Messenger, but since Windows Messenger itself has been discontinued, the distinction is meaningless in practice.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Don&#8217;t check the version, just check the feature.<\/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":[25],"class_list":["post-107623","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Don&#8217;t check the version, just check the feature.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107623","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=107623"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107623\/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=107623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107623"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}