代码之家  ›  专栏  ›  技术社区  ›  Quibblesome

如果占用用户界面线程,为什么Windows CE会删除关键事件?

  •  0
  • Quibblesome  · 技术社区  · 17 年前

    现在我很欣赏这个故事的寓意是“不要占用用户界面线程”,但我们试图通过尽可能长时间地保持用户界面线程上的内容来亲吻,但我认为我们已经达到了临界点,我们将不得不改变我们的设计。

    但是无论如何……我在我们的设备上注意到了一些桌面上不会发生的事情:当你霸占用户界面线程时,它会掉钥匙。这里有一个显示问题的非常简单的应用程序。

    using System;
    using System.Windows.Forms;
    
    namespace DeviceApplication14
    {
        public partial class Form1 : Form
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [MTAThread]
            static void Main()
            {
                Application.Run(new Form1());
            }
    
            private int ctr;
    
            public Form1()
            {
                InitializeComponent();
                KeyPreview = true;
                KeyDown += Form1_KeyDown;
            }
    
            void Form1_KeyDown(object sender, KeyEventArgs e)
            {
                for (int i = 0; i < 1000000; i++)
                {
    
                }
                ctr++;
                button1.Text = ctr.ToString();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                ctr = 0;
                button1.Text = ctr.ToString();
            }
    
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows Form Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.button1 = new System.Windows.Forms.Button();
                this.button2 = new System.Windows.Forms.Button();
                this.SuspendLayout();
                // 
                // button1
                // 
                this.button1.Location = new System.Drawing.Point(235, 137);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(329, 239);
                this.button1.TabIndex = 0;
                this.button1.Text = "button1";
                // 
                // button2
                // 
                this.button2.Location = new System.Drawing.Point(62, 291);
                this.button2.Name = "button2";
                this.button2.Size = new System.Drawing.Size(72, 20);
                this.button2.TabIndex = 1;
                this.button2.Text = "Clear";
                this.button2.Click += new System.EventHandler(this.button2_Click);
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
                this.AutoScroll = true;
                this.ClientSize = new System.Drawing.Size(638, 455);
                this.Controls.Add(this.button2);
                this.Controls.Add(this.button1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);
    
            }
    
            #endregion
    
            private Button button1;
            private Button button2;
        }
    }
    

    当我在自定义框上运行这个命令时,我可以连续按四个键,但我的ctr只会增加两个。如果我添加一些零(以补偿桌面的更快速度),然后在桌面上运行它,我会得到所有的键。

    这是怎么回事?

    3 回复  |  直到 16 年前
        1
  •  2
  •   Adam Davis    17 年前
    for (int i = 0; i < 1000000; i++)
                {
    
                }
    

    提供时间延迟的空循环表示对事件驱动模型的理解不足。

    Windows CE与桌面版本的Windows具有足够不同的事件处理程序,虽然Windows可以容忍这种滥用,但Windows CE不会。

    如果您在这样的空循环中占用了大量的处理时间,而不是调用一个延迟例程,该例程将控制权正确地释放回调度程序,那么就不会调用事件处理程序。如果事件处理程序的调用频率不够高,那么您将丢失事件。有各种各样的缓冲区来存储其中的一些事件,但是根据输入设备(键盘、触摸屏等),这些缓冲区可能不充分或不存在。

    更糟糕的是,便携式设备上的事件处理程序没有大的缓冲区。台式计算机有大量的缓冲区用于键盘和鼠标操作。

    还有许多其他的区别,但底线是您确实需要正确地释放线程并适当地延迟,而不是这些简单的空循环延迟。

    WindowsCE计时器在这里会更合适-用keydown程序启动计时器,当它触发时,执行所需的操作。这会将控件释放回UI,以便其他事件可以运行。

    另外,请记住,虽然WindowsCE是多线程/多任务的,但最好将您的程序视为一次只运行一件事情。操作系统和事件模型可能正在发送您的应用程序事件(而不是缓冲它们),而您的应用程序正处于这个延迟例程中,忽略它们。当循环执行时,您将看不到其他事件(包括关键字)。根据系统的负载和性能,延迟可能会运行几毫秒到数百毫秒-您不能指望它每次运行相同的时间长度-使用实时计时器的另一个原因。

    -亚当

        2
  •  1
  •   ctacke    17 年前

    一旦消息进入队列,WindowsCE就不会“删除”任何键。我猜你用的量子太多了,以至于键盘驱动程序本身无法获得所有的键,因此无法传递它们。你可以打电话确认 PostKeybdMessage 而不是使用键盘本身排除硬件或驱动程序交互。

        3
  •  1
  •   Quibblesome    16 年前

    问题是与BSP中的一个错误有关(显然是来自一些飞思卡尔代码),这意味着键盘驱动程序在比预期的低得多的优先级中断下工作。

    现在已经修好了,一切都很好。:)