3.5 1/1000秒単位の時間を正確に取得
QueryPerformanceCounter関数とQueryPerformanceFrequencyを使うと、1/1000秒単位の時間をGetTickCount関数よりも正確に取得することができます。ちなみに、マイクロ秒までの時間も取得可能です。

QueryPerformanceCounter関数で取得できる値はCPUがカウントしている値です。このままでは時間としては使えません。時間に直すには、QueryPerformanceFrequency取得した値(CPUがどれぐらいの速度でカウントしているかを表す)で割ります。
関数を定義する
API「QueryPerformanceCounter関数」と「QueryPerformanceFrequency関数」を使うときは、まずはこの関数がどこにある、どんなヤツなのかなど、この関数を使うための準備(宣言)を行います。

この関数を使うときは、標準モジュールを準備し(General)(Declarations)の所へ次のように記述します。なお、標準モジュールの追加方法はエクセルスマイルの「4.マクロを書く場所/標準モジュール」をどうぞ。

'標準モジュールの(General)(Declarations)へ記述します
Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Boolean
Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Boolean
 ※このエクセルマクロは標準モジュール内へ記述するマクロです

簡単に説明すると、DeclareDLLの中にある関数を呼び出すときに付ける物で、Functionは関数の宣言、次が関数名(QueryPerformanceCounterまたはQueryPerformanceFrequency)、Libで関数の居場所を指定します。居場所には、どちらもkernel32を指定してください。なお、これらの関数の戻り値はBoolean型で、関数が実行できたときはTrue、実行できなかったときはFalseです。戻り値は取り出した値ではないことに注意してください。

取り出す値は引数を経由して行い、どちらの引数もCurrency型です。
使用例
QueryPerformanceCounterQueryPerformanceFrequencyの使用例です。Subプロシージャ「prcInit」を実行するとA列から順番にF列までのセル背景色が上から変わります。QueryPerformanceCounterQueryPerformanceFrequencyで取得した時刻を使っているA列〜C列では指定したインターバルの結果が顕著に表れますが、GetTickCountを使ったD列〜F列の結果は、インターバルを細かく指定してもあまり変化しません。

QueryPerformanceFrequencyで取得できる値は、CPUがどれぐらいの速度でカウントしているかを表す値で常に一定です。そのため、前処理(prcInit)で一度だけ値を取得すればOK。

実際に時間に変換しているのはFunctionプロシージャ「fncGetTimeCount」です。ここでは、QueryPerformanceCounterで取得した値(curFrequency)をQueryPerformanceFrequencyで取得した値(curFrequency)で割った結果に1000を掛け、1/1000秒単位の時間に変換しています。

Option Explicit

'CPUの実行速度
Dim curFrequency As Currency

Sub prcInit()

    'CPUの実行速度を取得
    Call QueryPerformanceFrequency(curFrequency)

    'ワークシートの初期化
    Range(Columns(1), Columns(6)).Delete

    'QueryPerformanceCounter使用時(20/1000秒)
    Call prcMain1(20, "A")

    'QueryPerformanceCounter使用時(21/1000秒)
    Call prcMain1(21, "B")

    'QueryPerformanceCounter使用時(22/1000秒)
    Call prcMain1(22, "C")

    'GetTickCount使用時(20/1000秒)
    Call prcMain2(20, "D")

    'GetTickCount使用時(21/1000秒)
    Call prcMain2(21, "E")

    'GetTickCount使用時(22/1000秒)
    Call prcMain2(22, "F")

End Sub

Sub prcMain1(lngInterval As Long, strColumns As String)

    'QueryPerformanceCounterとQueryPerformanceFrequencyを使った例

    Dim lngTime  As Long
    Dim lngCnt   As Long
    Dim lngLimit As Long
    Dim i        As Long

    '初期化
    lngCnt = 1
    lngLimit = GetTickCount

    '前回処理時刻の保存
    lngTime = fncGetTimeCount()

    Do Until GetTickCount - lngLimit >= 1000

       '前回色を変えてからnミリ秒経過していれば
       '指定列のセル背景色を上からランダムに変更
       If fncGetTimeCount() - lngTime >= lngInterval Then
          Range(strColumns & lngCnt).Interior.ColorIndex = Int(Rnd * 57)
          lngCnt = lngCnt + 1
          lngTime = fncGetTimeCount()
       End If

    Loop

End Sub

Function fncGetTimeCount() As Long

    Dim curCount As Currency

    'カウンターの取得
    Call QueryPerformanceCounter(curCount)

    '1/1000秒に変換
    'Long型にセットすることで、小数部をカットしています
    fncGetTimeCount = CLng(curCount * 1000 / curFrequency)

End Function

Sub prcMain2(lngInterval As Long, strColumns As String)

    'GetTickCountを使った例

    Dim lngTime As Long
    Dim lngCnt  As Long
    Dim lngLimit As Long
    Dim i       As Long

    '初期化
    lngCnt = 1
    lngLimit = GetTickCount()

    '前回処理時刻の保存
    lngTime = GetTickCount()

    Do Until GetTickCount - lngLimit >= 1000
          
       '前回色を変えてからnミリ秒経過していれば
       '指定列のセル背景色を上からランダムに変更
       If GetTickCount() - lngTime >= lngInterval Then
          Range(strColumns & lngCnt).Interior.ColorIndex = Int(Rnd * 57)
          lngCnt = lngCnt + 1
          lngTime = GetTickCount()
       End If

    Loop

End Sub
 ※このエクセルマクロはワークシート内へ記述するマクロです。
  標準モジュールへGetTickCount関数、QueryPerformanceFrequency関数、QueryPerformanceCounter関数を定義する必要があります。
Copyright(C) 1999-2006 結城圭介。 All rights reserved