none
RegisterDeviceNotification in WPF

    Question

  • Hi all,

     

    I am writing a C# class library for a WPF application. The class library should raise an event whenever some USB device is plugged in/plugged out.

     

    I am registering the USB devices, using RegisterRawInputDevices API and I am able to process WM_Input messages in the library.

     

    I am also able to get WM_DEVICECHANGE messages. But the values of WParam is always 7 whereas I am hoping to get

    DBT_DEVICEARRIVAL = 0x8000 or DBT_DEVICEREMOVECOMPLETE = 0x8004

     

    I referred to an example from http://www.dotnet247.com/247reference/msgs/32/164968.aspx(window application example).

     

    It talks about using RegisterDeviceNotification() method. This method needs a handle.

    I am passing the current window handle of the WPF application using

     

    System.Windows.Interop.WindowInteropHelper temp = new WindowInteropHelper(this.currentWindow);

    windowHandle = temp.Handle;

    RegisterDeviceNotification(windowHandle, Buffer, DEVICE_NOTIFY_WINDOW_HANDLE);

     

    However, I am still not able to get DBT_DEVICEARRIVAL/ DBT_DEVICEREMOVECOMPLETE values in WParam in the WM_DEVICECHANGE message?

     

    Any help would be greatly appreciated.

     

    Regards

    Pankaj

     

    Saturday, April 21, 2007 11:41 AM

All replies

  • This code will help you

     

    Code Snippet

    WqlEventQuery _q = new WqlEventQuery("__InstanceOperationEvent", "TargetInstance ISA 'Win32_USBControllerDevice' ");

    _q.WithinInterval = TimeSpan.FromSeconds(1);

    ManagementEventWatcher _w = new ManagementEventWatcher(_q);

    _w.EventArrived += new EventArrivedEventHandler(onEventArrived);

    _w.Start();

     

    void onEventArrived(object sender, EventArrivedEventArgs e)

    {

    ManagementBaseObject _o = e.NewEvent["TargetInstance"] as ManagementBaseObject;

    if (_o != null)

    {

    using (ManagementObject mo = new ManagementObject(_o["Dependent"].ToString()))

    {

    if (mo != null)

    {

    try

    {

    if(mo.GetPropertyValue("DeviceID").ToString() != string.Empty)

    {

    //connected

    }

    }

    catch (ManagementException ex)

    {

    //disconnected

    }

    }

    }

    }

    }

     

    • Proposed as answer by Omar Elsherif Monday, July 23, 2012 11:36 PM
    Sunday, April 22, 2007 2:44 PM
  • Hi Tamir,

     

    Thanks for your reply !

    The approach you suggested uses ManagementEventWatcher.

     

    Is there any way by which I can RegisterDeviceNotification () API and process DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE in WPF?

    This is working fine in Windows application (http://www.dotnet247.com/247reference/msgs/32/164968.aspx)

     

    What is it, that needs to be done to get this working in C# class library, in addition what I have done in post 1 ?

     

    Regards

    Pankaj

    Sunday, April 22, 2007 3:03 PM
  • In order to get current window handle use following (Win32 class is the same as in the sample within your link)

     

    Code Snippet

    protected override void OnSourceInitialized(EventArgs e)

    {

    base.OnSourceInitialized(e);

    HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;

    if (hwndSource != null)

    {

    hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));

    }

    }

    IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)

    {

    if (msg == Win32.WM_DEVICECHANGE)

    {

    if ((int)wParam == Win32.DBT_DEVICEARRIVAL)

    {

    RaiseDeviceArrived();

    }

    else if ((int)wParam == Win32.DBT_DEVICEREMOVECOMPLETE)

    {

    RaiseDeviceRemoved();

    }

    }

    return IntPtr.Zero;

    }

     

     

     

    Monday, April 23, 2007 8:36 AM
  • I tried this WPF code, but wParam is 7 whether the device is added or removed...any ideas on why that is?

     

    Here's a bit more info as to what's going on: the 7 is DBT_DEVNODES_CHANGED. This is supposed to be the parameter that is sent when the window has not called RegisterDeviceNotification (calling RDN is supposed to result in the more specific messages coming in). However, even using the original WinForm code (as a WinForm app), I still get DBT_DEVNODES_CHANGED. In fact, every sample for listening for device add/remove returns 7 on my machine. If I were to take a guess as to the issue, I'd say it has something to do with me running Vista (maybe as part of its heightened security, there's more hoops to jump through to RegisterDeviceNotification); I'll try my test app tomorrow on an XP machine to see if the value is different for that one. In the meantime, I'll see if I can find some kind of release note for Vista related to that API

    Wednesday, January 09, 2008 3:24 AM
  • Took a little playing around, but basically, if you call RegisterDeviceNotification with

    Win32.DEVICE_NOTIFY_WINDOW_HANDLE | Win32.DEVICE_NOTIFY_ALL_INTERFACE_CLASSES instead of just

    Win32.DEVICE_NOTIFY_WINDOW_HANDLE, you should be able to start getting the Added/Removed messages in addition to the NodesChanged message.

    Thursday, January 10, 2008 7:31 AM
  • Using both DEVICE_NOTIFY_ALL_INTERFACE_CLASSES and DEVICE_NOTIFY_WINDOW_HANDLE  worked the first time I ran it and then it was back to 7 again. Do I ahve to restart my computer? ;)
    Thursday, June 19, 2008 11:37 PM
  • Keith,

    Can you post the code sample where you called RegisterDeviceNotification?
    Monday, July 07, 2008 9:51 PM
  • im doing the same thing but i can find a way to detect a removed device the code i used for deteting a new devies is ...
    (btw this ant my code i got it off anouther page)

    private const int WM_DEVICECHANGE = 0x0219;
    private const int LOGICAL_VOLUME  = 2;
    private readonly IntPtr DBT_DEVICEARRIVAL = new IntPtr(0x8000);

    protected override void WndProc(ref Message m)
    {
        if ((m.Msg == WM_DEVICECHANGE) && (m.WParam == DBT_DEVICEARRIVAL))
        {
            int deviceType = Marshal.ReadInt32(m.LParam, sizeof(int));

            if (deviceType == LOGICAL_VOLUME)
            {
                uint unitMask = (uint)Marshal.ReadInt32(m.LParam, sizeof(int) * 3);

                if (unitMask != 0)
                {
                    char driveLetter = DriveLetterFromUnitMask(unitMask);
                    Debug.WriteLine("Drive was inserted: " + driveLetter);

                    // Now copy your file to the drive specified by 'driveLetter'.
                }
            }
        }

        base.WndProc(ref m);
    }

    private char DriveLetterFromUnitMask(uint unitMask)
    {
        for (int bitIndex = 0, bit = 1; bitIndex < 32; ++bitIndex, bit <<= 1)
        {
            if ((unitMask & bit) != 0)
            {
                return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[bitIndex];
            }
        }

        return '?';
    }

    sam eden


    porgramer that will program all day lol sites.google.com/site/sameden2
    Wednesday, April 29, 2009 3:04 PM

  • I realize this post is pretty old but I'll state the answer here as I could not find an answer anywhere online. It took me all night to figure this out. In the WndProc handler, t he WParam is always 7and IParam is always 0 on attach/detach as long as CreateFile(...) has not yet been called to create the file handle for your device.

    By the way, I did it using the
    RegisterDeviceNotification() API.

    Anderson John
    Friday, July 17, 2009 10:44 AM
  • As andyfoxx said: This post is old, but I did not find any solution to the same kind of problem in the web. So I solved it by myself.

    Thing is that if you want to get more information from a USB device than just wParam = 7 you need to RegisterDeviceNotification for your device(s) before you wait for the WndProc Message.

    I did that by using the user32.dll in C#

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    		internal static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags);

    This is the function I need. I use it like:

    deviceNotificationHandle = RegisterDeviceNotification(formHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE);

    formHandle is as the name says the Handle of the control.
    DEVICE_NOTIFY_WINDOW_HANDLE is a int32 constant which equals 0.
    devBroadcastDeviceInterfaceBuffer is a little complicated. The source is a open source snippet. Here you are:

    DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE();
    			IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; 
    			Int32 size = 0;
    
    			try
    			{
    				// Set the parameters in the DEV_BROADCAST_DEVICEINTERFACE structure.
    
    				// Set the size.
    
    				size = Marshal.SizeOf(devBroadcastDeviceInterface);
    				devBroadcastDeviceInterface.dbcc_size = size;
    
    				// Request to receive notifications about a class of devices.
    
    				devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    
    				devBroadcastDeviceInterface.dbcc_reserved = 0;
    
    				// Specify the interface class to receive notifications about.
    
    				devBroadcastDeviceInterface.dbcc_classguid = classGuid;
    
    				// Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure.
    
    				devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size);
    
    				// Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer.
    				// Set fDeleteOld True to prevent memory leaks.
    
    				Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true);

    This did it for me. I hope I could help you. (I know this is almost the same andyfoxx posted. Just a bit of code for you ^^)

    Yours
    fieldtracker

    Wednesday, April 04, 2012 1:53 PM