var watcher = new ManagementEventWatcher();
var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2 or EventType = 3");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
private void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
MessageBox.Show("Device Connected or Disconnected");
}
if any device plugged on unplugged in usb port this call back works, but multiple callbacks are cumming, what to to restrict with single call back ?
any one please help ?
Related
I have two functions. One is for query in WMI for USB devices, and 2nd one is for detect device remove/insertion. Both of them work independently very well. The problem starts when I trying to make the function responsible for detecting devices trigger function responsible for listing devices. Refresh the list when I connect or remove devices. It shows that the application is in "break mode" because of the threads.
I know that I will have to take for example the device detection function and put it to different thread and send for example integer 0/1 when devices are inserted/removed so that will trigger the list function in the GUI thread. The problem is that I have no idea how to do it ;/.
Device list code:
private void button1_Click(object sender, EventArgs e)
{
listView1.Items.Clear();
ManagementObjectSearcher s =
new ManagementObjectSearcher("root\\CIMV2", #"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%""");
try
{
foreach (ManagementObject device in s.Get())
{
string Name = device.GetPropertyValue("Name").ToString();
ListViewItem items = new ListViewItem(Name);
string Description = device.GetPropertyValue("Description").ToString();
items.SubItems.Add(Description);
string Caption = device.GetPropertyValue("Caption").ToString();
items.SubItems.Add(Caption);
string PNPDeviceID = device.GetPropertyValue("PNPDeviceID").ToString();
items.SubItems.Add(PNPDeviceID);
string DeviceID = device.GetPropertyValue("DeviceID").ToString();
items.SubItems.Add(DeviceID);
string Service = device.GetPropertyValue("Service").ToString();
items.SubItems.Add(Service);
string Status = device.GetPropertyValue("Status").ToString();
items.SubItems.Add(Status);
string Manufacturer = device.GetPropertyValue("Manufacturer").ToString();
items.SubItems.Add(Manufacturer);
Boolean zmienna6 = (Boolean)device.GetPropertyValue("ConfigManagerUserConfig");
string ConfigManagerUserConfig = zmienna6.ToString();
items.SubItems.Add(ConfigManagerUserConfig);
/// string zmienna7 = (String)device.GetPropertyValue("ProtocolCode");
listView1.Items.Add(items);
}
}
catch (ManagementException ex)
{
MessageBox.Show("An error occurred while querying for WMI data: " + ex.Message);
}
Function for detecting devices:
private void Form1_Load(object sender, EventArgs e)
{
bgwDriveDetector.DoWork += bgwDriveDetector_DoWork;
bgwDriveDetector.RunWorkerAsync();
}
/// detection of the device con or discon
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
/// send intiger or string 1
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
/// send intiger or string 0
}
void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e)
{
var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += DeviceInsertedEvent;
insertWatcher.Start();
var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
var removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += DeviceRemovedEvent;
removeWatcher.Start();
}
I am trying to implement the code from the following link: Detecting USB drive insertion and removal using windows service and c#
I think the issue I am having is that my main UI thread isn't being notified by the background thread when the device is inserted or removed. I verified this by not being able to update the content of a label in my user control.
I have included my source code below:
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
MessageBox.Show(property.Name + " = " + property.Value); // Dialog box appears as expected.
StatusMessage.Content = $"{property.Name} = {property.Value}";
}
StatusMessage.Content = "Removable Drive detected!"; //label content should be updated here, and for some reason it is not.
bool isDriveRemoved = FindRemovableDrive(); //get the drive info
if (isDriveRemoved || Count > 0)
{
Count = 0;
}
else
{
Count++;
}
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
MessageBox.Show(property.Name + " = " + property.Value); // Dialog box appears as expected, but label is not updated.
}
StatusMessage.Content = $"{property.Name} = {property.Value}";
FileMenu.Items.Clear(); // the file menu should be getting cleared here.
}
private void backgroundWorker1_DoWork(object sender, RoutedEventArgs e)
{
WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += DeviceInsertedEvent;
insertWatcher.Start();
WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += DeviceRemovedEvent;
removeWatcher.Start();
// Do something while waiting for events
//Thread.Sleep(10000);
}
-Any input/solutions would be greatly appreciated.
Thanks for your time,
Michael
Rather than regularly scanning devices you can use a WMI Events to be notified when there is a hardware change.
Starting a listener for plug & play events:
var wmiPath = new ManagementPath(#"root\cimv2");
var scope = new ManagementScope(wmiPath);
scope.Connect();
var instanceQuery = new WqlEventQuery("__InstanceOperationEvent",
new TimeSpan(0, 0, 1),
"TargetInstance isa \"Win32_PnPEntity\"");
wmiWatcher = new ManagementEventWatcher(scope, instanceQuery);
wmiWatcher.EventArrived += OnInstanceEvent;
wmiWatcher.Start();
The event handler:
private void OnInstanceEvent(object sender, EventArrivedEventArgs ea) {
var eventType = (string)ea.NewEvent["__CLASS"];
var targetWmiObj = ea.NewEvent["TargetInstance"] as ManagementBaseObject;
var deviceId = (string)targetWmiObj["deviceId"];
if (String.Equals("__InstanceCreationEvent", (string)ea.NewEvent["__CLASS"], StringComparison.Ordinal)) {
if (/* Filter on the device id for what is interesting here*/) {
// Handle relevant device arriving
}
}
}
There are other values of NewEvent["__CLASS"] for other event types (including device removal).
PS. This is (partial) code from a WinForms app that monitored for a specialised device being plagged in and then downloaded/uploaded data from it. All the work was done in the thread pool: everything here should just work under WPF.
I am first time using BackGroundWorker and EventHandler. I dont know if I am doing it correctly or not. I want to search for USB devices connected (just which have certain VID & PID). Because by debugging program dont want to go inside bw_worker_dowork loop.
I also using WPF with MVVM method - for info.
Please for help. I am doing it correctly or not?
BackgroundWorker bw_worker;
USBmiddleware cs = new USBmiddleware();
public Windows1ViewModel()
{
bw_worker = new BackgroundWorker();
bw_worker.DoWork += new DoWorkEventHandler(bw_worker_dowork);
bw_worker.WorkerReportsProgress = true;
bw_worker.WorkerReportsProgress = true;
}
void bw_worker_dowork(object sender, DoWorkEventArgs e)
{
WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
insertWatcher.Start();
WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent);
removeWatcher.Start();
// Do something while waiting for events
System.Threading.Thread.Sleep(20000000);
}
void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
cs.FindDevices();
}
void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
cs.FindDevices();
}
You didn't start your BackgroundWorker !
BackgroundWorker.RunWorkerAsync Method
Sorry. Problem was there:
Before:
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'"
Now:
"SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"
Before was working only on my USB Headset, now working also for my other device :) Sorry.
i'm tryin' to read the content of the packets that i've captured with SharpPCap.
This is my little code
private void button4_Click(object sender, EventArgs e)
{
// Retrieve the device list
var devices = LibPcapLiveDeviceList.Instance;
// Extract a device from the list
var device = devices[1];
// Register our handler function to the
// 'packet arrival' event
device.OnPacketArrival +=
new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
// Open the device for capturing
int readTimeoutMilliseconds = 1000;
if (device is AirPcapDevice)
{
// NOTE: AirPcap devices cannot disable local capture
var airPcap = device as AirPcapDevice;
airPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp, readTimeoutMilliseconds);
}
else if (device is WinPcapDevice)
{
var winPcap = device as WinPcapDevice;
winPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp | SharpPcap.WinPcap.OpenFlags.NoCaptureLocal, readTimeoutMilliseconds);
}
else if (device is LibPcapLiveDevice)
{
var livePcapDevice = device as LibPcapLiveDevice;
livePcapDevice.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
}
else
{
throw new System.InvalidOperationException("unknown device type of " + device.GetType().ToString());
}
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
device.StartCapture();
MessageBox.Show("-- Listening on {0}, hit 'Enter' to stop...",
device.Description);
// Stop the capturing process
device.StopCapture();
// Close the pcap device
device.Close();
}
private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
if (e.Packet.LinkLayerType == PacketDotNet.LinkLayers.Ethernet)
{
var packet = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
var ethernetPacket = (PacketDotNet.EthernetPacket)packet;
MessageBox.Show(System.Text.Encoding.ASCII.GetString(e.Packet.Data));
packetIndex++;
}
}
I capture a byte[] packet but i don't know how can i read the whole server response.
thank you for the help
i have a serial port that will iterate through the ports with this method:
foreach (string s in SerialPort.GetPortNames())
{
var serialOneOfMany = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
if (serialOneOfMany.IsOpen)
{
serialOneOfMany.Close();
}
else
{
try
{
serialOneOfMany.Open();
}
catch
{
var openSerial = new System.Timers.Timer(3100);
openSerial.Elapsed += (o, e) =>
{
serialOneOfMany.Open();
openSerial.Enabled = false;
openSerial.Dispose();
};
openSerial.Enabled = true;
}
}
if (serialOneOfMany.IsOpen)
{
string received;
try
{
lblPortNum.Content = s;
lblPortNum.Refresh();
serialOneOfMany.Write(testMessage);
serialOneOfMany.DataReceived += new SerialDataReceivedEventHandler(testSerialPort_DataReceived);
}
catch (TimeoutException e)
{
serialOneOfMany.Close();
continue;
}
}
}
so, i want to open the port, send it a message, listen for the response, then close it. as everyone knows, every comport found in GetPortNames isn't a valid serial port. so, what i've been doing is setting a timer with a dispatcher timer:
DispatcherTimer time = new DispatcherTimer();
time.Interval = TimeSpan.FromMilliseconds(3000);
time.Tick += new EventHandler(someEventHandler);
time.Start();
here's the other method handled here:
private void someEventHandler(Object sender, EventArgs args)
{
SerialPort serial = (SerialPort)sender;
if (serial.IsOpen)
serial.Close();
serial.Dispose();
//if you want this event handler executed for just once
DispatcherTimer thisTimer = (DispatcherTimer)sender;
thisTimer.Stop();
}
so, it'll open the com port, if it doesn't get a response within 3 seconds, it will close the port. the problem i'm having is that the foreach loop will just barrel through the code and open the comport several times, i'll get a message saying The COM Port is open already and can't be used. so basically it's not pausing in openSerial.
i want it to open a new serial port, and if it's not accessible, wait 3100 milliseconds and try again. how do i do that?
UPDATED CODE:
private void button1_Click(object sender, RoutedEventArgs e)
{
CheckPorts();
}
private void checkPorts()
{
SendMessage("messageToDevice1", 19200);
SendMessage("Message2", 9600);
}
private void SendMessage(string testMessage, int baudRate)
{
int baudRate = 9600;
string testMessage = "test";
txtPortName.Text = "Testing all serial ports";
foreach (string s in SerialPort.GetPortNames())
{
SerialPort newPort = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
if (!newPort.IsOpen)
{
try
{
newPort.Open();
}
catch { }
}
if (newPort.IsOpen)
{
openPorts.Add(newPort);
newPort.Write(testMessage);
newPort.DataReceived += new SerialDataReceivedEventHandler(serialOneOfMany_DataReceived);
}
else
{
newPort.Dispose();
}
}
txtPortName.Text = "Waiting for response";
tmrPortTest.Enabled = true;
}
my new problem is that it just blows through the com ports, i need it to stop for each one, take a second to listen, then close it. it just blows through the foreach loop.
now, the reason why i don't just open up the port and keep it open through all the messages is that my devices have different baud rates, and i can't adjust them to all match. so, i need to open the ports, then send messages, listen, if they don't respond to the first round of messages, then open them up at the new baudrate and send a new batch of messages. but the foreachloop doens't pause for me to listen.
I think this more or less agrees with rare's answer. The port where you receive a response (you would probably want to check the response as well) will remain open and all the others should close.
private List<SerialPort> openPorts = new List<SerialPort>();
private void button3_Click(object sender, EventArgs e)
{
int baudRate = 9600;
string testMessage = "test";
txtPortName.Text = "Testing all serial ports";
foreach (string s in SerialPort.GetPortNames())
{
SerialPort newPort = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
if (!newPort.IsOpen)
{
try
{
newPort.Open();
}
catch { }
}
if (newPort.IsOpen)
{
openPorts.Add(newPort);
newPort.Write(testMessage);
newPort.DataReceived += new SerialDataReceivedEventHandler(serialOneOfMany_DataReceived);
}
else
{
newPort.Dispose();
}
}
txtPortName.Text = "Waiting for response";
tmrPortTest.Enabled = true;
}
private void serialOneOfMany_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
txtPortName.Text = ((SerialPort)sender).PortName;
}
private void tmrPortTest_Tick(object sender, EventArgs e)
{
tmrPortTest.Enabled = false;
foreach (SerialPort port in openPorts)
{
if (port.PortName != txtPortName.Text)
{
port.Close();
port.Dispose();
}
}
}
Here's how I would do this --
First, try to open all the serial ports. The ones that actually do open are put in a list.
Assign all serial ports in the list to the same DataReceived event handler. The event handler is where you will save the port name (it's in the args) and kill the timer if you rx'd the response
Send your testMessage out all the open ports
Set just one timer for 3.1 seconds
Close the ports once the timer fires or the event handler rx's the response.