当前位置:网站首页>13、使用wpf开发usb检测工具
13、使用wpf开发usb检测工具
2022-06-09 11:00:00 【komla168】
一、简介
网上查了下使用c#开发监听usb设备的资料,winfrom的比较多,wpf 的不太多,而且大多是FramWork框架下的,
本文测试的设备是一个带有存储功能的usb设备,可以理解为一个u盘,我想获取u盘的拔插信息和盘符等设备信息。
要实现功能
1、监听usb设备插入拔出
2、获取盘符
3、获取其他设备信息
二、方案选型分析
2.1 WndProc
HWND是Handle to A Window的缩写,H表示句柄(handle), Wnd 是变量对象描述,表示窗口,所以hWnd 表示窗口句柄。简而言之,hwnd就是窗口句柄的意思。
WndProc函数的使用局限于窗体程序中,控制台程序用不了,因为这个函数在System.Windows.Forms命名空间下。
其次WndProc函数在WPF中不存在,但是WPF提供了另一种方法来完成挂钩的功能,要借助HwndSource 才能完成捕获消息的功能。
WinForm实现
using System;
using System.IO;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace USB
{
public partial class USB : Form
{
public USB()
{
InitializeComponent();
}
public const int WM_DEVICECHANGE = 0x219;
public const int DBT_DEVICEARRIVAL = 0x8000;
public const int DBT_CONFIGCHANGECANCELED = 0x0019;
public const int DBT_CONFIGCHANGED = 0x0018;
public const int DBT_CUSTOMEVENT = 0x8006;
public const int DBT_DEVICEQUERYREMOVE = 0x8001;
public const int DBT_DEVICEQUERYREMOVEFAILED = 0x8002;
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
public const int DBT_DEVICEREMOVEPENDING = 0x8003;
public const int DBT_DEVICETYPESPECIFIC = 0x8005;
public const int DBT_DEVNODES_CHANGED = 0x0007;
public const int DBT_QUERYCHANGECONFIG = 0x0017;
public const int DBT_USERDEFINED = 0xFFFF;
public const int DBT_DEVTYP_VOLUME = 0x00000002;
public string ID="";
public string Value;
public string[] item;
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_VOLUME
{
public int dbcv_size;
public int dbcv_devicetype;
public int dbcv_reserved;
public int dbcv_unitmask;
}
protected override void WndProc(ref Message m)
{
try
{
if (m.Msg == WM_DEVICECHANGE)
{
switch (m.WParam.ToInt32())
{
case WM_DEVICECHANGE:
break;
case DBT_DEVICEARRIVAL://U盘有插入
this.timer1.Enabled = true;
DriveInfo[] s = DriveInfo.GetDrives();
foreach (DriveInfo DriveI in s)
{
if (DriveI.DriveType == DriveType.Removable)
{
break;
}
int devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
DEV_BROADCAST_VOLUME vol;
vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
ID=vol.dbcv_unitmask.ToString("x");
this.Text = IO(ID);
this.Tag = IO(ID);
}
this.label1.Text = this.Text;
}
break;
case DBT_CONFIGCHANGECANCELED:
break;
case DBT_CONFIGCHANGED:
break;
case DBT_CUSTOMEVENT:
break;
case DBT_DEVICEQUERYREMOVE:
break;
case DBT_DEVICEQUERYREMOVEFAILED:
break;
case DBT_DEVICEREMOVECOMPLETE:
DriveInfo[] I = DriveInfo.GetDrives();
foreach (DriveInfo DrInfo in I)
{
int devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
DEV_BROADCAST_VOLUME vol;
vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
ID = vol.dbcv_unitmask.ToString("x");
this.Text = IO(ID) + "盘退出!\n";
}
this.label1.Text += this.Text;
// MessageBox.Show("U盘已经卸载", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
break;
case DBT_DEVICEREMOVEPENDING:
break;
case DBT_DEVICETYPESPECIFIC:
break;
case DBT_DEVNODES_CHANGED:
break;
case DBT_QUERYCHANGECONFIG:
break;
case DBT_USERDEFINED:
break;
default:
break;
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
base.WndProc(ref m);
}
public string IO(string ff)
{
switch (ff)
{
case "1":
Value="A:";
break;
case "2":
Value= "B:";
break;
case "4":
Value= "C:";
break;
case "8":
Value= "D:";
break;
case "10":
Value= "E:";
break;
case "20":
Value= "F:";
break;
case "40":
Value= "G:";
break;
case "80":
Value= "H:";
break;
case "100":
Value= "I:";
break;
case "200":
Value= "J:";
break;
case "400":
Value= "K:";
break;
case "800":
Value= "L:";
break;
case "1000":
Value= "M:";
break;
case "2000":
Value= "N:";
break;
case "4000":
Value= "O:";
break;
case "8000":
Value= "P:";
break;
case "10000":
Value= "Q:";
break;
case "20000":
Value= "R:";
break;
case "40000":
Value= "S:";
break;
case "80000":
Value= "T:";
break;
case "100000":
Value= "U:";
break;
case "200000":
Value= "V:";
break;
case "400000":
Value= "W:";
break;
case "800000":
Value= "X:";
break;
case "1000000":
Value= "Y:";
break;
case "2000000":
Value= "Z:";
break;
default: break;
}
return Value;
}
private void timer1_Tick(object sender, EventArgs e){}
}
}WPF实现

借助 HwndSource类实现WndProc函数功能。HwndSource的官网解释HwndSource 类 (System.Windows.Interop) | Microsoft Docs
HwndSource 实现包含 WPF 内容的 Win32 窗口。 WPF 内容在此窗口中排列、度量、呈现,并且可交互式输入。
HwndSource 类设计用于一般的交互操作,而不是设计用作托管 HWND 包装。 通常,它不会提供操作窗口的托管方法或检测其状态的属性。 相反,HwndSource 类提供通过 Handle 属性对 Win32 窗口句柄 (HWND) 的访问,可通过 PInvoke 技术将其传递到 Win32 APIs 以操作该窗口。
构造--HwndSource 的诸多方面只能在构造时指定。 若要创建 HwndSource,请首先创建 HwndSourceParameters 结构,然后使用所需参数填充该结构。 这些参数包括以下内容:类、窗口和扩展窗口样式。
在创建窗口之后,您必须使用 PInvoke 来更改样式。 并不是所有样式都可以在创建窗口后进行更改。 在更改窗口样式之前,请查阅 Win32 文档。窗口的初始位置。窗口的初始大小,其中包括说明是指定此大小,还是应当根据 WPF 内容的已确定大小进行确定。
父窗口--包含在窗口过程链中的 HwndSourceHook。 如果在构造时指定了挂钩,则它将接收此窗口的所有消息。 在创建窗口之后,您可以使用 AddHook 来添加挂钩。透明度设置。 可以配置顶级窗口,使其根据 WPF 内容的每像素透明度与桌面上的其他窗口混合。 请将 HwndSourceParameters 中的 UsesPerPixelOpacity 属性设置为 true 以启用此功能。 此属性只能在构造时通过 HwndSource(HwndSourceParameters) 构造函数签名来指定,并实施多个限制。在填充 HwndSourceParameters 结构之后,请将其传递到 HwndSource 的 HwndSource(HwndSourceParameters) 构造函数。值得注意的是 对于挂钩 HwndSource 实现的是 挂钩将按后进先出的顺序调用所以你需要确定挂钩委托的生命周期
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Wpf_DataGrid_RowDragAndDrop
{
/// <summary>
/// WinUpan.xaml 的交互逻辑
/// </summary>
public partial class WinUpan : Window
{
public WinUpan()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
/*WPF中处理消息首先要获取窗口句柄,创建HwndSource对象 通过HwndSource对象添加
* 消息处理回调函数.HwndSource类: 实现其自己的窗口过程。 创建窗口之后使用 AddHook
* 和 RemoveHook 来添加和移除挂钩,接收所有窗口消息。*/
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;//窗口过程
if (hwndSource != null)
{
hwndSource.AddHook(new HwndSourceHook(WndProc));//挂钩
}
}
string panfu = "";
public const int WM_DEVICECHANGE = 0x219;//U盘插入后,OS的底层会自动检测到,然后向应用程序发送“硬件设备状态改变“的消息
public const int DBT_DEVICEARRIVAL = 0x8000; //就是用来表示U盘可用的。一个设备或媒体已被插入一块,现在可用。
public const int DBT_CONFIGCHANGECANCELED = 0x0019; //要求更改当前的配置(或取消停靠码头)已被取消。
public const int DBT_CONFIGCHANGED = 0x0018; //当前的配置发生了变化,由于码头或取消固定。
public const int DBT_CUSTOMEVENT = 0x8006; //自定义的事件发生。 的Windows NT 4.0和Windows 95:此值不支持。
public const int DBT_DEVICEQUERYREMOVE = 0x8001; //审批要求删除一个设备或媒体作品。任何应用程序也不能否认这一要求,并取消删除。
public const int DBT_DEVICEQUERYREMOVEFAILED = 0x8002; //请求删除一个设备或媒体片已被取消。
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; //一个设备或媒体片已被删除。
public const int DBT_DEVICEREMOVEPENDING = 0x8003; //一个设备或媒体一块即将被删除。不能否认的。
public const int DBT_DEVICETYPESPECIFIC = 0x8005; //一个设备特定事件发生。
public const int DBT_DEVNODES_CHANGED = 0x0007; //一种设备已被添加到或从系统中删除。
public const int DBT_QUERYCHANGECONFIG = 0x0017; //许可是要求改变目前的配置(码头或取消固定)。
public const int DBT_USERDEFINED = 0xFFFF; //此消息的含义是用户定义的
public const uint GENERIC_READ = 0x80000000;
public const int GENERIC_WRITE = 0x40000000;
public const int FILE_SHARE_READ = 0x1;
public const int FILE_SHARE_WRITE = 0x2;
public const int IOCTL_STORAGE_EJECT_MEDIA = 0x2d4808;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_DEVICECHANGE)
{
switch (wParam.ToInt32())
{
case DBT_DEVICEARRIVAL:
DriveInfo[] s = DriveInfo.GetDrives();
s.Any(t =>
{
if (t.DriveType == DriveType.Removable)
{
panfu = t.Name;
MessageBox.Show("U盘插入,盘符为:" + t.Name);
DirSearch(t.RootDirectory.FullName);
return true;
}
return false;
});
break;
case DBT_DEVICEREMOVECOMPLETE:
MessageBox.Show("U盘卸载");
break;
default:
break;
}
}
return IntPtr.Zero;
}
private void DirSearch(string path)
{
try
{
foreach (string f in Directory.GetFiles(path))
{
listview.Items.Add(f);
}
foreach (string d in Directory.GetDirectories(path))
{
DirSearch(d);
}
}
catch (Exception)
{
throw;
}
}可以看到,这里是写了个WndProc方法。不像WinForm中的直接有个WndProc方法可以去操作。
2.2 WMI
使用到WMI 的方法,需要安装System.Management ,通过NuGet安装即可,注意下版本,不然可能不兼容。
using System;
using System.Management;
using System.Windows;
namespace WpfUsb
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 or EventType = 3");
watcher.EventArrived += (s, e) =>
{
string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
EventType eventType = (EventType)(Convert.ToInt16(e.NewEvent.Properties["EventType"].Value));
string eventName = Enum.GetName(typeof(EventType), eventType);
};
watcher.Query = query;
watcher.Start();
}
public enum EventType
{
Inserted = 2,
Removed = 3
}
}
}
这里涉及到查找硬件序列号
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"select * from " + Key);这里的key可以使用多个不同的字符串,如需要找到CPU的序列号,就可以使用Win32_Processor
具体可以查看这篇博客15 WMI 中WIN32类库名_komla168的博客-CSDN博客
三、引用文献
4.1 WPF判断USB插拔_11273245的技术博客_51CTO博客
边栏推荐
- 建议收藏:数据标准的概念,分类,价值及6大实施步骤解析
- [buuctf.reverse] 105_ [FlareOn6]Memecat Battlestation
- Little knowledge -- the difference between let const var
- [buuctf.reverse] 114_[MRCTF2020]VirtualTree
- About CSRF and its defense
- wsl2环境搭建
- 浅谈Event-Loop
- 使用 KubeKey 搭建 Kubernetes/KubeSphere 环境的“心路(累)历程“
- 微信小程序 登录失效后处理
- The latest Camtasia 2022 free computer screen recording tool
猜你喜欢

What are the preparations for building your own website

腾亚精工深交所上市:市值26亿 第一季扣非后净利降42%

Win7系统怎么卸载IE浏览器

百度 90 后程序员删改数据库被判刑,其称因对领导不满

组件el-scrollbar的使用

What are the application advantages of 3D digital sand table display
![P5482 [jloi2011] inequality system, cckk](/img/c7/e6cb7e6fc5f626df2d1ec8952bd19e.jpg)
P5482 [jloi2011] inequality system, cckk

Multi engine database management tool DataGrid 2022.1.5 Chinese version
![BUUCTF之HardSQL[极客大挑战 2019]](/img/bc/44f966a29a21e69296b00c1e29fce8.png)
BUUCTF之HardSQL[极客大挑战 2019]

Perfdog releases new indicators, tailored to the game
随机推荐
[buuctf.reverse] 114_[MRCTF2020]VirtualTree
浅析子组件自定义属性问题
Lecture 4: data warehouse construction (II)
Jingzhida rushes to the scientific innovation board: the annual revenue is 458million, and the SME fund is the shareholder
[buuctf.reverse] 103_ [CFI-CTF 2018]powerPacked
[buuctf.reverse] 107_[FlareOn4]greek_to_me
Learning notes of data structure in redis
Platinum resistance gas thermometer designed based on Internet of things (Huawei cloud IOT) [play with Huawei cloud]
10 useful flutter widgets
精智达冲刺科创板:年营收4.58亿 中小企业基金是股东
移动端拉起键盘后遮挡问题
redis中数据结构的学习笔记
首家BMW i品牌专属体验店开业,全面展示宝马电动产品的魅力
Protobuf介绍以及简单使用
About CSRF and its defense
[buuctf.reverse] 103_[CFI-CTF 2018]powerPacked
"Chinese characteristics" of Web3
【SignalR全套系列】之在.Net Core 中实现SignalR实时通信
[advanced MySQL] optimize SQL by using the execution plan explain (2)
版式设计三大原则