Detecting USB device insertion and removal
- Does anyone know how to extract a usb device's "Friendly Name"?
What I want to do is: I have a usb device, when I plug the device into my computer, I want my program to detect that a new usb device has been inserted and grab the device's "Friendly Name." If the friendly name matches the name of the device, which I have hard coded, call my procedure. Essentially, I do not want to have my procedure called when ANY usb device is inserted, I ONLY want it called when my specific usb device is insterted.
I pretty much have most of the code done. I am able to detect USB device arivals and removal, by overiding the WndProc procedure but I am stuck on retrieving the freindly name of the device that has been inserted.
Here is the code I have so far
using System.Runtime.InteropServices;
private const int WM_DEVICECHANGE = 0x0219; // device change eventprivate const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device private const int DBT_DEVICEREMOVEPENDING = 0x8003; // about to remove, still available private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // device is gone private const int DBT_DEVTYP_PORT = 0x00000003; // serial, parallel protected override void WndProc(ref Message m) { int devType; base.WndProc(ref m); switch (m.WParam.ToInt32()) { case DBT_DEVICEARRIVAL: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device inserted, // get the friendly name of the new device // if the friendly name matches my device name, // call my procedure for new device } break; case DBT_DEVICEREMOVECOMPLETE: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device removed, // get the friendly name of the device removed // if the friendly name matches my device name, // call my procedure for removed device } break; } } Can anyone offer any suggestions?
Answers
I have very little experience overriding WndProc. OK, I've never done it...
What I would try is to define "OnDeviceArrival" and "OnDeviceRemoval" functions, and BeginInvoke them from WndProc. This will allow WndProc to return quickly after queueing the callback functions.
-Steve
- Marked As Answer byLingzhi SunMSFT, ModeratorMonday, February 02, 2009 1:08 AM
- I set this aside for a bit to work on other things. I finally got back to it and what Stephen Cleary suggested is the solution. Here's the code:
using System.Management; using System.Management.Instrumentation; using System.Runtime.InteropServices; private const int WM_DEVICECHANGE = 0x0219; // device change event private const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device private const int DBT_DEVICEREMOVEPENDING = 0x8003; // about to remove, still available private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // device is gone private const int DBT_DEVTYP_PORT = 0x00000003; // serial, parallel //delegate enables asynchronous call for getting the list of friendly names private getFriendlyNameListDelegate mDeleg; protected override void WndProc(ref Message m) { int devType; base.WndProc(ref m); switch (m.WParam.ToInt32()) { case DBT_DEVICEARRIVAL: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device inserted, call the query mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList); AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback); // invoke the thread that will handle getting the friendly names mDeleg.BeginInvoke(callback, new object()); } break; case DBT_DEVICEREMOVECOMPLETE: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device removed, call the query mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList); AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback); // invoke the thread that will handle getting the friendly names mDeleg.BeginInvoke(callback, new object()); } break; } } // function queries the system using WMI and gets an arraylist of all com port devices private ArrayList getFriendlyNameList() { ArrayList deviceList = new ArrayList(); // getting a list of all available com port devices and their friendly names // must add System.Management DLL resource to solution before using this // Project -> Add Reference -> .Net tab, choose System.Management // source: // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity"); foreach (ManagementObject devices in searcher.Get()) { string name = devices.GetPropertyValue("Name").ToString(); // only add item if the friendly names contains "COM" // we only want to add COM Ports if (name.Contains("(COM")) { deviceList.Add(name); } } searcher.Dispose(); return deviceList; } // delegate wrapper function for the getFriendlyNameList function private delegate ArrayList getFriendlyNameListDelegate(); // callback method when the thread returns private void getFriendlyNameListCallback(IAsyncResult ar) { // got the returned arrayList, now we can do whatever with it ArrayList result = mDeleg.EndInvoke(ar); }
As Steve suggested, I had to create a delegate to handle the rereshing of the Friendly Name list. Whenever an OnDeviceArrival or OnDeviceRemoval message is trapped, check if the device is a port. If it is, then call the delegated function to invoke a thread to handle getting the updated list if port device friendly names.
The following site helped me out alot on how to use delegates and callback functions.
http://progtutorials.tripod.com/C_Sharp.htm#_Toc65227886- Marked As Answer bywlo413 Wednesday, February 04, 2009 6:34 PM
All Replies
hi wlo413 , i was searching how to deal with USB in C# so can you tell me what is your reference in this or you could explain to me how to detect it and deal with it , "Couldn't understand so much of the code above" -- "BEGINNER :D".
Thanks.
To Be The BestWell, the easiest way would probably be to use WMI, if you know the type of device you're looking for. It is probably possible to do the same with SetupAPI.
If WMI doesn't work and you don't want to mess with the P/Invoke necessary for SetupAPI, you can check out the FriendlyName values under subkeys of HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum. I don't recommend this practice, but it's the way the famous deveject program works.
-Steve
Salaam Aliakmon
here a sample code on code project you can use it
the programmer here detected the usb and get its drive name, and by knowing the drive name ( C:, D: or ... H: ) then you can easily know the caption of this drive.
Best Regards- Hello Monah
I have taken a look at the code found on code project already. Unfortunately, my application is slightly different. The USB device I'm querying is not a mass storage device, its actually a port device. So when I plug it in, Windows assigns a virtual com port number for the usb device.
For example, when the usb device is plugged in, and I take a look at the Windows Device Manager. Under Ports(COM & LPT1), I will see the name of the usb device and the com port it is on. It is this name, I believe is called a Friendly Name, that I want my code to get.
As Stephen Cleary posted earlier, I might have to try using the WMI, although I haven't worked with it before and not quite sure how to go about doing it.
I have simple source code that uses ManagementObject and friends to query WMI at http://code.msdn.microsoft.com/NitoWMI.
On my system, the Win32_SerialPort class has Description (a friendly name), DeviceID (the actual com port name which can be passed to CreateFile), and PNPDeviceID (the unique PNP ID) all with useful values.
However, I just read MSDN on DBT_DEVICEARRIVAL, and it should be giving you the friendly name already. You just have to pull it out of the structure that's passed to WndProc.
-Steve
- Hello Steve
I'm just reading the MSDN documentation for DBT_DEVICEARRIVAL, you're right about the structure being passed into WndProc. However, I can't seem to find any further documentation on what the struct contains for fields.
MSND lists this:
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_DEVICECHANGE
WPARAM wParam, // device-change event
LPARAM lParam // event-specific data
);
I am assuming I use the LPARAM, which looks like an IntPtr to a another struct, but I can't seem to find anything on what this struct's fields are. Even if the Friendly Name is stored in this struct, I'm uncertain how to extract it at the moment.Gonna keep looking though.
- It looks like I was able to get a list of all the connected port devices, including their friendly names, through WMI.
I made a separate function that queries the system's connected Com Port devices, then place the results in an arraylist. In my WndProc, whenever a a DBT_DEVICEARRIVAL or DBT_DEVICEREMOVEDCOMPLETE messages are caught, I will call this function that returns an arrayList of conncected Com Port devices.
The problem I am getting now is a unhandled ManagementException, The Application called an interface that was marshalled for a different thread. This occurs when the query is made within the WndProc.
Here's my code so far:
My getFriendlyName function works when I link it to an a button eventHandler, it only throws the ManagementException when it is called from within WndProc. MSDN also provides very little information on this type of exception.using System.Management; using System.Management.Instrumentation; using System.Runtime.InteropServices; private const int WM_DEVICECHANGE = 0x0219; // device change event private const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device private const int DBT_DEVICEREMOVEPENDING = 0x8003; // about to remove, still available private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // device is gone private const int DBT_DEVTYP_PORT = 0x00000003; // serial, parallel protected override void WndProc(ref Message m) { int devType; base.WndProc(ref m); switch (m.WParam.ToInt32()) { case DBT_DEVICEARRIVAL: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device inserted, call the query ArrayList myList = getFriendlyNameList(); } break; case DBT_DEVICEREMOVECOMPLETE: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device removed, call the query ArrayList myList = getFriendlyNameList(); } break; } } private ArrayList getFriendlyNameList() { ArrayList deviceList = new ArrayList(); // getting a list of all available com port devices and their friendly names // must add System.Management DLL resource to solution before using this // Project -> Add Reference -> .Net tab, choose System.Management // source: // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity"); foreach (ManagementObject devices in searcher.Get()) { string name = devices.GetPropertyValue("Name").ToString(); // only add item if the friendly names contains "COM" // we only want to add COM Ports if (name.Contains("(COM")) { deviceList.Add(name); } } searcher.Dispose(); return deviceList; I have very little experience overriding WndProc. OK, I've never done it...
What I would try is to define "OnDeviceArrival" and "OnDeviceRemoval" functions, and BeginInvoke them from WndProc. This will allow WndProc to return quickly after queueing the callback functions.
-Steve
- Marked As Answer byLingzhi SunMSFT, ModeratorMonday, February 02, 2009 1:08 AM
- I set this aside for a bit to work on other things. I finally got back to it and what Stephen Cleary suggested is the solution. Here's the code:
using System.Management; using System.Management.Instrumentation; using System.Runtime.InteropServices; private const int WM_DEVICECHANGE = 0x0219; // device change event private const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device private const int DBT_DEVICEREMOVEPENDING = 0x8003; // about to remove, still available private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // device is gone private const int DBT_DEVTYP_PORT = 0x00000003; // serial, parallel //delegate enables asynchronous call for getting the list of friendly names private getFriendlyNameListDelegate mDeleg; protected override void WndProc(ref Message m) { int devType; base.WndProc(ref m); switch (m.WParam.ToInt32()) { case DBT_DEVICEARRIVAL: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device inserted, call the query mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList); AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback); // invoke the thread that will handle getting the friendly names mDeleg.BeginInvoke(callback, new object()); } break; case DBT_DEVICEREMOVECOMPLETE: devType = Marshal.ReadInt32(m.LParam, 4); if (devType == DBT_DEVTYP_PORT) { // usb device removed, call the query mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList); AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback); // invoke the thread that will handle getting the friendly names mDeleg.BeginInvoke(callback, new object()); } break; } } // function queries the system using WMI and gets an arraylist of all com port devices private ArrayList getFriendlyNameList() { ArrayList deviceList = new ArrayList(); // getting a list of all available com port devices and their friendly names // must add System.Management DLL resource to solution before using this // Project -> Add Reference -> .Net tab, choose System.Management // source: // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity"); foreach (ManagementObject devices in searcher.Get()) { string name = devices.GetPropertyValue("Name").ToString(); // only add item if the friendly names contains "COM" // we only want to add COM Ports if (name.Contains("(COM")) { deviceList.Add(name); } } searcher.Dispose(); return deviceList; } // delegate wrapper function for the getFriendlyNameList function private delegate ArrayList getFriendlyNameListDelegate(); // callback method when the thread returns private void getFriendlyNameListCallback(IAsyncResult ar) { // got the returned arrayList, now we can do whatever with it ArrayList result = mDeleg.EndInvoke(ar); }
As Steve suggested, I had to create a delegate to handle the rereshing of the Friendly Name list. Whenever an OnDeviceArrival or OnDeviceRemoval message is trapped, check if the device is a port. If it is, then call the delegated function to invoke a thread to handle getting the updated list if port device friendly names.
The following site helped me out alot on how to use delegates and callback functions.
http://progtutorials.tripod.com/C_Sharp.htm#_Toc65227886- Marked As Answer bywlo413 Wednesday, February 04, 2009 6:34 PM

