一聚教程网:一个值得你收藏的教程网站

热门教程

WPF实现Winform的窗口消息WndProc的例子

时间:2022-06-25 08:42:28 编辑:袖梨 来源:一聚教程网

昨天在项目开发中,遇到了USB口拔插的操作,想在程序中,实现对com口拔插的监控,但是常规的WndProc是在winform实现的,所以查询了一下wpf是怎么实现的。

有下面的方法,测试可行:

1、USB消息结构的定义

 // usb消息定义
        public const int WM_DEVICE_CHANGE = 0x219;
        public const int DBT_DEVICEARRIVAL = 0x8000;
        public const int DBT_DEVICE_REMOVE_COMPLETE = 0x8004;
        public const UInt32 DBT_DEVTYP_PORT = 0x00000003;
        [StructLayout(LayoutKind.Sequential)]
        struct DEV_BROADCAST_HDR
        {
            public UInt32 dbch_size;
            public UInt32 dbch_devicetype;
            public UInt32 dbch_reserved;
        }
        [StructLayout(LayoutKind.Sequential)]
        protected struct DEV_BROADCAST_PORT_Fixed
        {
            public uint dbcp_size;
            public uint dbcp_devicetype;
            public uint dbcp_reserved;
            // Variable?length field dbcp_name is declared here in the C header file.
        }

2、定义钩子方法:WndProc


 ///


        /// 检测USB串口的拔插
        ///

        ///
        public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_DEVICE_CHANGE)        // 捕获USB设备的拔出消息WM_DEVICECHANGE
            {
                switch (wParam.ToInt32())
                {
                    case DBT_DEVICE_REMOVE_COMPLETE:    // USB拔出                       
                        break;
                    case DBT_DEVICEARRIVAL:             // USB插入获取对应串口名称
                        DEV_BROADCAST_HDR dbhdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_HDR));
                        if (dbhdr.dbch_devicetype == DBT_DEVTYP_PORT)
                        {
                            string portName = Marshal.PtrToStringUni((IntPtr)(lParam.ToInt32() + Marshal.SizeOf(typeof(DEV_BROADCAST_PORT_Fixed))));
                            Console.WriteLine("Port '" + portName + "' arrived.");
                        }
                        break;
                }
            }
            return hwnd;
        }
3、在loaded中,注册这个方法

 HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
                if (source != null) source.AddHook(WndProc);


扩展阅读:

Marshal.StructureToPtr方法简介              

1. 功能及位置

                                           
将数据从托管对象封送到非托管内存块,属于.NET Framework 类库
命名空间:System.Runtime.InteropServices
程序集:mscorlib(在 mscorlib.dll 中)
2. 语法

                                           
C#:
      [ComVisibleAttribute(true)] public static void StructureToPtr (Object structure,IntPtr ptr,bool fDeleteOld);
C++:
      [ComVisibleAttribute(true)]public: static void StructureToPtr (Object^ structure, IntPtr ptr, bool fDeleteOld);
3. 参数说明                                           

structure:托管对象,包含要封送的数据。该对象必须是格式化类的实例。
ptr:指向非托管内存块的指针,必须在调用此方法之前分配该指针。
fDeleteOld:设置为 true 可在执行Marshal.DestroyStructure方法前对 ptr 参数调用此方法。请注意,传递 false 可导致内存泄漏。
4. 异常

                                           
异常类型:ArgumentException
条件:structrue参数是泛型类型
5. 备注

StructureToPtr将结构的内容复制到 ptr 参数指向的预分配内存块。如果 fDeleteOld 参数为 true,则使用嵌入指
针上适当的删除 API 来删除最初由 ptr 指向的缓冲区,但该缓冲区必须包含有效数据。此方法为在镜像托管类中指
定的每个引用字段执行清理工作。
                                           
假设 ptr 指向非托管内存块。此内存块的布局由相应的托管类 structure 描述。StructureToPtr将字段值从结构封
送到指针。假设 ptr 块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到 ptr 块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。最后,您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。如果将 fDeleteOld 参数设置为真,则 StructureToPtr 在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。
参考:

在Visual的句柄创建后(如OnLoad、OnSourceInitialized代码里),使用下面方法:

方法一:

HwndSource source =PresentationSource.FromVisual(this) as HwndSource;
if(source != null) source.AddHook(WndProc);

方法二:

HwndSource source =HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
if(source != null) source.AddHook(WndProc);
注:两种方法中的this可换成Visual对象。

然后就可以HwndSourceHook委托的WndProc方法了:

private IntPtr WndProc(IntPtr hwnd,int msg,IntPtr wParam,IntPtr lParam,ref bool handled)
{
    // Handle messages...
    return IntPtr.Zero;
}

热门栏目