private static string ParseServiceName(ref Structs.BtSdkRemoteServiceAttrStru attrs) { string nameUtf8 = BluesoleilUtils.FixedLengthArrayToStringUtf8(attrs.svc_name); string nameUL = Encoding.Unicode.GetString(attrs.svc_name); nameUL = nameUL.Trim('\0'); #if DEBUG string nameUB = Encoding.BigEndianUnicode.GetString(attrs.svc_name); nameUB = nameUB.Trim('\0'); Debug.Assert(nameUL.Length == nameUB.Length, "Our simple check of length doesn't work for Unicode little-endian vs big-endian, the lengths are the same." + " BUT different here!! nameUL.Length: " + nameUL.Length + ", nameUB.Length: " + nameUB.Length); #endif // string name = nameUtf8; if (nameUL.Length > name.Length) { name = nameUL; } // As described in DEBUG above, can't do this!! if (nameUB.Length > name.Length) name = nameUB; return(name); }
public ServiceRecord[] GetServiceRecords(Guid service) { BtSdkError ret; var search = new Structs.BtSdkSDPSearchPatternStru[1]; search[0] = new Structs.BtSdkSDPSearchPatternStru(service); UInt32[] recordHandles = new uint[MaxServiceRecordsLookup]; int num = recordHandles.Length; // Fetch the matching records (the handles of). int numSearch = search.Length; ret = _factory.Api.Btsdk_BrowseRemoteServicesEx(_hDev, search, numSearch, recordHandles, ref num); if (ret == BtSdkError.NO_SERVICE) // None { return(new ServiceRecord[0]); } BluesoleilUtils.CheckAndThrow(ret, "Btsdk_BrowseRemoteServicesEx"); // Fetch the records' attributes and convert to our format. var results = new List <ServiceRecord>(); for (int i = 0; i < num; ++i) { var hRcd = recordHandles[i]; var attrs = new Structs.BtSdkRemoteServiceAttrStru( StackConsts.AttributeLookup.ServiceName | StackConsts.AttributeLookup.ExtAttributes); // Use 'Get' here and not 'Refresh' as the 'Browse' call above // should have retrieved the attributes. ret = _factory.Api.Btsdk_GetRemoteServiceAttributes(hRcd, ref attrs); BluesoleilUtils.CheckAndThrow(ret, "Btsdk_RefreshRemoteServiceAttributes"); Debug.Assert(attrs.dev_hdl == _hDev); // IBluesoleilApi hackApi = _factory.Api; ServiceRecord sr = CreateServiceRecord(ref attrs, hackApi); results.Add(sr); } return(results.ToArray()); }
internal static extern BtSdkError Btsdk_GetRemoteServiceAttributes(BTSVCHDL svc_hdl, ref Structs.BtSdkRemoteServiceAttrStru attribute);
internal static ServiceRecord CreateServiceRecord(ref Structs.BtSdkRemoteServiceAttrStru attrs, IBluesoleilApi api) { ServiceRecordBuilder bldr = new ServiceRecordBuilder(); //-- Guid sc = BluetoothService.CreateBluetoothUuid(attrs.svc_class); bldr.AddServiceClass(sc); //-- string name = ParseServiceName(ref attrs); if (name.Length != 0) { bldr.ServiceName = name; } // byte?port = null; var extras = new List <ServiceAttribute>(); Debug.Assert(attrs.status == 0, "attrs.status: 0x" + attrs.status.ToString("X")); if (attrs.ext_attributes != IntPtr.Zero) { if (sc == BluetoothService.HumanInterfaceDevice) { var hidInfo = (Structs.BtSdkRmtHidSvcExtAttrStru_HACK)Marshal.PtrToStructure( attrs.ext_attributes, typeof(Structs.BtSdkRmtHidSvcExtAttrStru_HACK)); Debug.Assert(Marshal.SizeOf(typeof(Structs.BtSdkRmtHidSvcExtAttrStru_HACK)) == Marshal.SizeOf(hidInfo), "SizeOf x2"); Debug.Assert(hidInfo.size == Marshal.SizeOf(typeof(Structs.BtSdkRmtHidSvcExtAttrStru_HACK)) + Structs.BtSdkRmtHidSvcExtAttrStru_HACK.StackMiscountsPaddingSize, "Different sizes! hidInfo.size: " + hidInfo.size + ", SizeOf(): " + Marshal.SizeOf(typeof(Structs.BtSdkRmtHidSvcExtAttrStru_HACK))); // TO-DO Human Interface (HID) record: Use "mask" field, it's undocumented, check for real life values // With test SdpCreateAHumanInputDeviceRecordsAllTwoOfThree // which adds two out of three of {DeviceReleaseNumber,DeviceSubclass,CountryCode} // mask==0. So mask apparently applies to other fields! // So we check these three values for zero // and discard them if so! Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "HID.mask: {0:X}", hidInfo.mask)); var list = new List <ServiceAttribute>(); if (hidInfo.deviceReleaseNumber != 0) { list.Add( new ServiceAttribute(HidProfileAttributeId.DeviceReleaseNumber, new ServiceElement(ElementType.UInt16, hidInfo.deviceReleaseNumber))); } if (hidInfo.deviceSubclass != 0) { list.Add( new ServiceAttribute(HidProfileAttributeId.DeviceSubclass, new ServiceElement(ElementType.UInt8, hidInfo.deviceSubclass))); } if (hidInfo.countryCode != 0) { list.Add( new ServiceAttribute(HidProfileAttributeId.CountryCode, new ServiceElement(ElementType.UInt8, hidInfo.countryCode))); } // TO-DO HID other... extras.AddRange(list); } else if (sc == BluetoothService.PnPInformation) { var deviceInfo = (Structs.BtSdkRmtDISvcExtAttrStru)Marshal.PtrToStructure( attrs.ext_attributes, typeof(Structs.BtSdkRmtDISvcExtAttrStru)); Debug.Assert(Marshal.SizeOf(typeof(Structs.BtSdkRmtDISvcExtAttrStru)) == Marshal.SizeOf(deviceInfo), "SizeOf x2"); Debug.Assert(deviceInfo.size == Marshal.SizeOf(typeof(Structs.BtSdkRmtDISvcExtAttrStru)) + Structs.BtSdkRmtDISvcExtAttrStru.StackMiscountsPaddingSize, "Different sizes! deviceInfo.size: " + deviceInfo.size + ", Marshal.SizeOf: " + Marshal.SizeOf(typeof(Structs.BtSdkRmtDISvcExtAttrStru))); // TO-DO Device Info (PnP) record: Use "mask" field, it's undocumented, check for real life values //Debug.Assert(deviceInfo.mask == 0, "Is mask field in BtSdkRmtDISvcExtAttrStru ever set!!!, is here:" + deviceInfo.mask); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "PnP/DI.mask: {0:X}", deviceInfo.mask)); // Like above (PnP) we see mask==0 for the fields we handle // here (six of). So we check these values // for zero and discard them if so! var list = new List <ServiceAttribute>(); if (deviceInfo.spec_id != 0) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.SpecificationId, new ServiceElement(ElementType.UInt16, deviceInfo.spec_id))); } if (deviceInfo.vendor_id != 0) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.VendorId, new ServiceElement(ElementType.UInt16, deviceInfo.vendor_id))); } if (deviceInfo.product_id != 0) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.ProductId, new ServiceElement(ElementType.UInt16, deviceInfo.product_id))); } if (deviceInfo.version != 0) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.Version, new ServiceElement(ElementType.UInt16, deviceInfo.version))); } if (true /* Zero means False here!! */) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.PrimaryRecord, new ServiceElement(ElementType.Boolean, deviceInfo.primary_record))); } if (deviceInfo.vendor_id_source != 0) { list.Add( new ServiceAttribute(DeviceIdProfileAttributeId.VendorIdSource, new ServiceElement(ElementType.UInt16, deviceInfo.vendor_id_source))); } // TO-DO URLs... extras.AddRange(list); } else { // On testing we see this never working! For one device // with an ImagingResponder record the size of 0x18 and // not 0x8 as per definition, and the port value is wrong. // And for its PhonebookAccessPse record the size is // correctly 0x8, but again the port value is wrong! // var sppInfo = (Structs.BtSdkRmtSPPSvcExtAttrStru)Marshal.PtrToStructure( attrs.ext_attributes, typeof(Structs.BtSdkRmtSPPSvcExtAttrStru)); Debug.Assert(sppInfo.size == Marshal.SizeOf(typeof(Structs.BtSdkRmtSPPSvcExtAttrStru)), "Different sizes!"); port = sppInfo.server_channel; } api.Btsdk_FreeMemory(attrs.ext_attributes); }//if (attrs.ext_attributes != NULL) // Use a different API to try and get the RFCOMM port number as // the previous API is quite rubbish at doing that!! var svcB = new Structs.BtSdkAppExtSPPAttrStru(sc); var retSpp = api.Btsdk_SearchAppExtSPPService(attrs.dev_hdl, ref svcB); if (retSpp == BtSdkError.NO_SERVICE) // error { } else if (retSpp != BtSdkError.OK) // error { Debug.WriteLine("GetSvcRcds Btsdk_SearchAppExtSPPService ret: " + BluesoleilUtils.BtSdkErrorToString(retSpp)); } else // success { if (svcB.rf_svr_chnl != 0) { byte newPort = svcB.rf_svr_chnl; if (port.HasValue) { Debug.Assert(port.Value == newPort, "port: " + port.Value + ", newPort: " + newPort); } else { port = newPort; } } if (svcB.sdp_record_handle != 0) { bldr.AddCustomAttribute(new ServiceAttribute( UniversalAttributeId.ServiceRecordHandle, ServiceElement.CreateNumericalServiceElement(ElementType.UInt32, svcB.sdp_record_handle))); } #if DEBUG Debug.Assert(svcB.service_class_128 == sc, "svcSpp.service_class_128: " + svcB.service_class_128 + ", sc: " + sc); var snSpp = BluesoleilUtils.FromNameString(svcB.svc_name, StackConsts.BTSDK_SERVICENAME_MAXLENGTH); if (snSpp == null) { Debug.Assert(name == null || name.Length == 0, "svcSpp.svc_name: null" + ", name: " + name); } else if (snSpp.Length == 1) { // SearchAppExtSPPService doesn't handle Unicode // but Btsdk_BrowseRemoteServicesEx etc does. Debug.Assert(snSpp[0] == name[0], "svcSpp.svc_name: " + snSpp + ", name: " + name); } else { Debug.Assert(snSpp == name, "svcSpp.svc_name: " + snSpp + ", bldr.ServiceName: " + name); } #endif } // if (port.HasValue) { } else { bldr.ProtocolType = BluetoothProtocolDescriptorType.None; } if (extras.Count != 0) { bldr.AddCustomAttributes(extras); } // const ServiceAttributeId FakeDescr = (ServiceAttributeId)(-1); bldr.AddCustomAttribute(new ServiceAttribute(FakeDescr, new ServiceElement(ElementType.TextString, "<partial BlueSoleil decode>"))); ServiceRecord sr = bldr.ServiceRecord; if (port.HasValue) { Debug.Assert(bldr.ProtocolType == BluetoothProtocolDescriptorType.Rfcomm, "type=" + bldr.ProtocolType); ServiceRecordHelper.SetRfcommChannelNumber(sr, port.Value); } else { bldr.ProtocolType = BluetoothProtocolDescriptorType.None; } return(sr); }
BtSdkError IBluesoleilApi.Btsdk_GetRemoteServiceAttributes(BTSVCHDL svc_hdl, ref Structs.BtSdkRemoteServiceAttrStru attribute) { return(NativeMethods.Btsdk_GetRemoteServiceAttributes(svc_hdl, ref attribute)); }