From 7f3183fe1fceb10b0392a2402d1eb0dd2f4a28ff Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 19 Sep 2023 18:52:43 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=BF=E7=94=A8=20Po?= =?UTF-8?q?inter=20=E7=9A=84=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/MainWindow.xaml.cs | 40 ++++++++++++++++++- ManipulationDemo/ManipulationDemo.csproj | 21 +++++----- ManipulationDemo/NativeMethods.txt | 1 + .../Properties/Settings.Designer.cs | 2 +- 4 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 ManipulationDemo/NativeMethods.txt diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index 99fbd1c..dc723d5 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -15,6 +15,7 @@ using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; +using Windows.Win32; namespace ManipulationDemo { @@ -107,7 +108,7 @@ public MainWindow() private readonly DispatcherTimer _timer; - private void OnTick(object sender, EventArgs e) + private unsafe void OnTick(object sender, EventArgs e) { try { @@ -154,6 +155,9 @@ private void OnTick(object sender, EventArgs e) device.Name, device.StylusDevices.Count, tabletSize)); } } + + AppendPointerDeviceInfo(builder); + PhysicalSizeRun.Text = builder.ToString(); } catch (Exception ex) @@ -162,6 +166,38 @@ private void OnTick(object sender, EventArgs e) } } + /// + /// 添加 Pointer 消息的信息 + /// + /// + private static unsafe void AppendPointerDeviceInfo(StringBuilder stringBuilder) + { + try + { + // 获取 Pointer 设备数量 + uint deviceCount = 0; + PInvoke.GetPointerDevices(ref deviceCount, + (Windows.Win32.UI.Controls.POINTER_DEVICE_INFO*)IntPtr.Zero); + Windows.Win32.UI.Controls.POINTER_DEVICE_INFO[] pointerDeviceInfo = + new Windows.Win32.UI.Controls.POINTER_DEVICE_INFO[deviceCount]; + fixed (Windows.Win32.UI.Controls.POINTER_DEVICE_INFO* pDeviceInfo = &pointerDeviceInfo[0]) + { + // 这里需要拿两次,第一次获取数量,第二次获取信息 + PInvoke.GetPointerDevices(ref deviceCount, pDeviceInfo); + stringBuilder.AppendLine($"PointerDeviceCount:{deviceCount} 设备列表:"); + foreach (var info in pointerDeviceInfo) + { + stringBuilder.AppendLine($" - {info.productString}"); + } + } + } + catch (Exception e) + { + // 也许是在非 Win8 或以上的系统,抛出找不到方法,这个 GetPointerDevices 方法是 Win8 加的 + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getpointerdevices + } + } + private void OnStylusDown(object sender, StylusDownEventArgs e) { StylusDownStoryboard.Begin(); @@ -242,7 +278,7 @@ private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref // 检查硬件设备插拔。 if (msg == (int) WindowMessages.DEVICECHANGE) { - var eventText = $"Event={(WindowsMessageDeviceChangeEventEnum)wparam}"; + var eventText = $"Event={(WindowsMessageDeviceChangeEventEnum) wparam}"; Log(DeviceChangeListenerTextBlock, $"[WM_DEVICECHANGE]设备发生插拔 0x{wparam.ToString("X4")}-0x{lparam.ToString("X4")};{eventText}", true); LogDevices(); diff --git a/ManipulationDemo/ManipulationDemo.csproj b/ManipulationDemo/ManipulationDemo.csproj index 7f36069..6d1ffd4 100644 --- a/ManipulationDemo/ManipulationDemo.csproj +++ b/ManipulationDemo/ManipulationDemo.csproj @@ -1,12 +1,15 @@  - - WinExe - netcoreapp3.1;net45 - true - ManipulationDemo.Program - - - - + + WinExe + net6.0-windows;net45 + true + latest + ManipulationDemo.Program + + + + + + diff --git a/ManipulationDemo/NativeMethods.txt b/ManipulationDemo/NativeMethods.txt new file mode 100644 index 0000000..8654ad0 --- /dev/null +++ b/ManipulationDemo/NativeMethods.txt @@ -0,0 +1 @@ +GetPointerDevices \ No newline at end of file diff --git a/ManipulationDemo/Properties/Settings.Designer.cs b/ManipulationDemo/Properties/Settings.Designer.cs index 1bb4fd8..6555046 100644 --- a/ManipulationDemo/Properties/Settings.Designer.cs +++ b/ManipulationDemo/Properties/Settings.Designer.cs @@ -27,7 +27,7 @@ public static Settings Default { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("3,5,6,7,8,13,14,15,19,20,24,25,28,31,32,36,61,70,71,124,125,127,131,132,133,134,1" + "60,161,174,274,281,282,283,356,522,526,532,533,534,561,562,641,642,674,675,725,7" + - "99,49283,49343,49586")] + "99,49283,49343,49586,")] public string IgnoredMsgs { get { return ((string)(this["IgnoredMsgs"])); From 1fe93a276ac49198e24eda386e3bf5e1e061a966 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 14:15:05 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E6=8B=BF=E8=A7=A6=E6=91=B8=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/MainWindow.xaml.cs | 18 ++++++++++++ .../TabletManager/ITabletManager.cs | 28 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 ManipulationDemo/TabletManager/ITabletManager.cs diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index dc723d5..01d6f88 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -13,6 +13,7 @@ using ManipulationDemo.Properties; using System.Management; using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Windows.Win32; @@ -29,6 +30,8 @@ public MainWindow() InitializeComponent(); this.RemoveIcon(); + Loaded += MainWindow_Loaded; + var args = Environment.GetCommandLineArgs(); if (args.Contains("--startup")) { @@ -93,6 +96,21 @@ public MainWindow() } } + private void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + var typeFromClsid = Type.GetTypeFromCLSID(new Guid("A5B020FD-E04B-4e67-B65A-E7DEED25B2CF")); + object comObject = Activator.CreateInstance(typeFromClsid); + + var manager = comObject as ITabletManager; + manager!.GetTabletCount(out var tabletCount); + for (uint i = 0; i < tabletCount; i++) + { + manager.GetTablet(i, out var tablet); + + tablet.GetName(out var name); + } + } + private Storyboard StylusDownStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusDown"); private Storyboard StylusMoveStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusMove"); private Storyboard StylusUpStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusUp"); diff --git a/ManipulationDemo/TabletManager/ITabletManager.cs b/ManipulationDemo/TabletManager/ITabletManager.cs new file mode 100644 index 0000000..fe43b08 --- /dev/null +++ b/ManipulationDemo/TabletManager/ITabletManager.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using HRESULT = System.Int32; + +namespace ManipulationDemo; + +[ComImport, Guid("764DE8AA-1867-47C1-8F6A-122445ABD89A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +public interface ITabletManager +{ + int GetDefaultTablet(out ITablet ppTablet); + int GetTabletCount(out ulong pcTablets); + int GetTablet(ulong iTablet, out ITablet ppTablet); +} + +[ComImport, Guid("1CB2EFC3-ABC7-4172-8FCB-3BC9CB93E29F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +public interface ITablet //: IUnknown +{ + HRESULT GetDefaultContextSettings(); + HRESULT CreateContext(); + HRESULT GetName([MarshalAs(UnmanagedType.LPWStr)] out string ppwszName); + //HRESULT GetMaxInputRect(out RECT prcInput); + //HRESULT GetHardwareCaps(out uint pdwCaps); + //HRESULT GetPropertyMetrics([In] ref Guid rguid, out PROPERTY_METRICS pPM); + //HRESULT GetPlugAndPlayId([MarshalAs(UnmanagedType.LPWStr)] out string ppwszPPId); + //HRESULT GetCursorCount(out uint pcCurs); + // HRESULT GetCursor(uint iCur, out ITabletCursor ppCur); +} From 523e8a96889ec7a5253bd736564b890d010568f4 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 14:15:29 +0800 Subject: [PATCH 03/10] =?UTF-8?q?Revert=20"=E5=B0=9D=E8=AF=95=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E6=8B=BF=E8=A7=A6=E6=91=B8=E8=AE=BE=E5=A4=87"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1fe93a276ac49198e24eda386e3bf5e1e061a966. --- ManipulationDemo/MainWindow.xaml.cs | 18 ------------ .../TabletManager/ITabletManager.cs | 28 ------------------- 2 files changed, 46 deletions(-) delete mode 100644 ManipulationDemo/TabletManager/ITabletManager.cs diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index 01d6f88..dc723d5 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -13,7 +13,6 @@ using ManipulationDemo.Properties; using System.Management; using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Windows.Win32; @@ -30,8 +29,6 @@ public MainWindow() InitializeComponent(); this.RemoveIcon(); - Loaded += MainWindow_Loaded; - var args = Environment.GetCommandLineArgs(); if (args.Contains("--startup")) { @@ -96,21 +93,6 @@ public MainWindow() } } - private void MainWindow_Loaded(object sender, RoutedEventArgs e) - { - var typeFromClsid = Type.GetTypeFromCLSID(new Guid("A5B020FD-E04B-4e67-B65A-E7DEED25B2CF")); - object comObject = Activator.CreateInstance(typeFromClsid); - - var manager = comObject as ITabletManager; - manager!.GetTabletCount(out var tabletCount); - for (uint i = 0; i < tabletCount; i++) - { - manager.GetTablet(i, out var tablet); - - tablet.GetName(out var name); - } - } - private Storyboard StylusDownStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusDown"); private Storyboard StylusMoveStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusMove"); private Storyboard StylusUpStoryboard => (Storyboard) IndicatorPanel.FindResource("Storyboard.StylusUp"); diff --git a/ManipulationDemo/TabletManager/ITabletManager.cs b/ManipulationDemo/TabletManager/ITabletManager.cs deleted file mode 100644 index fe43b08..0000000 --- a/ManipulationDemo/TabletManager/ITabletManager.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using HRESULT = System.Int32; - -namespace ManipulationDemo; - -[ComImport, Guid("764DE8AA-1867-47C1-8F6A-122445ABD89A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] -public interface ITabletManager -{ - int GetDefaultTablet(out ITablet ppTablet); - int GetTabletCount(out ulong pcTablets); - int GetTablet(ulong iTablet, out ITablet ppTablet); -} - -[ComImport, Guid("1CB2EFC3-ABC7-4172-8FCB-3BC9CB93E29F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] -public interface ITablet //: IUnknown -{ - HRESULT GetDefaultContextSettings(); - HRESULT CreateContext(); - HRESULT GetName([MarshalAs(UnmanagedType.LPWStr)] out string ppwszName); - //HRESULT GetMaxInputRect(out RECT prcInput); - //HRESULT GetHardwareCaps(out uint pdwCaps); - //HRESULT GetPropertyMetrics([In] ref Guid rguid, out PROPERTY_METRICS pPM); - //HRESULT GetPlugAndPlayId([MarshalAs(UnmanagedType.LPWStr)] out string ppwszPPId); - //HRESULT GetCursorCount(out uint pcCurs); - // HRESULT GetCursor(uint iCur, out ITabletCursor ppCur); -} From e6de866008905baaf42760dd9c129ab38798c4d7 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 14:21:23 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E5=BA=93=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/ManipulationDemo.csproj | 16 +++++++++++++++- ManipulationDemo/Properties/Settings.Designer.cs | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ManipulationDemo/ManipulationDemo.csproj b/ManipulationDemo/ManipulationDemo.csproj index 6d1ffd4..816b9d1 100644 --- a/ManipulationDemo/ManipulationDemo.csproj +++ b/ManipulationDemo/ManipulationDemo.csproj @@ -8,8 +8,22 @@ ManipulationDemo.Program - + + + + + True + True + Settings.settings + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + diff --git a/ManipulationDemo/Properties/Settings.Designer.cs b/ManipulationDemo/Properties/Settings.Designer.cs index 6555046..7777495 100644 --- a/ManipulationDemo/Properties/Settings.Designer.cs +++ b/ManipulationDemo/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace ManipulationDemo.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.6.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); From 49ceb50c619c612ebb8baafc0bdb57e4b0381cf0 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:06:43 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E7=9A=84=E8=AE=BE=E5=A4=87=E6=8F=92=E6=8B=94?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/MainWindow.xaml.cs | 77 +++++++++++++++++++++++---- ManipulationDemo/UsbNotification.cs | 82 +++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 ManipulationDemo/UsbNotification.cs diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index dc723d5..d4c9cf8 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -16,6 +16,9 @@ using System.Threading; using System.Threading.Tasks; using Windows.Win32; +using static ManipulationDemo.UsbNotification; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; namespace ManipulationDemo { @@ -177,7 +180,7 @@ private static unsafe void AppendPointerDeviceInfo(StringBuilder stringBuilder) // 获取 Pointer 设备数量 uint deviceCount = 0; PInvoke.GetPointerDevices(ref deviceCount, - (Windows.Win32.UI.Controls.POINTER_DEVICE_INFO*)IntPtr.Zero); + (Windows.Win32.UI.Controls.POINTER_DEVICE_INFO*) IntPtr.Zero); Windows.Win32.UI.Controls.POINTER_DEVICE_INFO[] pointerDeviceInfo = new Windows.Win32.UI.Controls.POINTER_DEVICE_INFO[deviceCount]; fixed (Windows.Win32.UI.Controls.POINTER_DEVICE_INFO* pDeviceInfo = &pointerDeviceInfo[0]) @@ -266,7 +269,8 @@ private void OnManipulationCompleted(object sender, ManipulationCompletedEventAr protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); - var source = (HwndSource) PresentationSource.FromVisual(this); + var source = (HwndSource) PresentationSource.FromVisual(this)!; + UsbNotification.RegisterUsbDeviceNotification(source.Handle); source?.AddHook(HwndHook); Log("程序启动时"); @@ -276,20 +280,71 @@ protected override void OnSourceInitialized(EventArgs e) private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) { // 检查硬件设备插拔。 - if (msg == (int) WindowMessages.DEVICECHANGE) + if (msg == (int)WindowMessages.DEVICECHANGE) { - var eventText = $"Event={(WindowsMessageDeviceChangeEventEnum) wparam}"; + // 是否应该加上通用的变更记录日志 + bool shouldCommonLog = true; - Log(DeviceChangeListenerTextBlock, $"[WM_DEVICECHANGE]设备发生插拔 0x{wparam.ToString("X4")}-0x{lparam.ToString("X4")};{eventText}", true); - LogDevices(); + bool isDeviceArrival = (int)wparam == (int)WindowsMessageDeviceChangeEventEnum.DBT_DEVICEARRIVAL; + bool isDeviceRemoveComplete = (int)wparam == (int)WindowsMessageDeviceChangeEventEnum.DBT_DEVICEREMOVECOMPLETE; + + if (isDeviceArrival || isDeviceRemoveComplete) + { + // 设备被移除或插入,试试拿到具体是哪个社保 + DEV_BROADCAST_HDR hdr = + (DEV_BROADCAST_HDR) Marshal.PtrToStructure(lparam, typeof(DEV_BROADCAST_HDR)); + if (hdr.dbch_devicetype == UsbNotification.DbtDevtypDeviceinterface) + { + DEV_BROADCAST_DEVICEINTERFACE deviceInterface = + (DEV_BROADCAST_DEVICEINTERFACE) Marshal.PtrToStructure(lparam, + typeof(DEV_BROADCAST_DEVICEINTERFACE)); + + var size = Marshal.SizeOf(typeof(DEV_BROADCAST_DEVICEINTERFACE)); + var namePtr = lparam + size; + var length = hdr.dbch_size - size; // 尽管 length 部分都是字符串的内容,然而字符串却是设计为 \0 结束方式 + var name = Marshal.PtrToStringUni(namePtr); + + string pid = string.Empty; + string vid = string.Empty; + + var pidMatch = Regex.Match(name, @"PID_([\dA-Fa-f]{4})"); + if (pidMatch.Success) + { + pid = pidMatch.Groups[1].Value; + } + + var vidMatch = Regex.Match(name, @"VID_([\dA-Fa-f]{4})"); + if (vidMatch.Success) + { + vid = vidMatch.Groups[1].Value; + } + + Log(DeviceChangeListenerTextBlock, $"[WM_DEVICECHANGE] 设备{(isDeviceArrival?"插入":"拔出")} PID={pid} VID={vid}\r\n{name}", true); + + // 换成带上更多信息的记录,不需要通用记录 + shouldCommonLog = false; + } + } + + if (shouldCommonLog) + { + var eventText = $"Event={(WindowsMessageDeviceChangeEventEnum) wparam}"; + + Log(DeviceChangeListenerTextBlock, + $"[WM_DEVICECHANGE]设备发生插拔 Param=0x{wparam.ToString("X4")}-0x{lparam.ToString("X4")};{eventText}", + true); + LogDevices(); + } } - else if (msg == (int) WindowMessages.TABLET_ADDED) + else if (msg == (int)WindowMessages.TABLET_ADDED) { - Log(DeviceChangeListenerTextBlock, $"[TABLET_ADDED]触摸设备插入 0x{wparam.ToString("X4")} - 0x{lparam.ToString("X4")}", true); + Log(DeviceChangeListenerTextBlock, + $"[TABLET_ADDED]触摸设备插入 0x{wparam.ToString("X4")} - 0x{lparam.ToString("X4")}", true); } - else if (msg == (int) WindowMessages.TABLET_DELETED) + else if (msg == (int)WindowMessages.TABLET_DELETED) { - Log(DeviceChangeListenerTextBlock, $"[TABLET_DELETED]触摸设备拔出 0x{wparam.ToString("X4")} - 0x{lparam.ToString("X4")}", true); + Log(DeviceChangeListenerTextBlock, + $"[TABLET_DELETED]触摸设备拔出 0x{wparam.ToString("X4")} - 0x{lparam.ToString("X4")}", true); } // 输出消息。 @@ -298,7 +353,7 @@ private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref return IntPtr.Zero; } - var formattedMessage = $"{(WindowMessages) msg}({msg})"; + var formattedMessage = $"{(WindowMessages)msg}({msg})"; Log(HwndMsgTextBlock, formattedMessage); return IntPtr.Zero; diff --git a/ManipulationDemo/UsbNotification.cs b/ManipulationDemo/UsbNotification.cs new file mode 100644 index 0000000..8787b3f --- /dev/null +++ b/ManipulationDemo/UsbNotification.cs @@ -0,0 +1,82 @@ +using System.Runtime.InteropServices; +using System; + +namespace ManipulationDemo +{ + /// + /// Copy From: https://stackoverflow.com/questions/1976573/using-registerdevicenotification-in-a-net-app + /// + internal static class UsbNotification + { + public const int DbtDevicearrival = 0x8000; // system detected a new device + public const int DbtDeviceremovecomplete = 0x8004; // device is gone + public const int WmDevicechange = 0x0219; // device change event + public const int DbtDevtypDeviceinterface = 5; + private static readonly Guid GuidDevinterfaceUSBDevice = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED"); // USB devices + private static IntPtr _notificationHandle; + + /// + /// Registers a window to receive notifications when USB devices are plugged or unplugged. + /// + /// Handle to the window receiving notifications. + public static void RegisterUsbDeviceNotification(IntPtr windowHandle) + { + DevBroadcastDeviceinterface dbi = new DevBroadcastDeviceinterface + { + DeviceType = DbtDevtypDeviceinterface, + Reserved = 0, + ClassGuid = GuidDevinterfaceUSBDevice, + Name = 0 + }; + + dbi.Size = Marshal.SizeOf(dbi); + IntPtr buffer = Marshal.AllocHGlobal(dbi.Size); + Marshal.StructureToPtr(dbi, buffer, true); + + _notificationHandle = RegisterDeviceNotification(windowHandle, buffer, 0); + } + + /// + /// Unregisters the window for USB device notifications + /// + public static void UnregisterUsbDeviceNotification() + { + UnregisterDeviceNotification(_notificationHandle); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); + + [DllImport("user32.dll")] + private static extern bool UnregisterDeviceNotification(IntPtr handle); + + [StructLayout(LayoutKind.Sequential)] + private struct DevBroadcastDeviceinterface + { + internal int Size; + internal int DeviceType; + internal int Reserved; + internal Guid ClassGuid; + internal short Name; + } + + + [StructLayout(LayoutKind.Sequential)] + public struct DEV_BROADCAST_HDR + { + public int dbch_size; + public int dbch_devicetype; + public int dbch_reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DEV_BROADCAST_DEVICEINTERFACE + { + public int dbcc_size; + public int dbcc_devicetype; + public int dbcc_reserved; + public Guid dbcc_classguid; + //public char[] dbcc_name; + } + } +} \ No newline at end of file From f7fb8993922c1410269aea70a387372a823705a1 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:09:40 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/MainWindow.xaml.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index d4c9cf8..abccc0f 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -290,7 +290,7 @@ private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref if (isDeviceArrival || isDeviceRemoveComplete) { - // 设备被移除或插入,试试拿到具体是哪个社保 + // 设备被移除或插入,试试拿到具体是哪个设备 DEV_BROADCAST_HDR hdr = (DEV_BROADCAST_HDR) Marshal.PtrToStructure(lparam, typeof(DEV_BROADCAST_HDR)); if (hdr.dbch_devicetype == UsbNotification.DbtDevtypDeviceinterface) @@ -299,10 +299,17 @@ private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref (DEV_BROADCAST_DEVICEINTERFACE) Marshal.PtrToStructure(lparam, typeof(DEV_BROADCAST_DEVICEINTERFACE)); + var classguid = deviceInterface.dbcc_classguid; + // 这里的 classguid 默认会带上 name 上,于是就用不着 + var size = Marshal.SizeOf(typeof(DEV_BROADCAST_DEVICEINTERFACE)); var namePtr = lparam + size; var length = hdr.dbch_size - size; // 尽管 length 部分都是字符串的内容,然而字符串却是设计为 \0 结束方式 var name = Marshal.PtrToStringUni(namePtr); + if (string.IsNullOrEmpty(name)) + { + name = "读取不到设备名"; + } string pid = string.Empty; string vid = string.Empty; From 89c1950e4c0a39cad1d90ca558ee55143fa787aa Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:26:23 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=9B=B4=E5=85=B7=E4=BD=93=E7=9A=84=E9=95=BF=E5=BA=A6=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/MainWindow.xaml.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ManipulationDemo/MainWindow.xaml.cs b/ManipulationDemo/MainWindow.xaml.cs index abccc0f..77b1dc5 100644 --- a/ManipulationDemo/MainWindow.xaml.cs +++ b/ManipulationDemo/MainWindow.xaml.cs @@ -304,8 +304,10 @@ private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref var size = Marshal.SizeOf(typeof(DEV_BROADCAST_DEVICEINTERFACE)); var namePtr = lparam + size; - var length = hdr.dbch_size - size; // 尽管 length 部分都是字符串的内容,然而字符串却是设计为 \0 结束方式 - var name = Marshal.PtrToStringUni(namePtr); + var nameSize = hdr.dbch_size - size; + // 使用 Unicode 读取的话,一个字符是两个字节 + var charLength = nameSize / 2; + var name = Marshal.PtrToStringUni(namePtr, charLength); if (string.IsNullOrEmpty(name)) { name = "读取不到设备名"; From f6c685ade2286d7ed27d612f4481d762b2cc4a5b Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:28:53 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E6=9B=B4=E6=AD=A3=20PInvoke=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/UsbNotification.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ManipulationDemo/UsbNotification.cs b/ManipulationDemo/UsbNotification.cs index 8787b3f..17b1586 100644 --- a/ManipulationDemo/UsbNotification.cs +++ b/ManipulationDemo/UsbNotification.cs @@ -44,7 +44,7 @@ public static void UnregisterUsbDeviceNotification() UnregisterDeviceNotification(_notificationHandle); } - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); [DllImport("user32.dll")] @@ -76,7 +76,8 @@ public struct DEV_BROADCAST_DEVICEINTERFACE public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc_classguid; - //public char[] dbcc_name; + //[MarshalAs(UnmanagedType.LPUTF8Str)] + //public string dbcc_name; } } } \ No newline at end of file From 58b22b3626f43794ea48ce082acae97116bb8df2 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:30:25 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/UsbNotification.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ManipulationDemo/UsbNotification.cs b/ManipulationDemo/UsbNotification.cs index 17b1586..e450116 100644 --- a/ManipulationDemo/UsbNotification.cs +++ b/ManipulationDemo/UsbNotification.cs @@ -60,7 +60,6 @@ private struct DevBroadcastDeviceinterface internal short Name; } - [StructLayout(LayoutKind.Sequential)] public struct DEV_BROADCAST_HDR { From 5e01b6ad04f70d3364a15d9870b22427ac213d65 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 21 Nov 2023 15:36:36 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ManipulationDemo/UsbNotification.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ManipulationDemo/UsbNotification.cs b/ManipulationDemo/UsbNotification.cs index e450116..e61d3f6 100644 --- a/ManipulationDemo/UsbNotification.cs +++ b/ManipulationDemo/UsbNotification.cs @@ -75,7 +75,6 @@ public struct DEV_BROADCAST_DEVICEINTERFACE public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc_classguid; - //[MarshalAs(UnmanagedType.LPUTF8Str)] //public string dbcc_name; } }