Я создал общий драйвер связи USB HID, способный отслеживать события USB и отправлять/принимать пакеты данных на устройства и с них. Я успешно использую его с WinForms
дня, так как большая часть кода была взята из MSDN и реализована очень похоже на предложенный способ здесь. Мой вопрос: примеры, которые я вижу, продолжают полагаться на то, что кажется старой архитектурой «Windows Messaging», то есть сообщения типа System.Runtime.InteropServices
, WM_xxxxxxxx, регистрация/обработка их в чисто C# WPF
приложении с HwndHandler
, переопределение WndProc
и т. д. Я был интересно, нет ли способа обрабатывать события USB, используя более современный подход, основанный на событиях, скажем, с delegates
, подпиской на EventHandlers
и т. д.? Даже эти сообщения SO предлагают воздержаться от использования таких архаичных методов, и я думаю должно быть решение и для событий USB. Спасибо.
Обработка USB-событий Windows
Ответы (1)
После небольшого исследования кажется, что обмен сообщениями Windows является необходимой частью обработки уведомлений об изменении USB-устройства. У меня есть рабочий класс драйвера USB-коммуникаций, который включает простую реализацию. Это решение состоит из двух частей: 1) класса EventNotifier
, который генерирует события, и 2) «приемника», который подписывается на события (т. е. клиент, который получает уведомления о событиях USB). Пример кода — C++/CLI, и хотя я не поддерживаю практику помещения исполняемого кода в заголовочные файлы, для краткости я делаю это здесь.
#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>
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);
}
/// <summary>
/// Defines the notification event.
/// </summary>
virtual event NotificationEventHandler^ NotificationEvent;
};
}
Затем в «приемнике» (объект, который подписывается и потребляет наш NotificationEvent
, все, что вам нужно сделать, это:
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.
}
person
Michael Brodsky
schedule
02.10.2014
OnSourceInitialized
иWndProc
в приемникWindow
. Я буду размещать здесь рабочие части и ссылаться на чужие. Кстати, я не против использования устаревшего кода. Я постоянно используюWinForms PropertyGrid
в своих материалах и просто пишу собственныеTypeConverters
иUIEditors
.PropertyGrid
надежный, проверенный, и я не нашел замены. - person Michael Brodsky   schedule 02.10.2014