I want to detect when the user plugs in or removes a USB sound card. I've managed to actually catch the event when this happens, but I can't tell what just got plugged in.
I tried an approach based on this question:
string query =
"SELECT * FROM __InstanceCreationEvent " +
"WITHIN 2 "
+ "WHERE TargetInstance ISA 'Win32_PnPEntity'";
var watcher = new ManagementEventWatcher(query);
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Start();
While I get the notifications via the EventArrived event, I have no idea how to determine the actual name of the device that just got plugged in. I've gone through every property and couldn't make heads or tails out of it.
I also tried a different query:
var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent where EventType = 1 or EventType = 2");
var watcher = new ManagementEventWatcher(query);
watcher.EventArrived += watcher_EventArrived;
watcher.Stopped += watcher_Stopped;
watcher.Query = query;
watcher.Start();
but also to no avail. Is there a way to find the name of the device that got plugged in or removed.
The bottom line is that I'd like to know when a USB sound card is plugged in or removed from the system. It should work on Windows 7 and Vista (though I will settle for Win7 only).
EDIT: Based on the suggestions by the winning submitter, I've created a full solution that wraps all the functionality.
If I use your first code, I can define my event like this:
// define USB class guid (from devguid.h)
static readonly Guid GUID_DEVCLASS_USB = new Guid("{36fc9e60-c465-11cf-8056-444553540000}");
static void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject )e.NewEvent["TargetInstance"];
if (new Guid((string)instance["ClassGuid"]) == GUID_DEVCLASS_USB)
{
// we're only interested by USB devices, dump all props
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
}
And this will dump something like this:
Availability =
Caption = USB Mass Storage Device
ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}
CompatibleID = System.String[]
ConfigManagerErrorCode = 0
ConfigManagerUserConfig = False
CreationClassName = Win32_PnPEntity
Description = USB Mass Storage Device
DeviceID = USB\VID_18A5&PID_0243\07072BE66DD78609
ErrorCleared =
ErrorDescription =
HardwareID = System.String[]
InstallDate =
LastErrorCode =
Manufacturer = Compatible USB storage device
Name = USB Mass Storage Device
PNPDeviceID = USB\VID_18A5&PID_0243\07072BE66DD78609
PowerManagementCapabilities =
PowerManagementSupported =
Service = USBSTOR
Status = OK
StatusInfo =
SystemCreationClassName = Win32_ComputerSystem
SystemName = KILROY_WAS_HERE
This should contain everything you need, including the device ID that you can get with something like instance["DeviceID"].
EDIT 1: Oh is see that it is not a USB storage device but only a USB device. I will look for another solution.
Two links that describe the same problem:
http://hintdesk.com/c-catch-usb-plug-and-unplug-event/
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/37123526-83fa-4e96-a767-715fe225bf28/
if (e.NewEvent.ClassPath.ClassName == "__InstanceCreationEvent")
{
Console.WriteLine("USB was plugged in");
//Get disk letter
foreach (ManagementObject partition in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + mbo.Properties["DeviceID"].Value
+ "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
{
foreach (ManagementObject disk in new ManagementObjectSearcher(
"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='"
+ partition["DeviceID"]
+ "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
{
Console.WriteLine("Disk=" + disk["Name"]);
}
}
}
When I tried #AngryHacker solution, I noticed that the DeviceChangedEventArgs class did not ever get called, though. I removed it and just added Console.WriteLines() in the watcher_eventArrived methods.
Besides the deletion of the DeviceChangedEventArgs, here are my changes:
(at line 46 in EstablishedWatchEvents)
// setup the query to monitor removal
const string qryRemoval = "SELECT *" + "FROM __InstanceDeletionEvent "
+ "WITHIN 2 " + "WHERE TargetInstance ISA 'Win32_PnPEntity' ";
#region Events
private void insertWatcher_EventArrived(object sender, EventArrivedEventArgs e)
{
var mbo = (ManagementBaseObject) e.NewEvent["TargetInstance"];
if (new Guid((string) mbo["ClassGuid"]) == GUID_DEVCLASS_USB)
{
var deviceName = (string) mbo["Name"];
Console.WriteLine(deviceName + " was inserted");
}
}
private void removeWatcher_EventArrived(object sender, EventArrivedEventArgs e)
{
var mbo = (ManagementBaseObject)e.NewEvent["TargetInstance"];
if (new Guid((string)mbo["ClassGuid"]) == GUID_DEVCLASS_USB)
{
var deviceName = (string)mbo["Name"];
Console.WriteLine(deviceName + " was removed");
}
}
#endregion
Related
I am trying to show the vid/pid and the drive letter of a usb drive when I connect it to my computer. I'm actually able to do both, but not at the same time.
1: I can use Win32_DiskDrive to get to Win32_LogicalDisk and extract the drive letter. But the deviceId has a non-numerical pid/vid which I can't use.
2: I can use Win32_USBHub or Win32_PnPEntity to extract the vid/pid, but I can't find a link between them and the drive letter.
public void CheckForUsbDevice()
{
string text =
"SELECT * FROM __InstanceCreationEvent " +
"WITHIN 2 "
+ "WHERE TargetInstance ISA 'Win32_PnPEntity'";
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery(text);
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
Console.ReadKey();
}
static readonly Guid GUID_DEVCLASS_USB = new Guid("{36fc9e60-c465-11cf-8056-444553540000}");
static void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
if ((new Guid((string)instance["ClassGuid"]) == GUID_DEVCLASS_USB) && ((string)instance.Properties["Name"].Value == "USB Mass Storage Device"))
{
// we're only interested by USB devices, dump all props
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
}
This has the output:
Availability =
Caption = USB Mass Storage Device
ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}
CompatibleID = System.String[]
ConfigManagerErrorCode = 0
ConfigManagerUserConfig = False
CreationClassName = Win32_PnPEntity
Description = USB Mass Storage Device
DeviceID = USB\VID_0911&PID_1F40&MI_00\6&27CAD51B&0&0000
ErrorCleared =
ErrorDescription =
HardwareID = System.String[]
InstallDate =
LastErrorCode =
Manufacturer = Compatible USB storage device
Name = USB Mass Storage Device
PNPClass = USB
PNPDeviceID = USB\VID_0911&PID_1F40&MI_00\6&27CAD51B&0&0000
PowerManagementCapabilities =
PowerManagementSupported =
Present = True
Service = USBSTOR
Status = OK
StatusInfo =
SystemCreationClassName = Win32_ComputerSystem
SystemName = WINDEV1905EVAL
I need a link between WMI classed containing the numerical pid/vid and the drive letter or a different way how that can be achieved.
I think it might be possible to use DeviceIoControl, but I have no idea where to start there.
Any help is highly appreciated.
For a couple of days, I have puzzled about how to do this in the best way possible. I created a form application like so:
I gave the name "WiFi Hacker" for giggles. But my question is, why does Visual Studio give me this error after a couple minutes using the program?
Additional information: Type 'NativeWifi.Wlan+WlanReasonCode' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
I am using NativeWifi for my program, and the code for logging networks is as follows:
WlanClient client = new WlanClient();
private void wifilister()
{
foreach (WlanClient.WlanInterface wI in client.Interfaces)
{
foreach (Wlan.WlanAvailableNetwork network in wI.GetAvailableNetworkList(0))
{
Wlan.Dot11Ssid ssid = network.dot11Ssid;
string networkName = Encoding.ASCII.GetString(ssid.SSID, 0, (int)ssid.SSIDLength);
if (wifis.Contains(networkName) == false)
{
//Name
ListViewItem item = new ListViewItem(networkName);
wifis.Add(networkName);
listBox1.Items.Add(networkName);
//Encryption Type
item.SubItems.Add(network.dot11DefaultCipherAlgorithm.ToString());
wifis.Add(network.dot11DefaultCipherAlgorithm.ToString());
//Signal
item.SubItems.Add(network.wlanSignalQuality + "%");
wifis.Add(network.wlanSignalQuality + "%");
//Logged Time
item.SubItems.Add(DateTime.Now.ToString("T"));
wifis.Add(DateTime.Now.ToString("T"));
listView1.Items.Add(item);
label2.Text = "Networks: " + (wifis.Count / 4).ToString();
}
if (checkBox2.Checked)
{
label1.Text = track;
if (Encoding.ASCII.GetString(ssid.SSID, 0, (int)ssid.SSIDLength) == track)
{
label1.Text += " " + network.wlanSignalQuality + "%";
}
}
}
}
I got most of this off a tutorial from YouTube, but after it logs more than about 40 different networks in the List, it seems to give that weird error about
'NativeWifi.Wlan+WlanReasonCode'.
This annoyed me, is there a way around it?
I'm querying to Win32_PrintJob WMI class every time there is a change with ManagementEventWatcher, I obtained data about it, such as: Document, HostPrintQueue, JobId, JobStatus, TotalPages, etc. But TotalPages is not representing the real number of page to print, Seems at the moment to obtain these data still the printjob doesn't finished to process and devolving a number of pages to print in that moment but the real total is other number, How to get the real number of a print job when finished it to process?
Here is my code:
ManagementEventWatcher createPrintJobWatcher;
String strComputerName = ".";
// Create event query to be notified within 1 milli second of a change in a service
WqlEventQuery createPrintJobQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 0.001 WHERE TargetInstance ISA \"Win32_PrintJob\"");
createPrintJobWatcher = new ManagementEventWatcher();
createPrintJobWatcher.Scope = new ManagementScope("\\\\" + strComputerName + "\\root\\CIMV2");
createPrintJobWatcher.Query = createPrintJobQuery;
// times out watcher.WaitForNextEvent in 1 seconds
createPrintJobWatcher.Options.Timeout = new TimeSpan(0, 0, 1);
//set the print event handler
createPrintJobWatcher.EventArrived += new EventArrivedEventHandler(createPrintJobListener);
createPrintJobWatcher.Start();
Console.WriteLine("Listening...");
Console.ReadLine();
createPrintJobListener method:
static void createPrintJobListener(object sender, EventArrivedEventArgs e)
{
SelectQuery query = new SelectQuery("Win32_PrintJob");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
using (ManagementObjectCollection printJobs = searcher.Get())
foreach (ManagementObject printJob in printJobs)
{
Console.WriteLine("c1:", printJob);
Console.WriteLine("ID: {0}", printJob.GetPropertyValue("JobId").ToString());
Console.WriteLine("name: {0}", printJob.GetPropertyValue("name").ToString());
Console.WriteLine("status: {0}", printJob.GetPropertyValue("status").ToString());
if (printJob.GetPropertyValue("JobStatus") != null)
{
Console.WriteLine("JobStatus: {0}", printJob.GetPropertyValue("JobStatus").ToString());
}
else
{
Console.WriteLine("JobStatus: NULLLLLL");
}
Console.WriteLine("PC: {0}", printJob.GetPropertyValue("HostPrintQueue").ToString());
Console.WriteLine("TOTOAL PAGES: {0}", printJob.GetPropertyValue("TotalPages").ToString());
}
}
WMI is probably not sufficient to do this.
Windows doesn't reliably provide the page count (or copies etc), so the only way to get accurate info is to pause the job and parse it. This is a non-trivial task, but here's a little more info.
I'm trying to find a particular USB device (1 or more) connected to my computer and retrieve the relevant path to the mounted drive. Ideally, it would be by finding the VID/PID of the USB device, but I'm not sure how to do that yet. The following works, but there must be some way to get the data in a single query.
What I'm doing here is looking or a physical drive that has a model matching HS SD Card Bridge USB Device and finding the physical drive # associated and using that to find the mounted partition..
foreach (ManagementObject disk in disks.Get()) {
//look for drives that match our string
Match m = Regex.Match(disk["model"].ToString(), "HS SD Card Bridge USB Device");
if (m.Success) {
m = Regex.Match(disk["DeviceID"].ToString(), #"PHYSICALDRIVE(\d+)");
if (m.Success) {
int driveNumber = Int32.Parse(m.Groups[1].ToString());
ManagementObjectSearcher mapping = new ManagementObjectSearcher("SELECT * FROM Win32_LogicalDiskToPartition");
foreach (ManagementObject map in mapping.Get()) {
m = Regex.Match(map["Antecedent"].ToString(), #"Disk #" + driveNumber + ",");
if (m.Success) {
string drive = map["Dependent"].ToString();
m = Regex.Match(drive, #"([A-Z]):");
if (m.Success) {
drive = m.Groups[1].ToString(); //< -- **FOUND**
}
}
}
//USBDevice dev = new USBDevice("", "");
// list.Items.Add();
Console.WriteLine("");
}
}
}
is there a way to do this from the VID/PID and a way to construct the search query so it requires just one query?
This is the one I used earlier . This will not be the answer. But will help you .
public int GetAvailableDisks()
{
int deviceFound = 0;
try
{
// browse all USB WMI physical disks
foreach (ManagementObject drive in
new ManagementObjectSearcher(
"select DeviceID, Model from Win32_DiskDrive where InterfaceType='USB'").Get())
{
ManagementObject partition = new ManagementObjectSearcher(String.Format(
"associators of {{Win32_DiskDrive.DeviceID='{0}'}} where AssocClass = Win32_DiskDriveToDiskPartition",
drive["DeviceID"])).First();
if (partition == null) continue;
// associate partitions with logical disks (drive letter volumes)
ManagementObject logical = new ManagementObjectSearcher(String.Format(
"associators of {{Win32_DiskPartition.DeviceID='{0}'}} where AssocClass = Win32_LogicalDiskToPartition",
partition["DeviceID"])).First();
if (logical != null)
{
// finally find the logical disk entry to determine the volume name - Not necesssary
//ManagementObject volume = new ManagementObjectSearcher(String.Format(
// "select FreeSpace, Size, VolumeName from Win32_LogicalDisk where Name='{0}'",
// logical["Name"])).First();
string temp = logical["Name"].ToString() + "\\";
// +" " + volume["VolumeName"].ToString(); Future purpose if Device Name required
deviceFound++;
if (deviceFound > 1)
{
MessageBox.Show(#"Multiple Removeable media found. Please remove the another device");
deviceFound--;
}
else
{
driveName = temp;
}
}
}
}
catch (Exception diskEnumerateException)
{
}
return deviceFound;
}
How can view logical memory configuration ?
private void button1_Click(object sender, EventArgs e)
{
ObjectQuery winQuery = new ObjectQuery("SELECT * FROM Win32_LogicalMemoryConfiguration");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(winQuery);
foreach (ManagementObject item in searcher.Get())
{
textBox1.Text =("Total Space = " + item["TotalPageFileSpace"]);
textBox2.Text = ("Total Physical Memory = " + item["TotalPhysicalMemory"]);
textBox3.Text = ("Total Virtual Memory = " + item["TotalVirtualMemory"]);
textBox4.Text = ("Available Virtual Memory = " + item["AvailableVirtualMemory"]);
}
}
In this code seems doesn't work . And has no error on compilation .
According to Microsoft
The Win32_LogicalMemoryConfiguration WMI class is no longer available for use as of Windows Vista.
The article suggests you use the Win32_OperatingSystem but you might be better off using Process.GetCurrentProcess().