有没有办法强制Win32计时器在不空闲时执行?

时间:2018-03-26 14:43:49

标签: winforms win32gui

使用SetTimer创建的Win32计时器通常仅在消息队列为空时执行。在GUI线程非常繁忙且因此不是空的情况下,有没有办法手动强制执行?

(编辑) 如下所述,特别是这是关于具有低优先级消息(在这种情况下间接地显示工具提示)在使UI线程饱和(但不阻塞它)时继续工作。这是一些代码:

$('form').on('submit', function(e) {
    e.preventDefault();

    //YOUR CODE HERE

    return false;
});

如果这是"错误的做法" ...很高兴听到'#34;正确的方式去做。"

1 个答案:

答案 0 :(得分:0)

成功!正如Raymond Chen所述,解决方案是使用PeekMessage。这是完成的代码:

using System;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ToolTipTesting
{
   [StructLayout(LayoutKind.Sequential)]
   public struct NativeMessage
   {
      public IntPtr handle;
      public uint msg;
      public IntPtr wParam;
      public IntPtr lParam;
      public uint time;
      public System.Drawing.Point p;
   }

   public partial class Form1 : Form
   {
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      static extern bool PeekMessage(ref NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);

      const int QS_TIMER = 0x0010;
      const int WM_TIMER = 0x0113;

      Thread _thread = null;
      bool _run = false;
      bool _exit = false;

      public Form1()
      {
         var tsbStart = new ToolStripButton();
         tsbStart.Text = "Start";
         tsbStart.Click += (s,e) => _run = true;

         var tsbStop  = new ToolStripButton();
         tsbStop.Text = "Stop";
         tsbStop.Click += (s,e) => _run = false;

         var tslValue = new ToolStripLabel();

         var ts = new ToolStrip();

         ts.Items.Add(tsbStart);
         ts.Items.Add(tsbStop);
         ts.Items.Add(tslValue);

         Controls.Add(ts);

         _thread = new Thread(() =>
         {
            int i = 0;

            NativeMessage nativeMessage = new NativeMessage();

            while (!_exit)
            {
               if(_run)
               { 
                  var result = 
                        BeginInvoke
                        (
                           new Action
                           (
                              () => 
                              {
                                 tslValue.Text = (i++).ToString();

                                 PeekMessage
                                 (
                                    ref nativeMessage,
                                    IntPtr.Zero,
                                    WM_TIMER,
                                    WM_TIMER,
                                    QS_TIMER << 16
                                 );

                                 ts.Update();
                              } 
                           )
                        );

                  while(!_exit && !result.IsCompleted)
                     result.AsyncWaitHandle.WaitOne(10);
               }
               else
               {
                  Thread.Sleep(100);
               }
            }
         });

         FormClosing += (s,e) =>
         { 
            _exit = true;
            _thread.Join();
         };

         _thread.Start();
      }
   }   
}