Jak odbierać powiadomienia urządzeń Plug & Play bez formularza windows

Próbuję napisać bibliotekę klas, która może przechwycić komunikaty systemu windows, aby powiadomić mnie, jeśli urządzenie zostało dołączone lub usunięte. Normalnie, w aplikacji Windows forms po prostu nadpisałbym metodę WndProc, ale w tym przypadku nie ma metody WndProc. Czy jest inny sposób na otrzymanie wiadomości?

Author: Hans Passant, 2010-01-14

3 answers

Potrzebujesz okna, nie obejdziesz tego. Oto przykładowa implementacja. Zaimplementuj obsługę zdarzeń dla DeviceChangeNotifier.Wydarzenie DeviceNotify, aby otrzymywać powiadomienia. Zadzwoń do urządzenia.Metoda Start () na początku programu. Zadzwoń Do DeviceChangeNotifier.Stop () na końcu programu. Uważaj, że zdarzenie DeviceNotify jest wywołane w wątku w tle, pamiętaj, aby zablokować w razie potrzeby, aby Twój wątek kodu był bezpieczny.

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);
  }
}
 38
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 10:11:31

Mam działającą klasę komunikacji USB, która implementuje powiadomienie o zmianie urządzenia w nieco inny sposób, jeśli ktoś jest zainteresowany. Jest dość kompaktowy (bez komentarzy) i nie opiera się na Threading lub OnSourceInitialized i HwndHandler rzeczy w kliencie. Ponadto nie potrzebujesz Form lub okna, jak wspomniano. Można użyć dowolnego typu, w którym można zastąpić WndProc(). Używam Control.

Próbka zawiera tylko kod potrzebny do zgłoszenia i nic więcej. Przykładowy kod to C++ / CLI i chociaż I nie Subskrybuj praktyki umieszczania kodu wykonywalnego w plikach nagłówkowych, dla zwięzłości, robię to tutaj.

#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;
    };
}

Następnie, w "odbiorniku" (obiekcie, który subskrybuje i konsumuje nasze NotificationEvent), wszystko co musisz zrobić, to:

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.
}
 5
Author: Michael Brodsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-22 06:59:58

W projektach Windows CE / Windows Mobile / SmartDevice, standard Form nie zapewnia nadpisania metody WndProc, ale można to osiągnąć poprzez utworzenie klasy opartej na Microsoft.WindowsCE.Forms.MessageWindow, utworzenie konstruktora, który przyjmuje formularz, przechowuje ten formularz w zmiennej lokalnej, aby metoda na tym formularzu mogła być wywołana za każdym razem, gdy wiadomość zostanie wykryta. Oto pomniejszona próbka do zilustrowania. Mam nadzieję, że jest to pomocne dla kogoś w świecie CE / Windows Mobile.

  public class MsgWindow : Microsoft.WindowsCE.Forms.MessageWindow {

    public const int WM_SER = 0x500;
    public const int WM_SER_SCANDONE = WM_SER + 0;

    frmMain msgform { get; set; }

    public MsgWindow(frmMain msgform) {
      this.msgform = msgform;
    }

    protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message m) {
      switch (m.Msg) {
        case WM_SER_SCANDONE:
          this.msgform.RespondToMessage(WM_SER_SCANDONE);
          break;
        default:
          break;
      }
      base.WndProc(ref m);
    }

  }

  public partial class frmMain : Form {

    public frmMain() {
      InitializeComponent();
    }

    public void RespondToMessage(int nMsg) {
      try {
        switch (nMsg) {
          case MsgWindow.WM_SER_SCANDONE:
            // do something here based on the message
            break;
          default:
            break;
        }
      } catch (Exception ex) {
        MessageBox.Show(string.Format("{0} - {1}", ex.Message, ex.ToString()), "RespondToMessage() Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
        // throw;
      }
    }

  }
 0
Author: Michael Murphy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-18 17:25:51