You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF应用如何捕获SD卡经程序弹出后的物理移除事件?

捕获SD卡物理移除事件的解决方案

一、通过WM_DEVICECHANGE窗口消息捕获(推荐,更可靠)

WPF窗口基于Win32窗口实现,重写WndProc方法直接监听Windows原生设备变更消息,比WMI更灵敏,尤其适合卷已卸载后的硬件移除场景。

实现步骤

  • 在WPF窗口类中重写WndProc,监听WM_DEVICECHANGE消息(消息ID为0x0219)。
  • 处理DBT_DEVICEREMOVECOMPLETE事件(事件类型为0x8004),解析设备信息判断是否为目标SD卡的物理移除。

代码示例

protected override void WndProc(ref Message m)
{
    const int WM_DEVICECHANGE = 0x0219;
    const int DBT_DEVICEREMOVECOMPLETE = 0x8004;

    if (m.Msg == WM_DEVICECHANGE)
    {
        int eventType = Marshal.ReadInt32(m.LParam, 0);
        if (eventType == DBT_DEVICEREMOVECOMPLETE)
        {
            DEV_BROADCAST_HDR hdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));
            if (hdr.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                DEV_BROADCAST_DEVICEINTERFACE deviceInterface = (DEV_BROADCAST_DEVICEINTERFACE)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_DEVICEINTERFACE));
                string devicePath = deviceInterface.dbcc_name;
                
                // 替换为你的SD卡/读卡器的VID/PID特征
                if (devicePath.Contains("VID_XXXX&PID_XXXX"))
                {
                    // 切换到UI线程执行操作
                    Dispatcher.Invoke(() => { /* 你的UI更新逻辑 */ });
                }
            }
        }
    }
    base.WndProc(ref m);
}

// 定义Win32结构体
[StructLayout(LayoutKind.Sequential)]
private struct DEV_BROADCAST_HDR
{
    public int dbch_size;
    public int dbch_devicetype;
    public int dbch_reserved;
}

private const int DBT_DEVTYP_DEVICEINTERFACE = 0x00000005;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DEV_BROADCAST_DEVICEINTERFACE
{
    public int dbcc_size;
    public int dbcc_devicetype;
    public int dbcc_reserved;
    public Guid dbcc_classguid;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
    public string dbcc_name;
}

二、修正WMI查询方案

之前的WMI查询未生效,是因为监听的事件类型不对。SD卡物理移除属于PnP设备实例删除事件,需监听Win32_PnPEntity的InstanceDeletionEvent,而非逻辑磁盘或通用设备变更事件。

实现步骤

  • 使用ManagementEventWatcher监听Win32_PnPEntity的实例删除事件。
  • 通过设备的PNPDeviceID或HardwareID过滤目标SD卡设备。

代码示例

using System.Management;

private void SetupWmiWatcher()
{
    string queryString = "SELECT * FROM InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PnPEntity'";
    ManagementEventWatcher watcher = new ManagementEventWatcher(new WqlEventQuery(queryString));
    watcher.EventArrived += Watcher_EventArrived;
    watcher.Start();
}

private void Watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject targetInstance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    string pnpDeviceId = targetInstance["PNPDeviceID"]?.ToString();
    
    // 匹配你的SD卡设备的PNPDeviceID特征
    if (pnpDeviceId != null && pnpDeviceId.Contains("VID_XXXX&PID_XXXX"))
    {
        // 切换到UI线程执行操作
        Dispatcher.Invoke(() => { /* 你的UI更新逻辑 */ });
    }
}

关键注意事项

  • 区分卷卸载和物理移除:卷卸载是软件层面的逻辑磁盘移除,物理移除是硬件层面的PnP设备消失,两者触发的事件类型不同。
  • 设备匹配:提前通过设备管理器获取目标SD卡/读卡器的VID/PID或PNPDeviceID,确保事件过滤的准确性。
  • 线程安全:WMI事件和WM_DEVICECHANGE消息均可能在非UI线程触发,必须通过Dispatcher.Invoke切换到UI线程执行UI操作。

内容的提问来源于stack exchange,提问作者Raj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:07:09