{"id":6621,"date":"2018-12-13T19:35:59","date_gmt":"2018-12-13T19:35:59","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=6621"},"modified":"2018-12-13T19:35:59","modified_gmt":"2018-12-13T19:35:59","slug":"enumerating-available-devices-in-uwp","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/enumerating-available-devices-in-uwp\/","title":{"rendered":"Enumerating available devices in UWP"},"content":{"rendered":"<p>In my previous post (<a href=\"http:\/\/putridparrot.com\/blog\/displaying-the-device-picker-in-a-uwp-application\/\" rel=\"noopener\" target=\"_blank\">Displaying the device picker in a UWP application<\/a>) I showed how to reuse the UWP device picker flyout within an application. <\/p>\n<p>However, it&#8217;s possible that the developer would prefer to offer devices in some alternate UI or, of course, simply locate a known device for an application to use. In the previous post I looked at filtering for Bluetooth devices and those are what I&#8217;m after for a little application I&#8217;m writing in which I do not require the DevicePicker UI.<\/p>\n<p><strong>Filtering<\/strong><\/p>\n<p>Before I get into code to enumerate the devices, I&#8217;ll first expand on the lines of code from my previous post, that look like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nBluetoothDevice.GetDeviceSelectorFromPairingState(false)\r\n<\/pre>\n<p>Each of the lines like this one actually returns a string which is an <strong>Advanced Query Syntax (AQS)<\/strong> language query. So for example this line will produce the following string (formatted to make it more readable)<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nSystem.Devices.DevObjectType:=5 AND \r\nSystem.Devices.Aep.ProtocolId:=\\&quot;{E0CBF06C-CD8B-4647-BB8A-263B43F0F974}\\&quot; AND \r\n(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#False OR\r\nSystem.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#True)\r\n<\/pre>\n<p>For completeness, here&#8217;s the results of each of the other GetDeviceSelectorFromPairingState calls<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nBluetoothLEDevice.GetDeviceSelectorFromPairingState(false)\r\n\r\nSystem.Devices.DevObjectType:=5 AND \r\nSystem.Devices.Aep.ProtocolId:=\\&quot;{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\\&quot; AND \r\n(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#False OR \r\nSystem.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#True)\r\n\r\nBluetoothLEDevice.GetDeviceSelectorFromPairingState(true)\r\n\r\nSystem.Devices.DevObjectType:=5 AND \r\nSystem.Devices.Aep.ProtocolId:=\\&quot;{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\\&quot; AND \r\n(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True OR \r\nSystem.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#False)\r\n\r\nBluetoothDevice.GetDeviceSelectorFromPairingState(true)\r\n\r\nSystem.Devices.DevObjectType:=5 AND \r\nSystem.Devices.Aep.ProtocolId:=\\&quot;{E0CBF06C-CD8B-4647-BB8A-263B43F0F974}\\&quot; AND \r\n(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True OR \r\nSystem.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#False)\r\n<\/pre>\n<p>Hence we could now create our own AQS query to search for devices. <\/p>\n<p>See <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/desktop\/search\/-search-3x-advancedquerysyntax\" rel=\"noopener\" target=\"_blank\">Using Advanced Query Syntax Programmatically<\/a> for more information on AQS.<\/p>\n<p><strong>Enumerating over devices (simple approach)<\/strong><\/p>\n<p>A simple approach to enumerating over all the available devices is to use the <em>DeviceInformation.FindAllAsync()<\/em> method, which is async\/await compatible, hence we simply use it like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar devices = await DeviceInformation.FindAllAsync();\r\n\r\n\/\/ output all devices\r\nforeach (var device in devices)\r\n{\r\n   Debug.WriteLine(device.Name);\r\n}\r\n<\/pre>\n<p>Obviously this is a little over the top if we&#8217;re looking for a specific device or set of devices. In such cases we can create an AQS query and pass this into one of the FindAllAsync overloads. Hence to recreate my previous post&#8217;s query looking for all Bluetooth devices we might prefer to use<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar devices = await DeviceInformation.FindAllAsync(\r\n    BluetoothDevice.GetDeviceSelectorFromPairingState(\r\n        false));\r\n<\/pre>\n<p>Whilst this solution to the problem of locating devices may fulfil many of the developer&#8217;s requirements, an area it fails on is that once the developer has a list of devices they do not have a way to tell when devices are turned off\/disabled\/or otherwise no longer available. In such situations it&#8217;s better to watch for device changes.<\/p>\n<p><strong>Watching for device changes<\/strong><\/p>\n<p>The <a href=\"https:\/\/docs.microsoft.com\/en-us\/uwp\/api\/windows.devices.enumeration.deviceinformation.createwatcher\" rel=\"noopener\" target=\"_blank\">DeviceInformation.CreateWatcher<\/a> method allows the developer to query for devices and via events, watch for items to be added, updated  or removed. This would suit an RX type of implementation.<\/p>\n<p>Here&#8217;s some code that demonstrates possible usage of the CreateWatcher<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ntry\r\n{\r\n   deviceWatcher = DeviceInformation.CreateWatcher(\r\n      BluetoothDevice.GetDeviceSelectorFromPairingState(false), \r\n      null,\r\n      DeviceInformationKind.Device);\r\n\r\n      deviceWatcher.Added += (watcher, args) =&gt;\r\n      {\r\n         Debug.WriteLine($&quot;Added {args.Name}&quot;);\r\n      };\r\n      deviceWatcher.Updated += (watcher, args) =&gt;\r\n      {\r\n         Debug.WriteLine($&quot;Updated {args.Id}&quot;);\r\n      };\r\n      deviceWatcher.Removed += (watcher, args) =&gt;\r\n      {\r\n         Debug.WriteLine($&quot;Removed {args.Id}&quot;);\r\n      };\r\n      deviceWatcher.EnumerationCompleted += (watcher, args) =&gt; \r\n      { \r\n         Debug.WriteLine(&quot;No more devices found&quot;); \r\n      };\r\n      deviceWatcher.Start();\r\n}\r\ncatch (ArgumentException ex)\r\n{\r\n   Debug.WriteLine(ex.Message);\r\n}\r\n<\/pre>\n<p>Again we&#8217;re using the AQS created via the GetDeviceSelectoryFromPairingState method and in this simplistic example, we simply subscribe to the Added\/Updated\/Removed and EnumerationCompleted events to output what devices have been added etc. We also need to be aware of possible ArgumentExceptions, such as incorrectly formatted GUID&#8217;s etc. See <a href=\"https:\/\/docs.microsoft.com\/en-us\/uwp\/api\/windows.devices.enumeration.deviceinformation\" rel=\"noopener\" target=\"_blank\">DeviceInformation<\/a> Class for a more complete example of this usage.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my previous post (Displaying the device picker in a UWP application) I showed how to reuse the UWP device picker flyout within an application. However, it&#8217;s possible that the developer would prefer to offer devices in some alternate UI or, of course, simply locate a known device for an application to use. In the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[231,106,230,107],"tags":[],"class_list":["post-6621","post","type-post","status-publish","format-standard","hentry","category-bluetooth","category-universal-app","category-uwp","category-windows-10"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6621","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=6621"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6621\/revisions"}],"predecessor-version":[{"id":6627,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6621\/revisions\/6627"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=6621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=6621"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=6621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}