在.net cf中处理Windows消息 | ||
在前面一篇文章中,我讲了如何使用Microsoft.WindowsCE.Forms.MessageWindow类捕获输入法改变事件,同样的,我们也可以利用该类进行其他消息处理。但是我发现该类并不能捕获所有的系统消息,比如WM_LBUTTONDOWN(鼠标左键按下),是不会调用WndProc函数的。 那么能不能实现对自身进程所有消息的捕获呢?SDK里面GetMessage函数告诉了我们是可能的。 首先把.net cf自带的Application类扔掉,建立自己的消息循环,代码如下: //ApplicationEx.cs using System; using System.Collections.Generic; using System.Windows.Forms; using System.Runtime.InteropServices; using Microsoft.WindowsCE.Forms; /// <summary> /// Application扩展类。 /// LastUpdate: 2007-12-26 NSnaiL /// </summary> public class ApplicationEx { #region Native ///导出非托管代码/// /// <summary> /// 向系统表明有个线程有终止请求,通常用来响应WM_DESTROY消息。 /// </summary> /// <param name="nExitCode">退出代码,此值被用作消息WM_QUIT的wParam参数。</param> [DllImport("coredll.dll", SetLastError = true)] internal static extern void PostQuitMessage(int nExitCode); /// <summary> /// 将虚键消息转换为字符消息; /// 字符消息被寄送到调用线程的消息队列里, /// 当下一次线程调用函数GetMessage或PeekMessage时被读出。 /// </summary> /// <param name="lpMsg">指向含有消息的MSG结构的指针。</param> /// <returns> /// 如果消息被转换(即,字符消息被寄送到调用线程的消息队列里),返回非零值。 /// 如果消息是WM_kEYDOWN,WM_KEYUP WM_SYSKEYDOWN或WM_SYSKEYUP,返回非零值,不考虑转换。 /// 如果消息没被转换(即,字符消息没被寄送到调用线程的消息队列里),返回值是零。 /// </returns> [DllImport("coredll.dll", SetLastError = true)] internal static extern bool TranslateMessage(out MessageExtern lpMsg); /// <summary> /// 调度一个消息给窗口程序; /// 通常调度从GetMessage取得的消息。 /// </summary> /// <param name="lpMsg">指向含有消息的MSG结构的指针。</param> /// <returns>返回值是窗口程序返回的值。尽管返回值的含义依赖于被调度的消息,但返回值通常被忽略。</returns> [DllImport("coredll.dll", SetLastError = true)] internal static extern bool DispatchMessage(ref MessageExtern lpMsg); /// <summary> /// 从调用线程的消息队列里取得一个消息并将其放于指定的结构。 /// </summary> /// <param name="lpMsg">指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。</param> /// <param name="hWnd">取得其消息的窗口的句柄。</param> /// <param name="wMsgFilterMin">指定被检索的最小消息值的整数。</param> /// <param name="wMsgFilterMax">指定被检索的最大消息值的整数。</param> /// <returns> /// 如果函数取得WM_QUIT之外的其他消息,返回非零值。 /// 如果函数取得WM_QUIT消息,返回值是零。 /// 如果出现了错误,返回-1。 /// </returns> [DllImport("coredll.dll", EntryPoint = "GetMessageW", SetLastError = true)] internal static extern bool GetMessage(out MessageExtern lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); /// <summary> /// 消息结构体。 /// </summary> [StructLayout(LayoutKind.Sequential)] internal struct MessageExtern { public IntPtr hwnd; //窗口句柄。 public int message; //消息ID。 //附加参数。 public IntPtr wParam; public IntPtr lParam; public int time; //产生时间。 //鼠标位置。 public int pointX; public int pointY; } #endregion #region Fields /// <summary>用于接收消息。</summary> private static MessageExtern Msg; /// <summary>主窗体。</summary> private static Form FrmMain; /// <summary>指示是否返还处理权。</summary> private static bool IsSysProc; /// <summary>接收消息的对象集合(实现IMessageListener接口)。</summary> private static List<IMessageListener> MessageListeners; /// <summary>空的对象,用于线程锁。</summary> private static object SyncObject; #endregion #region Methods static ApplicationEx() { MessageListeners = new List<IMessageListener>(); Msg = new MessageExtern(); SyncObject = new object(); } /// <summary> /// 增加一个消息接收对象。 /// </summary> /// <param name="value"></param> public static void AddMessageListener(IMessageListener value) { MessageListeners.Add(value); } /// <summary> /// 移除一个消息接收对象。 /// </summary> /// <param name="value"></param> public static void RemoveMessageListener(IMessageListener value) { MessageListeners.Remove(value); } /// <summary> /// 在当前线程上开始运行标准应用程序消息循环,并使指定窗体可见。 /// </summary> /// <param name="frmMain">一个 System.Windows.Forms.Form,它代表要使之可见的窗体。</param> public static void Run(Form frmMain) { ApplicationEx.FrmMain = frmMain; ApplicationEx.FrmMain.Closed += new EventHandler(OnFrmMainClosed); MessageLoop(); } /// <summary> /// 结束应用程序。 /// </summary> public static void Exit() { if (FrmMain != null) FrmMain.Dispose(); GC.GetTotalMemory(true); } /// <summary> /// 消息循环。 /// </summary> private static void MessageLoop() { FrmMain.Visible = true; for (; MessagePump(); ) { } Exit(); } /// <summary> /// 消息泵。 /// </summary> /// <returns></returns> private static bool MessagePump() { if (GetMessage(out Msg, IntPtr.Zero, 0, 0)) { IsSysProc = true; IMessageListener[] listeners = MessageListeners.ToArray(); lock (SyncObject) { for (int i = 0; i < listeners.Length; i++) { Message m = Message.Create(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam); IsSysProc = IsSysProc ? !listeners[i].WndProc(ref m) : false; } if (IsSysProc) { TranslateMessage(out Msg); DispatchMessage(ref Msg); } return true; } } return false; } /// 主窗体关闭事件。 private static void OnFrmMainClosed(object sender, EventArgs e) { PostQuitMessage(0); } #endregion } 然后再定义一个接口,规定消息接收对象必须实现WndProc方法。 using Microsoft.WindowsCE.Forms; /// <summary> /// 消息接收者接口。 /// LastUpdate: 2007-12-25 NSnaiL /// Merry Christmas! :) public interface IMessageListener { /// <summary> /// 消息处理过程。 /// </summary> /// <param name="m">消息结构体。</param> /// <returns>返回false以将消息处理权返回系统。</returns> bool WndProc(ref Message m); } 这样就实现了对自身线程所有消息的捕获。调用示例: using System; using System.ComponentModel; using System.Windows.Forms; public class FrmSample : Form, IMessageListener { public static void Main() { //使用Application扩展类替代Application类。 ApplicationEx.Run(new FrmSample()); } public FrmSample() { //将此窗体加入消息接受者集合。 ApplicationEx.AddMessageListener(this); MinimizeBox = false; Closing += new CancelEventHandler(FrmSample_Closing); } private void FrmSample_Closing(object sender, CancelEventArgs e) { //将此窗体从消息接受者集合移除。 ApplicationEx.RemoveMessageListener(this); } #region IMessageListener 成员 bool IMessageListener.WndProc(ref Microsoft.WindowsCE.Forms.Message m) { switch (m.Msg) { //do sth. here default: break; } //返回false,把消息处理权还给系统。 return false; } #endregion } |
在.net cf中处理Windows消息
最新推荐文章于 2024-09-13 21:15:03 发布