c# - 如何挂接到 WPF 窗口句柄以监听 USB 事件
问题描述
我在工作中需要挂钩到 WPF 应用程序的 Windows 事件。我需要听 USB 事件。我发现了零散和不完整的答案,所以我想在一个统一的位置记录我的方法。
尝试在此处复制代码示例时发生了我的原始问题:
https ://stackoverflow.com/a/19435744/1683999
我能够连接到 Windows 事件并接收设备通知,但是它们非常通用,并没有给我太多可用于我的应用程序的信息。
在该页面上的进一步阅读使我在同一页面上得到了不同的答案,该页面直接连接到窗口句柄以监视事件:
https ://stackoverflow.com/a/620179/1683999
这个答案提供了一个链接:
https ://www.codeproject.com/Articles/3946/Trapping-windows-messages
通过按照 codeproject 教程进行一些修改以挂钩 WPF 的窗口句柄,我能够获得 WM_DEVICECHANGE 消息,但是在解码 wParam 时,我只收到 DBT_DEVNODES_CHANGED,因为我没有注册监听 USB 事件。快速的 Google 搜索让我找到了一个旧的 MSDN 论坛帖子:
https ://social.msdn.microsoft.com/Forums/vstudio/en-US/983dc1ee-6208-4036-903f-3fd5674a1efb/registerdevicenotification-in-wpf?forum =wpf
在这个线程中,我找到了我正在寻找的答案。我没有注册 Window 来专门查找 USB 事件,所以我从 Windows 获得了一般事件代码。进一步的研究让我回到了 StackOverflow:
https ://stackoverflow.com/a/16245901/1683999
最后一个答案为我完成了难题。我提供了代码片段,概述了通过连接到 WPF 窗口然后创建一个注册窗口以侦听 USB 事件的侦听器来侦听 Windows 事件所需的内容。
解决方案
要访问 USB 事件,我们需要几件事。
首先,我们需要链接到 user32.dll 中的一些方法。
namespace Example
{
// https://www.pinvoke.net/default.aspx/Structures.DEV_BROADCAST_DEVICEINTERFACE
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_DEVICE_INTERFACE
{
public int Size;
public int DeviceType;
public int Reserved;
public Guid ClassGuid;
public short Name;
}
public class Win32Native
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr RegisterDeviceNotification(
IntPtr hRecipient,
IntPtr notificationFilter,
uint flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
}
}
我们需要它来注册我们的 WPF 窗口来监听 USB 事件。
namespace Example
{
public class UsbEventRegistration : IDisposable
{
private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
private static readonly s_guidDevInterfaceUsbDevice =
new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
private readonly IntPtr _windowHandle;
private IntPtr _notificationHandle = IntPtr.Zero;
public bool IsRegistered => _notificationHandle != IntPtr.Zero;
public UsbEventRegistration(IntPtr windowHandle)
{
_windowHandle = windowHandle;
}
public void Register()
{
var dbdi = new DEV_BROADCAST_DEVICE_INTERFACE
{
DeviceType = DBT_DEVTYP_DEVICEINTERFACE,
Reserved = 0,
ClassGuid = s_guidDevInterfaceUsbDevice,
Name = 0,
};
dbdi.Size = Marshal.SizeOf(dbdi);
IntPtr buffer = Marshal.AllocHGlobal(dbdi.Size);
Marshal.StructureToPtr(dbdi, buffer, true);
_notificationHandle = Win32Native.RegisterDeviceNotification(
_windowHandle,
buffer,
0);
}
// Call on window unload.
public void Dispose()
{
Win32Native.UnregisterDeviceNotification(_notificationHandle);
}
}
}
最后,准备好您的 WPF 窗口代码隐藏。
namespace Example
{
public partial class WPFWindow : Window
{
private UsbEventRegistration _usbEventRegistration;
public WPFWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// IMO this should be abstracted away from the code-behind.
var windowSource = (HwndSource)PresentationSource.FromVisual(this);
_usbEventRegistration = new UsbEventRegistration(windowSource.Handle);
// This will allow your window to receive USB events.
_usbEventRegistration.Register();
// This hook is what we were aiming for. All Windows events are listened to here. We can inject our own listeners.
windowSource.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Here's where the help ends. Do what you need here.
// Get additional info from http://www.pinvoke.net/
// USB event message is msg == 0x0219 (WM_DEVICECHANGE).
// USB event plugin is wParam == 0x8000 (DBT_DEVICEARRIVAL).
// USB event unplug is wParam == 0x8004 (DBT_DEVICEREMOVECOMPLETE).
// Your device info is in lParam. Filter that.
// You need to convert wParam/lParam to Int32 using Marshal.
return IntPtr.Zero;
}
}
}
推荐阅读
- r - 我可以使用“lapply”在 R 中重写这个循环吗?
- python - 如何在不考虑空格并知道字符串的原始索引的情况下在字符串中查找子字符串
- google-chrome - Chrome 扩展程序在自动更新后缺少文件
- javascript - 以 HTML/CSS 为中心制作文本和图片
- react-native - React Native / Redux - 中间件中的商店为空
- python - Python .. 访问默认排序功能?
- java - 如何在 Android 上从 ASP.NET 站点下载文件?
- bash - 在子目录列表上迭代 shell 脚本
- python - 模块“networkx”没有属性“add_nodes_from”
- apache-flink - 为什么检查点对延迟的影响如此之大?