How do I identify a paired Bluetooth device that's currently disconnected? - c#

How do I discover a paired Bluetooth device that's currently disconnected?
I've attempted the following code using the Windows 10 SDK:
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth.Rfcomm;
var serviceInfoCollection = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
I've also tried the following:
using System;
using System.Diagnostics;
using System.Management;
public class Win32_UsbDriveWatcher
{
ManagementEventWatcher m_watcher;
public delegate void DeviceInsertedEventHandler(object sender, Win32_UsbDriveInsertEventArgs e);
public event DeviceInsertedEventHandler DeviceInserted;
public event EventHandler DeviceRemoved;
public void Start(int pollingInterval)
{
try
{
var queryString =
"SELECT * " +
" FROM __InstanceOperationEvent" +
" WITHIN " + pollingInterval +
" WHERE TargetInstance ISA 'Win32_PnPEntity'";
var processQuery = new EventQuery(queryString);
m_watcher = new ManagementEventWatcher(processQuery);
m_watcher.EventArrived += EventArrived;
m_watcher.Start();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
void EventArrived(object sender, EventArrivedEventArgs e)
{
var instance = ((PropertyData)(e.NewEvent.Properties["TargetInstance"]));
var obj = (ManagementBaseObject)instance.Value;
var args = new Win32_UsbDriveInsertEventArgs();
if ((string)obj["InterfaceType"] == "BLUETOOTH")
{
args.IsCreated = (obj.ClassPath.ClassName == "__InstanceCreationEvent");
args.DriveName = GetDriveLetterFromDisk((string)obj["Name"]);
if (args.IsCreated)
{
DeviceInserted?.Invoke(this, args);
}
else
{
DeviceRemoved?.Invoke(this, EventArgs.Empty);
}
}
}
static string GetDriveLetterFromDisk(string name)
{
name = name.Replace("\\", "\\\\");
var query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + name + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
var queryDrive = new ObjectQuery(query);
using (var searcherDrive = new ManagementObjectSearcher(queryDrive))
{
foreach (ManagementObject drive in searcherDrive.Get())
{
query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" +
drive["DeviceID"] +
"'} WHERE AssocClass = Win32_LogicalDiskToPartition";
var queryPartition = new ObjectQuery(query);
using (var searcherPartition = new ManagementObjectSearcher(queryPartition))
{
foreach (ManagementObject disk in searcherPartition.Get())
{
return (string)disk["Name"];
}
}
}
return string.Empty;
}
}
}
public class Win32_UsbDriveInsertEventArgs : EventArgs
{
public bool IsCreated;
public string DriveName;
}
Regardless of the code snippets that I've attempted, I'm still unable to discover paired disconnected devices.
Any suggestions?

There are few way:
Use WM_DEVICE_CHANGE message to know when device connected and disconnected.
Once you found all paired devices query each for its services. Not available (disconnected) device reports error.
Try to connect to device's SDP service using DeviceIOControl (the best way).

Related

Finding Bluetooth Mac address in Windows10 UWP without pairing

I'm trying to write an app that reads all MAC addresses around on Windows 10 IoT. These lines of code is returning all paired devices even if they aren't turn on.
var selector = BluetoothDevice.GetDeviceSelector();
var devices = await DeviceInformation.FindAllAsync(selector);
listBox.Items.Add(devices.Count);
foreach (var device in devices)
{
listBox.Items.Add(device.Id);
}
And I also found this line of code
await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
This returning null though. Is there any way to scan for all MAC addresses in a Windows 10 universal app?
You are very close to finding the answer of your question. You might try getting a BluetoothDevice instance from the DeviceId property. You will then be able to get all the specific Bluetooth information including the Bluetooth address
var selector = BluetoothDevice.GetDeviceSelector();
var devices = await DeviceInformation.FindAllAsync(selector);
foreach (var device in devices)
{
var bluetoothDevice = await BluetoothDevice.FromIdAsync(device.Id);
if (bluetoothDevice != null)
{
Debug.WriteLine(bluetoothDevice.BluetoothAddress);
}
Debug.WriteLine(device.Id);
foreach(var property in device.Properties)
{
Debug.WriteLine(" " + property.Key + " " + property.Value);
}
}
There is a new approach using BluetoothLEAdvertisementWatcher to scan for all Bluetooth LE device around.
Here is a piece of code I use in my project:
var advertisementWatcher = new BluetoothLEAdvertisementWatcher()
{
SignalStrengthFilter.InRangeThresholdInDBm = -100,
SignalStrengthFilter.OutOfRangeThresholdInDBm = -102,
SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000)
};
advertisementWatcher.Received += AdvertisementWatcher_Received;
advertisementWatcher.Stopped += AdvertisementWatcher_Stopped;
advertisementWatcher.Start();
and later
advertisementWatcher.Stop();
advertisementWatcher.Received -= AdvertisementWatcher_Received;
advertisementWatcher.Stopped -= AdvertisementWatcher_Stopped;
private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
//MessAgeChanged(MsgType.NotifyTxt, "FR_NAME:"+ eventArgs.Advertisement.LocalName + "BT_ADDR: " + eventArgs.BluetoothAddress);
string sDevicename = setup.Default.BLEName.Text;
BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
if (asyncInfo.GetResults() == null)
{
if (!FailMsg)
{
MessAgeChanged(MsgType.NotifyTxt, "None");
}
}
else
{
BluetoothLEDevice currentDevice = asyncInfo.GetResults();
Boolean contain = false;
foreach (BluetoothLEDevice device in DeviceList.ToArray())/
{
if (device.DeviceId == currentDevice.DeviceId)
{
contain = true;
}
}
if (!contain)
{
byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress);
Array.Reverse(_Bytes1);
// The received signal strength indicator (RSSI)
double rssi = eventArgs.RawSignalStrengthInDBm;
DeviceList.Add(currentDevice);
MessAgeChanged(MsgType.NotifyTxt, currentDevice.Name + " " + BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower() + " " + rssi);
DeviceWatcherChanged(MsgType.BleDevice, currentDevice);
}
}
}
};
}

How to set IP address of device connected to Host PC? C# Winform?

I have a Modbus TCP/IP to MODBUS RTU converter , which comes with a default IP of 192.168.0.1 . I need to develop a small c# Winform app to change this device's IP address to any desired IP address. How do I do that?.
You could do it with WMI (Windows Management Instrumentation).
First, you have to add the reference for System.Management to your Project.
Second, you need to find the NetworkInterface for your network connection by name:
using System.Net.NetworkInformation;
using System.Management;
public class NetworkManager
{
public static NetworkInterface GetNetworkInterface(string sName)
{
NetworkInterface NetInterface = null;
// Precondition
if (sName == "") return null;
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface ni in interfaces)
{
if (ni.Name == sName)
{
NetInterface = ni;
break;
}
}
return NetInterface;
}
Third, you have to create a ManagementObject for your NetworkInterface:
public static ManagementObject GetNetworkAdapterManagementObject(NetworkInterface NetInterface)
{
ManagementObject oMngObj = null;
// Precondition
if (NetInterface == null) return null;
string sNI = NetInterface.Id;
ManagementClass oMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection oMOC = oMC.GetInstances();
foreach (ManagementObject oMO in oMOC)
{
string sMO = oMO["SettingID"].ToString();
if (sMO == sNI)
{
// Found
oMngObj = oMO;
break;
}
}
return oMngObj;
}
Fours, you can set the ipadress with:
public static bool SetIPAdress(ManagementObject oMO, string[] saIPAdress, string[] saSubnetMask)
{
bool bErg = false;
try
{
// Precondition
if (oMO == null) return false;
if (saIPAdress == null) return false;
if (saSubnetMask == null) return false;
// Get ManagementBaseObject
ManagementBaseObject oNewIP = null;
oNewIP = oMO.GetMethodParameters("EnableStatic");
oNewIP["IPAddress"] = saIPAdress;
oNewIP["SubnetMask"] = saSubnetMask;
// Invoke
oMO.InvokeMethod("EnableStatic", oNewIP, null);
// Alles ok
bErg = true;
}
catch (Exception ex)
{
Console.WriteLine("SetIPAdress failed: " + ex.Message);
}
return bErg;
}
}
Now you can use it, for example in a button click event handler:
private void button1_Click(object sender, EventArgs e)
{
string sConn = "LAN-Verbindung";
NetworkInterface oNI = NetworkManager.GetNetworkInterface(sConn);
ManagementObject oMO = NetworkManager.GetNetworkAdapterManagementObject(oNI);
string sIPAdress = "192.168.1.1";
string sSubnetMask = "255.255.255.0";
string[] saIPAdress = {sIPAdress};
string[] saSubnetMask = {sSubnetMask};
if (NetworkManager.SetIPAdress(oMO, saIPAdress, saSubnetMask))
{
Console.WriteLine("Yes...");
}
}
Depending on the policies on your pc, may be you have to run the program as Administrator...

Obtaining HDD Serial Number via Drive Letter using WMI query in C#

I have the following code which works well in obtaining HDD serial numbers via the Model string value in Win32_DiskDrive. But I need to obtain the serial number via the drive letter assigned. Is this possible? If so how?
public string GetDriveSerial(string model)
{
string serial = string.Empty;
string query = "SELECT * FROM Win32_DiskDrive WHERE Model = '" + model + "'";
try
{
using (var results = new ManagementObjectSearcher("root\\CIMV2", query))
{
foreach (ManagementObject result in results.Get())
{
serial = result["SerialNumber"].ToString();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return serial;
}
You can try this:
public static string GetSerialFromDrive(string driveLetter)
{
try
{
using (var partitions = new ManagementObjectSearcher("ASSOCIATORS OF {Win32_LogicalDisk.DeviceID='" + driveLetter +
"'} WHERE ResultClass=Win32_DiskPartition"))
{
foreach (var partition in partitions.Get())
{
using (var drives = new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" +
partition["DeviceID"] +
"'} WHERE ResultClass=Win32_DiskDrive"))
{
foreach (var drive in drives.Get())
{
return (string)drive["SerialNumber"];
}
}
}
}
}
catch
{
return "<unknown>";
}
// Not Found
return "<unknown>";
}
This expects the drive letter like this: "C:", "D:" ...
The original code can be found here.

How to use PrintCapabilities Class in C#

I am trying to intercept a printer job and change the attributes of the print job. I can intercept the print job and get information regarding it. I followed this article for that
http://www.codeproject.com/Questions/423178/printing-order-intercept-with-csharp
Now I want to change the paper size of the print job and for that I found this article
http://social.msdn.microsoft.com/Forums/en/windowsxps/thread/8af6ba92-5d2c-444b-91f4-a8747739c1b7
But the problem is I cannot create class PrintCapabilities. Am I missing something ?? Please help.
My current code looks like the following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Printing;
namespace PrintJob
{
class EvenWatch
{
private ManagementEventWatcher manEWatch;
public EvenWatch(string host)
{
System.Management.ManagementScope oMs = new System.Management
.ManagementScope(#"\\" + host + #"\root\cimv2");
oMs.Connect();
manEWatch = new ManagementEventWatcher(oMs, new EventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 0.1 WHERE TargetInstance ISA 'Win32_PrintJob'"));
manEWatch.EventArrived += new EventArrivedEventHandler(
mewPrintJobs_EventArrived);
manEWatch.Start();
}
static void mewPrintJobs_EventArrived(object sender, EventArrivedEventArgs e)
{
foreach (PropertyData prop in e.NewEvent.Properties)
{
string val = prop.Value == null ? "null" : prop.Value.ToString();
}
ManagementBaseObject printJob = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
string v = "";
foreach (PropertyData propp in printJob.Properties)
{
string name = propp.Name;
string val = propp.Value == null ? "null" : propp.Value.ToString();
val += "\n";
v += name + ":" + val;
}
PrintQueue printerSpooler = null;
printerSpooler = new PrintQueue(new PrintServer(), "EPSON LQ-300+ /II ESC/P 2");
PrintJobSettings printJobSetting = printerSpooler.CurrentJobSettings;
string desc = printJobSetting.Description;
//printerSpooler.CurrentJobSettings.CurrentPrintTicket
Console.WriteLine("-------");
Console.WriteLine(v);
}
}
}
I actually found out the answer. If you are using 4.0 you should also reference ReachFramework.dll once you do that the magic does happen :)

Scanning for a Human Interface Device (HID) using C#

I am developing a C# .NET 2.0 application wherein I need to scan for an attached HID. How can this be done? Because it is a HID, Windows does not assign a COM port to it. I only need to programmatically determine if the device is attached. Thank you.
ADDITIONAL INFORMATION
When I connect the USB device to my computer two entries appear under Human Interface Devices in the Device Manager. Clicking into their Properties yields this information in their respective Details tabs:
HID-compliant device
Device Instance Id: HID\VID_1795&PID_6004\7&2694D932&0&0000
USB Human Interface Device
Device Instance Id: USB\VID_1795&PID_6004\B973000000EB0D00
In the WMI Code Creator select these options:
Namespace: root\WMI
Class: MSWmi_PnPInstanceNames
Select InstanceNames from the Results box for the following code:
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class MyWMIQuery
{
public static void Main()
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSWmi_PnPInstanceNames");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSWmi_PnPInstanceNames instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
Here is an example of enumerating Hid devices on Windows:
public static ConnectedDeviceDefinition GetDeviceDefinition(string deviceId, SafeFileHandle safeFileHandle)
{
try
{
var hidAttributes = GetHidAttributes(safeFileHandle);
var hidCollectionCapabilities = GetHidCapabilities(safeFileHandle);
var manufacturer = GetManufacturer(safeFileHandle);
var serialNumber = GetSerialNumber(safeFileHandle);
var product = GetProduct(safeFileHandle);
return new ConnectedDeviceDefinition(deviceId)
{
WriteBufferSize = hidCollectionCapabilities.OutputReportByteLength,
ReadBufferSize = hidCollectionCapabilities.InputReportByteLength,
Manufacturer = manufacturer,
ProductName = product,
ProductId = (ushort)hidAttributes.ProductId,
SerialNumber = serialNumber,
Usage = hidCollectionCapabilities.Usage,
UsagePage = hidCollectionCapabilities.UsagePage,
VendorId = (ushort)hidAttributes.VendorId,
VersionNumber = (ushort)hidAttributes.VersionNumber,
DeviceType = DeviceType.Hid
};
}
catch (Exception)
{
return null;
}
}
Full class here: https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Hid.Net/Windows/WindowsHidDeviceFactory.cs
API Calls here: https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Hid.Net/Windows/HidAPICalls.cs
Here is a similar thing for Windows 10 (UWP):
public async Task<IEnumerable<ConnectedDeviceDefinition>> GetConnectedDeviceDefinitions(FilterDeviceDefinition deviceDefinition)
{
var aqsFilter = GetAqsFilter(deviceDefinition.VendorId, deviceDefinition.ProductId);
var deviceInformationCollection = await wde.DeviceInformation.FindAllAsync(aqsFilter).AsTask();
var deviceDefinitions = deviceInformationCollection.Select(d => GetDeviceInformation(d, DeviceType));
var deviceDefinitionList = new List<ConnectedDeviceDefinition>();
foreach (var deviceDef in deviceDefinitions)
{
var connectionInformation = await TestConnection(deviceDef.DeviceId);
if (connectionInformation.CanConnect)
{
await Task.Delay(1000);
deviceDef.UsagePage = connectionInformation.UsagePage;
deviceDefinitionList.Add(deviceDef);
}
}
return deviceDefinitionList;
}
Code:https://github.com/MelbourneDeveloper/Device.Net/blob/77439b1ab0f4b3ad97376e4e62c7efac0a749783/src/Device.Net.UWP/UWPDeviceFactoryBase.cs#L47
Android (https://github.com/MelbourneDeveloper/Device.Net/blob/77439b1ab0f4b3ad97376e4e62c7efac0a749783/src/Usb.Net.Android/AndroidUsbDeviceFactory.cs#L31):
public Task<IEnumerable<ConnectedDeviceDefinition>> GetConnectedDeviceDefinitions(FilterDeviceDefinition deviceDefinition)
{
return Task.Run<IEnumerable<ConnectedDeviceDefinition>>(() =>
{
//TODO: Get more details about the device.
return UsbManager.DeviceList.Select(kvp => kvp.Value).Where(d => deviceDefinition.VendorId == d.VendorId && deviceDefinition.ProductId == d.ProductId).Select(GetAndroidDeviceDefinition).ToList();
});
}
Using Hid.Net, you can enumerate devices in the same way on any platform like below. See the full article.
var devices = await DeviceManager.Current.GetConnectedDeviceDefinitions(new FilterDeviceDefinition { VendorId = 0x1209, ProductId = 0x53C1 });
foreach (var device in devices)
{
Debug.WriteLine(device.DeviceId);
}

Categories

Resources