Win32 API + C#(P/Invoke)で 60FPS タイマーを作るサンプル

コンピュータ

C#でWin32APIの呼び出しのサンプルとして、QueryPerformanceCounterを使った高性能タイマープログラムを作成しました。

  • 1秒 = 1,000,000 マイクロ秒精度の高性能タイマー
  • Tick 毎に 16.666 ms(=1/60秒) を正確に維持
  • スリープは誤差が大きいので スピン + Sleep(0) 併用
  • WPFでもコンソールでも動く(STA不要)

ソースコード

ファイル名:win32api60fps.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

ファイル名:Program.cs

using System;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    // Win32 API
    [DllImport("Kernel32.dll")]
    static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

    [DllImport("Kernel32.dll")]
    static extern bool QueryPerformanceFrequency(out long lpFrequency);

    static void Main()
    {
        if (!QueryPerformanceFrequency(out long freq))
        {
            Console.WriteLine("High resolution performance counter not supported.");
            return;
        }

        double targetDelta = freq / 60.0;   // 60 FPS
        Console.WriteLine($"Frequency: {freq} Hz");
        Console.WriteLine($"Target delta: {targetDelta} counts");
        Console.WriteLine("Start 60 FPS loop...");

        QueryPerformanceCounter(out long last);

        while (true)
        {
            // フレーム処理
            Update();

            // 次のフレームまで busy-wait + Sleep(0)
            long current;
            while (true)
            {
                QueryPerformanceCounter(out current);

                long diff = current - last;
                if (diff >= targetDelta)
                    break;

                // 長すぎる busy-wait を避ける(CPU温存)
                Thread.Sleep(0);
            }

            last = current;
        }
    }

    static void Update()
    {
        Console.WriteLine($"Frame: {DateTime.Now:HH:mm:ss.fff}");
    }
}

結果

Frame: 20:47:29.295
Frame: 20:47:29.311
Frame: 20:47:29.328
Frame: 20:47:29.345
Frame: 20:47:29.361
Frame: 20:47:29.378
Frame: 20:47:29.395
Frame: 20:47:29.411
Frame: 20:47:29.428
Frame: 20:47:29.445
Frame: 20:47:29.461
Frame: 20:47:29.478
Frame: 20:47:29.495
Frame: 20:47:29.511
Frame: 20:47:29.528
Frame: 20:47:29.545
Frame: 20:47:29.561
Frame: 20:47:29.578
Frame: 20:47:29.595
Frame: 20:47:29.611
Frame: 20:47:29.628
Frame: 20:47:29.645
Frame: 20:47:29.661
Frame: 20:47:29.678
Frame: 20:47:29.695
Frame: 20:47:29.711
Frame: 20:47:29.728
Frame: 20:47:29.745
Frame: 20:47:29.761

コメント