{"id":270,"date":"2008-05-25T21:49:52","date_gmt":"2008-05-25T21:49:52","guid":{"rendered":"http:\/\/dalelane.co.uk\/blog\/?p=270"},"modified":"2008-05-25T22:18:04","modified_gmt":"2008-05-25T22:18:04","slug":"programmatically-searching-for-nearby-bluetooth-devices-in-windows-mobile-from-c","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=270","title":{"rendered":"Programmatically searching for nearby Bluetooth devices in Windows Mobile from C#"},"content":{"rendered":"<p>As part of my plan to write a <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=268\">location-based reminder app using Bluetooth devices<\/a>, I need a way to know what bluetooth devices are near me. <\/p>\n<p>I&#8217;ve not done any Bluetooth development before, so I&#8217;ve had to learn a few new bits and pieces tonight.<\/p>\n<p><!--more--><\/p>\n<h3>Decision 1 &#8211; Which SDK?<\/h3>\n<p>It turns out that there is more than one type of Bluetooth radio used in Windows Mobile phones. And the SDKs that lets you programmatically interact with the bluetooth stack are specific to certain radios. There seem to be only a few big players here. A lot of Windows Mobile devices use the Microsoft Bluetooth stack, and Microsoft provide an API for them. The other big chunk of devices are supported by a <a href=\"http:\/\/www.broadcom.com\/products\/bluetooth_sdk.php\" target=\"_blank\">Widcomm Bluetooth SDK<\/a>. I also found references in a couple of forum posts about a third, smaller, provider &#8211; although I can&#8217;t find them now. (<em>Why don&#8217;t I make better notes as I go along?!<\/em>)<\/p>\n<p>My Windows Mobile devices both support the Microsoft Bluetooth stack, so I&#8217;m gonna go with that for now. I did download the Widcomm SDK and start playing with it a bit, but I think I&#8217;ll leave that for another day.<\/p>\n<h3>Decision 2 &#8211; To discover, or not to discover&#8230;<\/h3>\n<p>I have a couple of options:<\/p>\n<h4>Search for all local Bluetooth devices with a discoverable device ID<\/h4>\n<p>PROS: <\/p>\n<ul>\n<li>The devices don&#8217;t need to be registered \/ paired with my phone. <\/li>\n<\/ul>\n<p>CONS: <\/p>\n<ul>\n<li>Not everyone leaves their Bluetooth devices in a &#8216;discoverable&#8217; mode.\n<\/li>\n<li>You can&#8217;t do this easily in a background, notification-based way. You&#8217;re limited to polling at regular intervals &#8211; which is never a particularly elegant (or battery-efficient!) programming paradigm.<\/li>\n<\/ul>\n<p>. <\/p>\n<h4>Register for connect and disconnect notifications from paired devices<\/h4>\n<p>PROS: <\/p>\n<ul>\n<li>Bluetooth devices you search for don&#8217;t need to be discoverable.\n<\/li>\n<li>You don&#8217;t need to poll &#8211; you can just register for notifications then sit back and wait to be called when a device comes into range<\/li>\n<\/ul>\n<p>CONS: <\/p>\n<ul>\n<li>You need to pair with every device &#8211; adding hassle and overhead for users. Would people worry about trust issues?<\/li>\n<\/ul>\n<p>I guess an ideal solution would be to write an app which can do both. For now, I&#8217;ll start with the Discovery approach.<\/p>\n<h3>Decision 3 &#8211; Implementation time!<\/h3>\n<p>As I&#8217;ve <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=269\">already started my app in C#<\/a>, I started by looking for a C# API. There isn&#8217;t one. (<em>Well, there are some third-party libraries kicking about&#8230; <a href=\"http:\/\/inthehand.com\/content\/32feet.aspx\" target=\"_blank\">32feet.NET<\/a> seems to be popular from what I&#8217;ve read. But where&#8217;s the fun in that?<\/em> \ud83d\ude42 )<\/p>\n<p>There is a C++ API to do it with Winsock commands which is well-documented with a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms881713.aspx\" target=\"_blank\">sample and walkthrough on MSDN<\/a>. I had a go at writing some P\/Invoke code to port the sample to C# &#8211; using P\/Invoke to call each of the <code>WSAStartup<\/code>, <code>WSALookupServiceBegin<\/code>, <code>WSALookupServiceNext<\/code>, <code>WSALookupServiceEnd<\/code>, <code>WSACleanup<\/code> functions in turn from C# code.<\/p>\n<p>I thought it was easy enough to write, but I can&#8217;t seem to get it working. It compiles fine, but I&#8217;m obviously not creating the C# equivalent of the <code>WSAQUERYSET<\/code> structure correctly, because calls to <code>WSALookupServiceBegin<\/code> keep getting <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms740668(VS.85).aspx\" target=\"_blank\">WSA_INVALID_HANDLE<\/a> error codes.<\/p>\n<p>I&#8217;ve tried a bunch of different approaches, but it just isn&#8217;t working. I&#8217;m guessing it&#8217;s something I&#8217;m doing wrong <a target=\"_blank\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa446529.aspx#netcfadvinterop_topic2\">marshalling the strings<\/a> in the structure.<\/p>\n<p>So on to Plan B &#8211; give up trying to write it in C#, write the whole thing in a C++ function, and compile it into a DLL which I can P\/Invoke from C#. Then I don&#8217;t need to muck about P\/Invoking the individual Winsock calls and structures. <\/p>\n<p>I&#8217;ve done that now, and it seems to be working okay. <\/p>\n<p>If anyone thinks it might be useful, the <a href=\"http:\/\/dalelane.co.uk\/files\/bLADEBluetoothLib.dll\">DLL is available here<\/a>. You can use it from C# like this:<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em\">[DllImport(\"bLADEBluetoothLib.dll\",\r\n  EntryPoint = \"discoverbluetoothdevices\",\r\n  CharSet = CharSet.Unicode,\r\n  SetLastError = true)]\r\nprivate static extern int DiscoverBluetoothDevices(String deviceList);\r\n\r\n[DllImport(\"Ws2.dll\", \r\n  SetLastError = true)]\r\nprivate extern static Int32 WSAGetLastError();\r\n\r\npublic static string[] GetDiscoverableDevices()\r\n{\r\n  \/\/ prepare a 500 character buffer for the DLL to return \r\n  \/\/  the result in\r\n  String deviceList = new String(' ', 500);\r\n\r\n  \/\/ get a comma-separated list of \r\n  \/\/ discoverable Bluetooth devices\r\n  \/\/ \r\n  \/\/ the number of devices is returned\r\n  int nbrDevices = DiscoverBluetoothDevices(deviceList);\r\n\r\n  if (nbrDevices >= 0)\r\n  {\r\n    return deviceList.ToString().Split(new char[] { ',' });\r\n  }\r\n  else\r\n  {\r\n    \/\/ if the DLL encounters an error in one of the WinSock\r\n    \/\/  functions it uses, it returns -1\r\n    \/\/ \r\n    \/\/ you can then use WSAGetLastError to find the source\r\n    \/\/  of the error\r\n    MessageBox.Show(nbrDevices.ToString() + \r\n            \" (reason: \" + WSAGetLastError() + \")\");\r\n    return new string[0];\r\n  }\r\n}<\/pre>\n<p>It&#8217;s still very rough around the edges, so stuff like tidying and error-handling needs to be sorted. I&#8217;ve not written C++ for P\/Invoking before, so as a first attempt, there are almost certainly a few mistakes in my approach. But so far&#8230; it seems to work.<\/p>\n<p>The <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=268\">location-based reminder app<\/a> is starting to take shape. \ud83d\ude42 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>As part of my plan to write a location-based reminder app using Bluetooth devices, I need a way to know what bluetooth devices are near me. I&#8217;ve not done any Bluetooth development before, so I&#8217;ve had to learn a few new bits and pieces tonight.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[202,209,38,208,207,19,43,210],"class_list":["post-270","post","type-post","status-publish","format-standard","hentry","category-code","tag-bluetooth","tag-dll","tag-microsoft","tag-pinvoke","tag-widcomm","tag-windows-mobile","tag-windowsmobile","tag-winsock"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/270","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=270"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/270\/revisions"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=270"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}