如何在C#中通过P/Invoke调用CM_Register_Notification函数?
在C#中用P/Invoke实现设备变化通知
要在C#里调用CM_Register_Notification实现设备增减通知,核心是先映射C++原生类型到C#,再通过委托处理回调。以下是关键实现步骤:
1. 定义对应枚举与结构体
先把Windows API里的相关类型转换成C#可识别的结构:
// 通知过滤器类型枚举 public enum CM_NOTIFY_FILTER_TYPE { CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0, CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE = 1, CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE = 2 } // 通知过滤器头部结构 [StructLayout(LayoutKind.Sequential)] public struct CM_NOTIFY_FILTER_HEADER { public uint cbSize; public CM_NOTIFY_FILTER_TYPE FilterType; public uint Reserved; } // 设备实例过滤器结构 [StructLayout(LayoutKind.Sequential)] public struct CM_NOTIFY_FILTER { public CM_NOTIFY_FILTER_HEADER Header; [MarshalAs(UnmanagedType.LPWStr)] public string DeviceInstanceId; }
2. 声明P/Invoke函数与回调委托
// 设备通知回调委托 public delegate void CM_NOTIFY_CALLBACK( IntPtr hNotify, IntPtr Context, uint NotificationType, IntPtr NotificationData, uint NotificationDataSize); // 注册设备通知的P/Invoke签名 [DllImport("cfgmgr32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr CM_Register_Notification( ref CM_NOTIFY_FILTER pFilter, CM_NOTIFY_CALLBACK pCallback, IntPtr Context, out uint pdwNotifyCookie); // 注销设备通知的P/Invoke签名 [DllImport("cfgmgr32.dll", SetLastError = true)] public static extern int CM_Unregister_Notification(uint dwNotifyCookie);
3. 注册通知并处理回调
因为你只需要感知设备变化,回调里可以简化处理,只触发自定义逻辑即可:
private uint _notifyCookie; // 注册全局设备变化通知 public void StartDeviceMonitoring() { var filter = new CM_NOTIFY_FILTER(); filter.Header.cbSize = (uint)Marshal.SizeOf(typeof(CM_NOTIFY_FILTER)); filter.Header.FilterType = CM_NOTIFY_FILTER_TYPE.CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE; filter.DeviceInstanceId = ""; // 空字符串表示监听所有设备实例 if (CM_Register_Notification(ref filter, OnDeviceChanged, IntPtr.Zero, out _notifyCookie) == IntPtr.Zero) { // 注册失败,可通过Marshal.GetLastWin32Error()获取错误码排查 } } // 设备变化回调 private void OnDeviceChanged(IntPtr hNotify, IntPtr Context, uint NotificationType, IntPtr NotificationData, uint NotificationDataSize) { // 仅触发设备变化提示,后续自行确认具体变化 Console.WriteLine("设备状态已发生变化"); } // 停止监听时注销通知,避免资源泄漏 public void StopDeviceMonitoring() { CM_Unregister_Notification(_notifyCookie); }
注意事项
- 结构体的内存布局必须与C++原生定义一致,通过
StructLayout保证顺序正确 - 程序退出或不再需要监听时,务必调用
CM_Unregister_Notification释放资源 - 若需监听特定类型设备,可修改
CM_NOTIFY_FILTER参数(比如指定设备接口GUID)
内容的提问来源于stack exchange,提问作者ispiro
相关产品推荐
相关产品推荐

