public byte[][] GetServiceRecordsUnparsedWindowsRaw(Guid service) { WqsOffset.AssertCheckLayout(); BlobOffsets.AssertCheckLayout(); //temporary workaround - sockets must be initialised Socket s = new Socket(AddressFamily32.Bluetooth, SocketType.Stream, BluetoothProtocolType.RFComm); //store variable length collection of records System.Collections.ArrayList records = new System.Collections.ArrayList(); byte[] sdp = null; WSAQUERYSET wqs = new WSAQUERYSET(); wqs.dwSize = WqsOffset.StructLength_60; wqs.dwNameSpace = WqsOffset.NsBth_16; #if NETCF CSADDR_INFO sainfo = new CSADDR_INFO(null, this.DeviceAddress , SocketType.Unknown, ProtocolType.Unknown); wqs.dwNumberOfCsAddrs = 1; IntPtr pSaInfo = Marshal32.AllocHGlobal(24); IntPtr pBrb = Marshal32.AllocHGlobal(256); IntPtr pService = Marshal32.AllocHGlobal(240); Marshal.StructureToPtr(sainfo, pSaInfo, false); wqs.lpcsaBuffer = pSaInfo; Marshal.WriteInt32(pBrb, 0, (int)SdpQueryType.SearchAttributeRequest); //write the service guid Marshal.Copy(service.ToByteArray(), 0, new IntPtr(pBrb.ToInt32() + 8), 16); Marshal.WriteInt16(pBrb, 24, (short)SdpSpecificType.Uuid128); Marshal.WriteInt16(pBrb, 26, 0); //write an empty guid to the next position Marshal.Copy(Guid.Empty.ToByteArray(), 0, new IntPtr(pBrb.ToInt32() + 28), 16); Marshal.WriteInt16(pBrb, 44, 0x0); Marshal.WriteInt16(pBrb, 46, 0); //number of attribute ranges Marshal.WriteInt32(pBrb, 248, 1); //min attribute Marshal.WriteInt16(pBrb, 252, 0); //max attribute Marshal.StructureToPtr((ushort)0xffff, (IntPtr)(pBrb.ToInt32() + 254), false); //Marshal.WriteInt16(pBrb, 254, 0x800); BLOB b = new BLOB(256, pBrb); IntPtr pb = Marshal32.AllocHGlobal(8); Marshal.StructureToPtr(b, pb, false); wqs.lpBlob = pb; #endif #if WinXP GCHandle hservice = GCHandle.Alloc(service.ToByteArray(), GCHandleType.Pinned); wqs.lpServiceClassId = hservice.AddrOfPinnedObject(); wqs.lpszContext = "(" + this.DeviceAddress.ToString("C") + ")"; // sb.ToString(); // hContext.AddrOfPinnedObject(); #endif IntPtr handle = IntPtr.Zero; int lookupresult; //start looking for Bluetooth services #if NETCF LookupFlags flagsForBegin; // Move above the #if is changed to use for desktop build too. flagsForBegin = 0; bool isQueryingLocalhost = false; try { BluetoothRadio theOne = BluetoothRadio.PrimaryRadio; // Only ever one on CE... if (theOne != null) { BluetoothAddress localAddr = theOne.LocalAddress; if (localAddr != null) { if (localAddr == this.DeviceAddress) { isQueryingLocalhost = true; } } } } catch (Exception ex) { System.Diagnostics.Debug.Fail("Exception in hack on CE to check if localhost: " + ex); } if (isQueryingLocalhost) { flagsForBegin |= LookupFlags.ResService; } #endif #if NETCF try { lookupresult = NativeMethods.WSALookupServiceBegin(ref wqs, flagsForBegin, out handle); #else lookupresult = NativeMethods.WSALookupServiceBegin(ref wqs, LookupFlags.FlushCache | LookupFlags.ReturnName | LookupFlags.ReturnBlob, out handle); #endif SocketBluetoothClient.ThrowSocketExceptionForHR(lookupresult); #if WinXP hservice.Free(); #endif while (lookupresult == 0) { byte[] sdpBuffer = new byte[6000]; BitConverter.GetBytes(WqsOffset.StructLength_60).CopyTo(sdpBuffer, WqsOffset.dwSize_0); BitConverter.GetBytes(WqsOffset.NsBth_16).CopyTo(sdpBuffer, WqsOffset.dwNameSpace_20); int size = sdpBuffer.Length; #if NETCF lookupresult = NativeMethods.WSALookupServiceNext(handle, (LookupFlags)0, ref size, sdpBuffer); #else lookupresult = NativeMethods.WSALookupServiceNext(handle, LookupFlags.FlushCache | LookupFlags.ReturnBlob, ref size, sdpBuffer); #endif if (lookupresult == -1) { const int WSA_E_NO_MORE = 10110; SocketBluetoothClient.ThrowSocketExceptionForHrExceptFor(lookupresult, WSA_E_NO_MORE); } else { IntPtr pBlob = InTheHand.Runtime.InteropServices.Marshal32.ReadIntPtr(sdpBuffer, WqsOffset.lpBlob_56); if (pBlob != IntPtr.Zero) { IntPtr pSdpBlob = InTheHand.Runtime.InteropServices.Marshal32.ReadIntPtr(pBlob, BlobOffsets.Offset_pBlobData_4); int cSdpBlob = Marshal.ReadInt32(pBlob); if (cSdpBlob > 2) { sdp = new byte[cSdpBlob]; Marshal.Copy(pSdpBlob, sdp, 0, cSdpBlob); records.Add(sdp); } } } } #if NETCF } finally { sainfo.Dispose(); Marshal32.FreeHGlobal(pSaInfo); Marshal32.FreeHGlobal(pb); Marshal32.FreeHGlobal(pBrb); } #endif //stop looking lookupresult = NativeMethods.WSALookupServiceEnd(handle); SocketBluetoothClient.ThrowSocketExceptionForHR(lookupresult); return (byte[][])records.ToArray(typeof(byte[])); }
IBluetoothDeviceInfo[] DoDiscoverDevices(int maxDevices, bool authenticated, bool remembered, bool unknown, bool discoverableOnly, InTheHand.Net.Sockets.BluetoothClient.LiveDiscoveryCallback liveDiscoHandler, object liveDiscoState) { WqsOffset.AssertCheckLayout(); CsaddrInfoOffsets.AssertCheckLayout(); // #if !NETCF Debug.Assert(liveDiscoHandler == null, "Don't use the NETCF live-disco feature on Win32!"); #endif #if WinXP const bool Win32DiscoverableOnlyIncludesAllDevices = false; #endif var prototype = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.Empty); int discoveredDevices = 0; List_IBluetoothDeviceInfo al = null; IntPtr handle = IntPtr.Zero; int lookupresult = 0; /* Windows XP SP3 * Begin takes the full Inquiry time. * 12:09:15.7968750: Begin * 10.265s 12:09:26.0625000: Begin complete * 12:09:26.0625000: Next * 12:09:26.0625000: Next Complete * ... * 12:09:26.1718750: Next * 12:09:26.1718750: Next Complete * 12:09:26.1718750: End * 12:09:26.1718750: End Complete */ /* WM 6 SP * Begin is quick, Next blocks until a device is found. * 13:46:47.1760000: Begin * 13:46:47.2350000: Begin complete * 13:46:47.2360000: Next * 10.537s 13:46:57.7730000: Next Complete * 13:46:57.8910000: Next * 13:46:57.8940000: Next Complete * 13:46:57.8950000: Next * 13:46:57.8960000: Next Complete * 13:46:57.8960000: End * 13:46:57.8990000: End Complete * */ System.Text.StringBuilder timings = null; #if DEBUG // timings = new System.Text.StringBuilder(); #endif Action <string> markTime = delegate(string name) { if (timings != null) { timings.AppendFormat(CultureInfo.InvariantCulture, "{1}: {0}\r\n", name, DateTime.UtcNow.TimeOfDay); } }; #if WinXP if (discoverableOnly && !Win32DiscoverableOnlyIncludesAllDevices) { // No way to separate out the devices-in-range on Win32. :-( return(new IBluetoothDeviceInfo[0]); } #endif #if NETCF DateTime discoTime = DateTime.UtcNow; if (unknown || discoverableOnly) { #endif al = new List_IBluetoothDeviceInfo(); byte[] buffer = new byte[1024]; BitConverter.GetBytes(WqsOffset.StructLength_60).CopyTo(buffer, WqsOffset.dwSize_0); BitConverter.GetBytes(WqsOffset.NsBth_16).CopyTo(buffer, WqsOffset.dwNameSpace_20); int bufferlen = buffer.Length; BTHNS_INQUIRYBLOB bib = new BTHNS_INQUIRYBLOB(); bib.LAP = iac;// 0x9E8B33; #if NETCF bib.length = Convert.ToByte(inquiryLength.TotalSeconds / 1.28); bib.num_responses = Convert.ToByte(maxDevices); #else bib.length = Convert.ToByte(inquiryLength.TotalSeconds); #endif GCHandle hBib = GCHandle.Alloc(bib, GCHandleType.Pinned); IntPtr pBib = hBib.AddrOfPinnedObject(); BLOB b = new BLOB(8, pBib); GCHandle hBlob = GCHandle.Alloc(b, GCHandleType.Pinned); Marshal32.WriteIntPtr(buffer, WqsOffset.lpBlob_56, hBlob.AddrOfPinnedObject()); //start looking for Bluetooth devices LookupFlags flags = LookupFlags.Containers; #if WinXP //ensure cache is cleared on XP when looking for new devices if (unknown || discoverableOnly) { flags |= LookupFlags.FlushCache; } #endif markTime("Begin"); lookupresult = NativeMethods.WSALookupServiceBegin(buffer, flags, out handle); markTime("Begin complete"); hBlob.Free(); hBib.Free(); // TODO ?Change "while(...maxDevices)" usage on WIN32? while (discoveredDevices < maxDevices && lookupresult != -1) { markTime("Next"); #if NETCF lookupresult = NativeMethods.WSALookupServiceNext(handle, LookupFlags.ReturnAddr | LookupFlags.ReturnBlob, ref bufferlen, buffer); #else LookupFlags flagsNext = LookupFlags.ReturnAddr; #if WIN32_READ_BTH_DEVICE_INFO flagsNext |= LookupFlags.ReturnBlob; #endif lookupresult = NativeMethods.WSALookupServiceNext(handle, flagsNext, ref bufferlen, buffer); #endif markTime("Next Complete"); if (lookupresult != -1) { //increment found count discoveredDevices++; //status #if WinXP BTHNS_RESULT status = (BTHNS_RESULT)BitConverter.ToInt32(buffer, WqsOffset.dwOutputFlags_52); bool devAuthd = ((status & BTHNS_RESULT.Authenticated) == BTHNS_RESULT.Authenticated); bool devRembd = ((status & BTHNS_RESULT.Remembered) == BTHNS_RESULT.Remembered); if (devAuthd && !devRembd) { System.Diagnostics.Debug.WriteLine("Win32 BT disco: Auth'd but NOT Remembered."); } bool devUnkwn = !devRembd && !devAuthd; bool include = (authenticated && devAuthd) || (remembered && devRembd) || (unknown && devUnkwn); Debug.Assert(!discoverableOnly, "Expected short circuit for Win32 unsupported discoverableOnly!"); if (include) #else if (true) #endif { #if NETCF IntPtr lpBlob = (IntPtr)BitConverter.ToInt32(buffer, 56); BLOB ib = (BLOB)Marshal.PtrToStructure(lpBlob, typeof(BLOB)); BthInquiryResult bir = (BthInquiryResult)Marshal.PtrToStructure(ib.pBlobData, typeof(BthInquiryResult)); #endif //struct CSADDR_INFO { // SOCKET_ADDRESS LocalAddr; // SOCKET_ADDRESS RemoteAddr; // INT iSocketType; // INT iProtocol; //} //struct SOCKET_ADDRESS { // LPSOCKADDR lpSockaddr; // INT iSockaddrLength; //} //pointer to outputbuffer IntPtr bufferptr = Marshal32.ReadIntPtr(buffer, WqsOffset.lpcsaBuffer_48); //remote socket address IntPtr sockaddrptr = Marshal32.ReadIntPtr(bufferptr, CsaddrInfoOffsets.OffsetRemoteAddr_lpSockaddr_8); //remote socket len int sockaddrlen = Marshal.ReadInt32(bufferptr, CsaddrInfoOffsets.OffsetRemoteAddr_iSockaddrLength_12); SocketAddress btsa = new SocketAddress(AddressFamily32.Bluetooth, sockaddrlen); for (int sockbyte = 0; sockbyte < sockaddrlen; sockbyte++) { btsa[sockbyte] = Marshal.ReadByte(sockaddrptr, sockbyte); } var bep = (BluetoothEndPoint)prototype.Create(btsa); //new deviceinfo IBluetoothDeviceInfo newdevice; #if NETCF newdevice = new WindowsBluetoothDeviceInfo(bep.Address, bir.cod); // Built-in to Win32 so only do on NETCF newdevice.SetDiscoveryTime(discoTime); #else newdevice = new WindowsBluetoothDeviceInfo(bep.Address); #if WIN32_READ_BTH_DEVICE_INFO ReadBlobBTH_DEVICE_INFO(buffer, newdevice); #endif #endif //add to discovered list al.Add(newdevice); if (liveDiscoHandler != null) { liveDiscoHandler(newdevice, liveDiscoState); } } } }//while #if NETCF } #endif //stop looking if (handle != IntPtr.Zero) { markTime("End"); lookupresult = NativeMethods.WSALookupServiceEnd(handle); markTime("End Complete"); } if (timings != null) { Debug.WriteLine(timings); #if !NETCF Console.WriteLine(timings); #endif } #if NETCF List_IBluetoothDeviceInfo known = WinCEReadKnownDevicesFromRegistry(); al = BluetoothClient.DiscoverDevicesMerge(authenticated, remembered, unknown, known, al, discoverableOnly, discoTime); #endif //return results if (al.Count == 0) { //special case for empty collection return(new IBluetoothDeviceInfo[0] { }); } return((IBluetoothDeviceInfo[])al.ToArray( #if V1 typeof(IBluetoothDeviceInfo) #endif )); }