//TODO PairRequest XmlDocs for XP and CE pre 5.0.
		/// <summary>
		/// Intiates pairing for a remote device.
		/// </summary>
		/// <param name="device">Remote device with which to pair.</param>
		/// <param name="pin">Chosen PIN code, must be between 1 and 16 ASCII characters.</param>
        /// <remarks><para>On Windows CE platforms this calls <c>BthPairRequest</c>,
        /// its MSDN remarks say:
        /// </para>
        /// <para>&#x201C;BthPairRequest passes the parameters to the <c>BthSetPIN</c>
        /// function and creates an ACL connection. Once the connection is established,
        /// it calls the <c>BthAuthenticate</c> function to authenticate the device.&#x201D;
        /// </para>
        /// <para>On Windows XP/Vista platforms this calls <c>BluetoothAuthenticateDevice</c>,
        /// if the pin argument is set to null a Wizard is displayed to accept a PIN from the user,
        /// otherwise the function executes in transparent mode.
        /// </para>
        /// <para>See also 
        /// <see cref="M:InTheHand.Net.Bluetooth.BluetoothSecurity.SetPin(InTheHand.Net.BluetoothAddress,System.String)"/>
        /// </para>
        /// </remarks>
        /// <returns>Whether the operation was successful.</returns>
		public static bool PairRequest(BluetoothAddress device, string pin)
		{
            if (device == null)
            {
                throw new ArgumentNullException("device");
            }
            if (device.ToInt64() == 0)
            {
                throw new ArgumentNullException("device", "A non-blank address must be specified.");
            }           
#if WinCE
            if (pin == null)
            {
                throw new ArgumentNullException("pin");
            }

            bool success = false;
            InTheHand.Net.Sockets.BluetoothDeviceInfo bdi = new InTheHand.Net.Sockets.BluetoothDeviceInfo(device);
            
           
            if (System.Environment.OSVersion.Version.Major >= 10)
            {
                byte[] pinbytes = System.Text.Encoding.ASCII.GetBytes(pin);
                int len = pin.Length;
                int result = NativeMethods.BthPairRequest(device.ToByteArray(), len, pinbytes);
                if (result == 0)
                {
                    success = true;
                }
             }
             else
             {
                //BthPairRequest is CE 5.0 onwards so we will do it with individual steps

                //preset outgoing pin
                success = SetPin(device, pin);

                if (success)
                {
                    int hresult;
                    ushort handle = 0;
                    
                    //connect to device
                    try
                    {
                        hresult = NativeMethods.BthCreateACLConnection(device.ToByteArray(), out handle);
                        if (hresult != 0)
                        {
                            success = false;
                        }
                        else
                        {

  //                          ushort default_sniff_max = 0x640; // 1 sec 
//                            ushort default_sniff_min = 0x4B0; // .75 sec m
    //                        ushort default_sniff_attempt = 0x20;  // 0x1
      //                      ushort default_sniff_to = 0x20; // 0x1
                            

                            //force authentication
                            hresult = NativeMethods.BthAuthenticate(device.ToByteArray());
                            if (hresult != 0)
                            {
                                success = false;
                            }
                       
                        }

                    }
                    finally
                    {
                        if (handle != 0)
                        {
                            //close connection
                            hresult = NativeMethods.BthCloseConnection(handle);
                        }
                    }

                }
            }

            if (success)
            {
                //setup UI pairing (registry)
                RegistryKey rkDevices = Registry.LocalMachine.CreateSubKey(NativeMethods.ceRegistryRoot + "\\Device");
                RegistryKey rkNewDevice = rkDevices.CreateSubKey(device.ToString());
                rkNewDevice.SetValue("name", bdi.DeviceName);
                rkNewDevice.SetValue("trusted", 1);
                rkNewDevice.SetValue("class", bdi.ClassOfDevice.GetHashCode());

#if V2
                RegistryKey rkServices = rkNewDevice.CreateSubKey("Services");
                ServiceRecord[] recs = bdi.GetServiceRecords(BluetoothService.SerialPort);
                //byte[][] recs = bdi.GetServiceRecordsUnparsedWindowsRaw(BluetoothService.SerialPort);
                
                if (recs.Length > 0)
                {
                    byte[] servRecord = recs[0].SourceBytes;
                    RegistryKey rkSerial = rkServices.CreateSubKey(BluetoothService.SerialPort.ToString());
                    rkSerial.SetValue("sdprecord", servRecord);
                    rkSerial.SetValue("Name", "Serial Port");
                    rkSerial.SetValue("enabled", 1);
                    int channel = ServiceRecordHelper.GetRfcommChannelNumber(recs[0]);
                    if (channel != -1) {
                        rkSerial.SetValue("channel", 0x14b0000 + channel);
                    } else {
                        System.Diagnostics.Debug.Fail("PairRequest CE, peer SPP record missing channel.");
                    }
                    rkSerial.Close();
                }
                rkServices.Close();
#endif

                rkNewDevice.Close();
                rkDevices.Close();
            }

            return success;
#else
            //use other constructor to ensure struct size is set
			BLUETOOTH_DEVICE_INFO bdi = new BLUETOOTH_DEVICE_INFO(device.ToInt64());
			
            //string length, but allow for null pins for UI
            int length = 0;
            if (pin != null)
            {
                length = pin.Length;
            }
            int result = NativeMethods.BluetoothAuthenticateDevice(IntPtr.Zero, IntPtr.Zero, ref bdi, pin, length);

			if(result!=0)
			{
				//determine error cause from result...

				return false;
			}
			return true;
#endif
        }
 //--------------------------------------------------------------
 private bool NativeCallback(IntPtr param, ref BLUETOOTH_DEVICE_INFO bdi)
 {
     System.Diagnostics.Debug.Assert(m_pin == null ^ m_userCallback == null);
     //
     System.Diagnostics.Debug.WriteLine(String.Format(
             System.Globalization.CultureInfo.InvariantCulture,
             "AuthenticateResponder callback (for {0}): 0x{1:X} 0x{2:X}",
             m_remoteAddress, param, bdi.Address));
     //
     String pin;
     Int32 ret = NativeErrorSuccess;
     if (m_pin != null) {
         // Pre-specified case.
         System.Diagnostics.Debug.Assert(bdi.Address == m_remoteAddress.ToInt64(),
             "Should only get callback for the single device.");
         //TODO if (bdi.Address != m_remoteAddress.ToInt64()) {
         //    return false;
         //}
         pin = m_pin;
         ret = NativeMethods.BluetoothSendAuthenticationResponse(
             m_radioHandle, ref bdi, pin);
     } else {
         // Callback case.
         System.Diagnostics.Debug.Assert(m_userCallback != null);
         BluetoothWin32AuthenticationEventArgs e = new BluetoothWin32AuthenticationEventArgs(bdi);
         while (true) {
             // Callback the user code
             OnAuthentication(e);
             // Don't proceed if no (null) passcode given, or
             // if the last attempt was successful, or
             // the decvice has disppeared.
             if (e.Pin == null) {
                 break;
             }
             if (e.PreviousNativeErrorCode == NativeErrorSuccess && e.AttemptNumber != 0) {
                 break;
             }
             if (e.PreviousNativeErrorCode == NativeErrorDeviceNotConnected) {
                 // When I try this (against Win2k+Belkin and iPaq hx2190,
                 // both apparently with Broadcom) I see:
                 //[[
                 //Authenticate one device -- with wrong passcode here the first two times.
                 //Passcode respectively: 'BAD-x', 'BAD-y', '9876'
                 //Making PC discoverable
                 //Hit Return to complete
                 //Authenticating 0017E464CF1E wm_alan1
                 //  Attempt# 0, Last error code 0
                 //Using '0.23672947484847'
                 //Authenticating 0017E464CF1E wm_alan1
                 //  Attempt# 1, Last error code 1244
                 //Using '0.54782851764365'
                 //Authenticating 0017E464CF1E wm_alan1
                 //  Attempt# 2, Last error code 1167
                 //Using '9876'
                 //Authenticating 0017E464CF1E wm_alan1
                 //  Attempt# 3, Last error code 1167
                 //etc
                 //]]
                 // That is we see the error code of 1244=ErrorNotAuthenticated
                 // once, and then the peer device disappears (1167=ErrorDeviceNotConnected).
                 // I suppose that's a security feature -- its stops an attacker
                 // from trying again and again with different passcodes.
                 //
                 // Anyway the result of that is that is it NOT worth repeating
                 // the callback after the device disappears.
                 break;
             }
             pin = e.Pin;
             System.Diagnostics.Debug.WriteLine(String.Format(System.Globalization.CultureInfo.InvariantCulture,
                 "BW32Auth SendAuthRsp pin {0}", pin));
             ret = NativeMethods.BluetoothSendAuthenticationResponse(
                 m_radioHandle, ref bdi, pin);
             if (ret != NativeErrorSuccess) {
                 System.Diagnostics.Trace.WriteLine(String.Format(
                     System.Globalization.CultureInfo.InvariantCulture,
                     "    BluetoothSendAuthenticationResponse failed: {0}=0x{0:X}", ret));
             }
             // Have to callback the user code after the attempt?
             BluetoothWin32AuthenticationEventArgs lastEa = e;
             if (!lastEa.CallbackWithResult) {
                 break;
             }
             e = new BluetoothWin32AuthenticationEventArgs(ret, lastEa);
         }
     }
     //
     if (ret != NativeErrorSuccess) {
         System.Diagnostics.Trace.WriteLine(String.Format(
             System.Globalization.CultureInfo.InvariantCulture,
             "BluetoothSendAuthenticationResponse failed: {0}=0x{0:X}", ret));
     }
     return true; // "The return value from this function is ignored by the system."
 }
 internal BluetoothWin32AuthenticationEventArgs(BLUETOOTH_DEVICE_INFO device)
 {
     m_device = new BluetoothDeviceInfo(device);
 }
 private void Register(BluetoothAddress remoteAddress)
 {
     System.Diagnostics.Debug.Assert(m_pin == null ^ m_userCallback == null);
     //
     m_callback = new NativeMethods.BluetoothAuthenticationCallback(NativeCallback);
     BLUETOOTH_DEVICE_INFO bdi = new BLUETOOTH_DEVICE_INFO(remoteAddress);
     UInt32 ret = NativeMethods.BluetoothRegisterForAuthentication(
         ref bdi, out m_regHandle, m_callback, IntPtr.Zero);
     int gle = Marshal.GetLastWin32Error();
     System.Diagnostics.Debug.Assert(ret == NativeErrorSuccess,
         "BluetoothRegisterForAuthentication failed, GLE="
         + gle.ToString() + "=0x)" + gle.ToString("X"));
     if (ret != NativeErrorSuccess) {
         throw new System.ComponentModel.Win32Exception(gle);
     }
     m_regHandle.SetObjectToKeepAlive(m_callback);
 }