在.net cf中处理Windows消息

在.net cf中处理Windows消息
 
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>
文/nsnail  出处/博客园

    在前面一篇文章中,我讲了如何使用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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值