Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to receive Plug & Play device notifications without a windows form

I am trying to write a class library that can catch the windows messages to notify me if a device has been attached or removed. Normally, in a windows forms app I would just override the WndProc method but there is not WndProc method in this case. Is there another way I can get the messages?

like image 425
PICyourBrain Avatar asked Jan 13 '10 23:01

PICyourBrain


People also ask

Why can't I get my plug in the socket?

If you look in the slots there is usually a plastic piece blocking the opening on tamper resistant receptacles. I find wiggling the plug back forth with a light force will usually release the “doors” and allow the plug to go in.

How does an plug work?

The hot hole is connected to the wire that supplies the electrical current. The neutral hole is connected to the wire that brings the electrical current back to the breaker box. When you plug in a lamp and turn it on, the hot part of the outlet allows electricity to flow into the lamp, turning on the light bulb.


2 Answers

You'll need a window, there's no way around that. Here's a sample implementation. Implement an event handler for the DeviceChangeNotifier.DeviceNotify event to get notifications. Call the DeviceChangeNotifier.Start() method at the start of your program. Call DeviceChangeNotifier.Stop() at the end of your program. Beware that the DeviceNotify event is raised on a background thread, be sure to lock as needed to keep your code thread-safe.

using System; using System.Windows.Forms; using System.Threading;  class DeviceChangeNotifier : Form {   public delegate void DeviceNotifyDelegate(Message msg);   public static event DeviceNotifyDelegate DeviceNotify;   private static DeviceChangeNotifier mInstance;    public static void Start() {     Thread t = new Thread(runForm);     t.SetApartmentState(ApartmentState.STA);     t.IsBackground = true;     t.Start();   }   public static void Stop() {     if (mInstance == null) throw new InvalidOperationException("Notifier not started");     DeviceNotify = null;     mInstance.Invoke(new MethodInvoker(mInstance.endForm));   }   private static void runForm() {     Application.Run(new DeviceChangeNotifier());   }    private void endForm() {     this.Close();   }   protected override void SetVisibleCore(bool value) {     // Prevent window getting visible     if (mInstance == null) CreateHandle();     mInstance = this;     value = false;     base.SetVisibleCore(value);   }   protected override void WndProc(ref Message m) {     // Trap WM_DEVICECHANGE     if (m.Msg == 0x219) {       DeviceNotifyDelegate handler = DeviceNotify;       if (handler != null) handler(m);     }     base.WndProc(ref m);   } } 
like image 173
Hans Passant Avatar answered Sep 21 '22 06:09

Hans Passant


I have a working USB communication class that implements device change notification in a slightly different way if anyone is interested. It's pretty compact (w/o the comments) and doesn't rely on Threading or the OnSourceInitialized and HwndHandler stuff in the client. Also, you do not need a Form or Window as mentioned. Any type where you can override WndProc() can be used. I use a Control.

The sample contains only code needed for notification and nothing else. 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 <Windows.h>    // Declares required datatypes. #include <Dbt.h>        // Required for WM_DEVICECHANGE messages. #include <initguid.h>   // 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);      /// <summary>     /// Declare a delegate for the notification event handler.     /// </summary>     /// <param name="sender">The object where the event handler is attached.</param>     /// <param name="e">The event data.</param>     public delegate void NotificationEventHandler(Object^ sender, EventArgs^ e);      /// <summary>     /// Class that generetaes USB Device Change notification events.     /// </summary>     /// <remarks>     /// A Form is not necessary. Any type wherein you can override WndProc() can be used.     /// </remarks>     public ref class EventNotifier : public Control     {     private:         /// <summary>         /// Raises the NotificationEvent.         /// </summary>         /// <param name="e">The event data.</param>         void RaiseNotificationEvent(EventArgs^ e) {             NotificationEvent(this, e);         }      protected:         /// <summary>         /// Overrides the base class WndProc method.         /// </summary>         /// <param name="message">The Windows Message to process. </param>         /// <remarks>         /// 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).         /// </remarks>         virtual void WndProc(Message% message) override {             if(message.Msg == WM_DEVICECHANGE)             {                 RaiseNotificationEvent(EventArgs::Empty);             }             __super::WndProc(message);         }      public:         /// <summary>         /// Creates a new instance of the EventNotifier class.         /// </summary>         EventNotifier(void) {             RequestNotifications(this->Handle); // Register ourselves as the Windows Message processor.         }          /// <summary>         /// Registers an object, identified by the handle, for         /// Windows WM_DEVICECHANGE messages.         /// </summary>         /// <param name="handle">The object's handle.</param>         bool RequestNotifications(IntPtr handle) {             DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;              ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));             NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;             NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);             NotificationFilter.dbcc_reserved = 0;             NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;             return RegisterDeviceNotificationUM((HANDLE)handle, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE) != NULL;         }          /// <summary>         /// Defines the notification event.         /// </summary>         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. } 
like image 23
Michael Brodsky Avatar answered Sep 18 '22 06:09

Michael Brodsky