SetTimer Windows APIを利用してタイマーを実装する - C#
Windows APIのSetTimer関数を用いてTimerを自作するコードを紹介します。
概要
SetTimer関数を用いると第一引数に与えたウィンドウハンドルを持つウィンドウに対してWM_TIMERウィンドウメッセージが送られます。ウィンドウ側でWM_TIMERをキャプチャすることで一定時間ごとに処理をするタイマーを実装できます。
サンプルプログラム
UI
下図のUIを作成します。
コード
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TimerDemo
{
public partial class FormMain : Form
{
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, WindowMessage.WindowsMessages uMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", ExactSpelling = true)]
static extern IntPtr SetTimer(IntPtr hWnd, IntPtr nIDEvent, uint uElapse, TimerProc lpTimerFunc);
delegate void TimerProc(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
[DllImport("user32.dll", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool KillTimer(IntPtr hWnd, IntPtr uIDEvent);
int interval = 1000;
int count = 0;
public FormMain()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
protected override void WndProc(ref Message message)
{
switch (message.Msg) {
case (int)WindowMessage.WindowsMessages.TIMER:
textBox1.Text += string.Format("TimerEvent : {0:d}\r\n",count);
count++;
break;
default:
base.WndProc(ref message);
break;
}
}
private void UpdateTimer()
{
KillTimer(this.Handle, (IntPtr)1);
if (interval != 0){
if (SetTimer(this.Handle, (IntPtr)1, (uint)interval, null) == (IntPtr)0) {
textBox1.Text = "No-Timer\r\n";
}
}
}
private void StopTimer()
{
KillTimer(this.Handle, (IntPtr)1);
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text += "Start\r\n";
UpdateTimer();
}
private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
{
UpdateTimer();
}
private void button2_Click(object sender, EventArgs e)
{
StopTimer();
textBox1.Text += "Stop\r\n";
}
}
}
解説
UpdateTimer()メソッドでタイマーの開始をしています。
SetTimer(this.Handle, (IntPtr)1, (uint)interval, null)
にてタイマーの処理を開始します。第一引数にはWM_TIMERメッセージを受け取るウインドウハンドル、第二引数はタイマーの識別子です。今回はタイマーを1つしか持たないため、"1"で固定しています。SetTimer()関数を呼び出した際に既に同じタイマーIDを持つタイマーが存在する場合はタイマーの置き換えが実行されます。複数のタイマーを動かす場合はIDを変える必要があります。
第三引数はタイマーのインターバルをミリ秒単位で与えます。第四引数はコールバック関数のポインタを指定します。今回はタイマーからの通知をウィンドウメッセージで受け取るため、nullを指定しています。
タイマーを呈すする場合は、KillTimer()メソッドを用います。
KillTimer(this.Handle, (IntPtr)1);
第一引数に、ウィンドウメッセージを受け取るウィンドウハンドル、第二引数にタイマーの識別子を指定します。今回識別子は"1"で固定されているため、"1"を与えています。
実行結果
プロジェクト実行します。下図のウィンドウが表示されます。
[Start]ボタンをクリックします。タイマー処理が開始され、テキストボックスに1秒間に1行ずつメッセージが表示されます。
[Stop]ボタンをクリックするとタイマーの処理が中断されます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用