Handling Windows USB events

后端 未结 1 1439
忘了有多久
忘了有多久 2021-01-24 14:49

I created a generic USB HID comms driver capable of monitoring USB events and sending/receiving data packets to and from devices. I\'ve been using it successfully since my

1条回答
  •  情歌与酒
    2021-01-24 15:28

    After doing a bit of research, it seems that Windows messaging is a necessary part of handling USB Device Change notifications. I have a working usb comms driver class which includes a simple implementation. This solution consists of two parts, 1) the EventNotifier class, which generates the events and 2) the 'receiver', which subscribes to the events (i.e. a client that gets notified of USB events). The sample code is C++/CLI and although I don't subscribe to the practice of putting executable code in header files, for the sake of brevity, I do so here.

    #pragma once
    
    #include     // Declares required datatypes.
    #include         // Required for WM_DEVICECHANGE messages.
    #include    // Required for DEFINE_GUID definition (see below).
    
    namespace USBComms 
    {
        using namespace System;
        using namespace System::Runtime::InteropServices;
        using namespace System::Windows;
        using namespace System::Windows::Forms;
    
        // This function is required for receieving WM_DEVICECHANGE messages.
        // Note: name is remapped "RegisterDeviceNotificationUM"
        [DllImport("user32.dll" , CharSet = CharSet::Unicode, EntryPoint="RegisterDeviceNotification")]                 
        extern "C" HDEVNOTIFY WINAPI RegisterDeviceNotificationUM(
            HANDLE hRecipient,
            LPVOID NotificationFilter,
            DWORD Flags);
    
        // Generic guid for usb devices (see e.g. http://msdn.microsoft.com/en-us/library/windows/hardware/ff545972%28v=vs.85%29.aspx).
        // Note: GUIDs are device and OS specific and may require modification. Using the wrong guid will cause notification to fail.
        // You may have to tinker with your device to find the appropriate GUID. "hid.dll" has a function `HidD_GetHidGuid' that returns
        // "the device interfaceGUID for HIDClass devices" (see http://msdn.microsoft.com/en-us/library/windows/hardware/ff538924%28v=vs.85%29.aspx).
        // However, testing revealed it does not always return a useful value. The GUID_DEVINTERFACE_USB_DEVICE value, defined as
        // {A5DCBF10-6530-11D2-901F-00C04FB951ED}, has worked with cell phones, thumb drives, etc. For more info, see e.g.
        // http://msdn.microsoft.com/en-us/library/windows/hardware/ff553426%28v=vs.85%29.aspx. 
        DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
    
        /// 
        /// Declare a delegate for the notification event handler.
        /// 
        /// The object where the event handler is attached.
        /// The event data.
        public delegate void NotificationEventHandler(Object^ sender, EventArgs^ e);
    
        /// 
        /// Class that generetaes USB Device Change notification events.
        /// 
        /// 
        /// A Form is not necessary. Any type wherein you can override WndProc() can be used.
        /// 
        public ref class EventNotifier : public Control
        {
        private:
            /// 
            /// Raises the NotificationEvent.
            /// 
            /// The event data.
            void RaiseNotificationEvent(EventArgs^ e) {
                NotificationEvent(this, e);
            }
    
        protected:
            /// 
            /// Overrides the base class WndProc method.
            /// 
            /// The Windows Message to process. 
            /// 
            /// This method receives Windows Messages (WM_xxxxxxxxxx) and
            /// raises our NotificationEvent as appropriate. Here you should
            /// add any message filtering (e.g. for the WM_DEVICECHANGE) and
            /// preprocessing before raising the event (or not).
            /// 
            virtual void WndProc(Message% message) override {
                if(message.Msg == WM_DEVICECHANGE)
                {
                    RaiseNotificationEvent(EventArgs::Empty);
                }
                __super::WndProc(message);
            }
    
        public:
            /// 
            /// Creates a new instance of the EventNotifier class.
            /// 
            EventNotifier(void) {
                RequestNotifications(this->Handle); // Register ourselves as the Windows Message processor.
            }
    
            /// 
            /// Registers an object, identified by the handle, for
            /// Windows WM_DEVICECHANGE messages.
            /// 
            /// The object's handle.
            void RequestNotifications(IntPtr handle) {
                GUID InterfaceClassGuid = GUID_DEVINTERFACE_USB_DEVICE;
                DEV_BROADCAST_DEVICEINTERFACE MyDeviceBroadcastHeader;
    
                MyDeviceBroadcastHeader.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
                MyDeviceBroadcastHeader.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
                MyDeviceBroadcastHeader.dbcc_reserved = 0;
                MyDeviceBroadcastHeader.dbcc_classguid = InterfaceClassGuid;
                RegisterDeviceNotificationUM((HANDLE)handle, &MyDeviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE);
            }
    
            /// 
            /// Defines the notification event.
            /// 
            virtual event NotificationEventHandler^ NotificationEvent;
        };
    }
    

    Then, in the 'receiver' (the object that subscribes to and consumes our NotificationEvent, all you have to do is:

    void Receiver::SomeFunction(void)
    {
        USBComms::EventNotifier usb = gcnew USBComms::EventNotifier();
    
        usb->NotificationEvent += gcnew USBComms::NotificationEventHandler(this, &Receiver::USBEvent);
    }
    
    void Receiver::USBEvent(Object^ sender, EventArgs^ e)
    {
        // Handle the event notification as appropriate.
    }
    

    0 讨论(0)
提交回复
热议问题